Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2045 lines
57 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1998 - 2001
  4. Module Name:
  5. join.c
  6. Abstract:
  7. Handles the various functions for joining a machine to a domain, including creating and
  8. deleting machine accounts and managing domain membership
  9. --*/
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include <netdom.h>
  13. DWORD
  14. NetDompHandleAdd(ARG_RECORD * rgNetDomArgs)
  15. /*++
  16. Routine Description:
  17. This function will add a machine account to the domain using the default password
  18. Arguments:
  19. Args - List of command line arguments
  20. Return Value:
  21. ERROR_INVALID_PARAMETER - No object name was supplied
  22. --*/
  23. {
  24. DWORD Win32Err = ERROR_SUCCESS;
  25. PWSTR Domain = NULL;
  26. ND5_AUTH_INFO DomainUser;
  27. PWSTR Server = NULL, OU = NULL, FullServer = NULL;
  28. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  29. ULONG DsGetDcOptions = 0, Length;
  30. WCHAR DefaultPassword[ LM20_PWLEN + 1 ];
  31. WCHAR DefaultMachineAccountName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  32. USER_INFO_1 NetUI1;
  33. RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
  34. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  35. eObject,
  36. eCommDomain,
  37. eCommOU,
  38. eCommUserNameD,
  39. eCommPasswordD,
  40. eCommServer,
  41. eAddDC,
  42. eCommVerbose,
  43. eArgEnd);
  44. if ( Win32Err != ERROR_SUCCESS ) {
  45. DisplayHelp(ePriAdd);
  46. return( ERROR_INVALID_PARAMETER );
  47. }
  48. PWSTR Object = rgNetDomArgs[eObject].strValue;
  49. if ( !Object ) {
  50. DisplayHelp(ePriAdd);
  51. return( ERROR_INVALID_PARAMETER );
  52. }
  53. //
  54. // Make sure that the object name we were given is valid
  55. //
  56. Win32Err = I_NetNameValidate( NULL,
  57. Object,
  58. NAMETYPE_COMPUTER,
  59. LM2X_COMPATIBLE );
  60. if ( Win32Err != ERROR_SUCCESS ) {
  61. goto HandleAddExit;
  62. }
  63. //
  64. // Get the server if it exists
  65. //
  66. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  67. eCommServer,
  68. &Server);
  69. if ( Win32Err != ERROR_SUCCESS ) {
  70. goto HandleAddExit;
  71. }
  72. //
  73. // Get the domain.
  74. //
  75. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  76. Server,
  77. TRUE,
  78. &Domain);
  79. if ( Win32Err != ERROR_SUCCESS ) {
  80. goto HandleAddExit;
  81. }
  82. //
  83. // Get the password and user if it exists
  84. //
  85. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
  86. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  87. eCommUserNameD,
  88. Domain,
  89. &DomainUser);
  90. if ( Win32Err != ERROR_SUCCESS ) {
  91. goto HandleAddExit;
  92. }
  93. }
  94. //
  95. // Get the OU if it exists
  96. //
  97. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  98. eCommOU,
  99. &OU);
  100. if ( Win32Err != ERROR_SUCCESS ) {
  101. goto HandleAddExit;
  102. }
  103. //
  104. // Get the name of a server for the domain
  105. //
  106. if ( Server == NULL || CmdFlagOn(rgNetDomArgs, eAddDC)) {
  107. LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, Domain ));
  108. DsGetDcOptions = DS_WRITABLE_REQUIRED;
  109. if ( OU ) {
  110. DsGetDcOptions |= DS_DIRECTORY_SERVICE_REQUIRED;
  111. } else {
  112. DsGetDcOptions |= DS_DIRECTORY_SERVICE_PREFERRED;
  113. }
  114. Win32Err = DsGetDcName( Server,
  115. Domain,
  116. NULL,
  117. NULL,
  118. DsGetDcOptions,
  119. &pDcInfo );
  120. if ( Win32Err == ERROR_SUCCESS ) {
  121. Server = pDcInfo->DomainControllerName;
  122. }
  123. }
  124. if ( Win32Err != ERROR_SUCCESS ) {
  125. goto HandleAddExit;
  126. }
  127. //
  128. // Set the default password as the first 14 characters of the machine name, lowercased
  129. //
  130. wcsncpy( DefaultPassword, Object, LM20_PWLEN );
  131. DefaultPassword[ LM20_PWLEN ] = UNICODE_NULL;
  132. _wcslwr( DefaultPassword );
  133. //
  134. // Ok, now, do the add
  135. //
  136. if ( OU ) {
  137. LOG_VERBOSE(( MSG_VERBOSE_CREATE_ACCT_OU, Object, OU ));
  138. //
  139. // Use the Ds routines
  140. //
  141. if (CmdFlagOn(rgNetDomArgs, eAddDC) ||
  142. CmdFlagOn(rgNetDomArgs, eCommServer))
  143. {
  144. //
  145. // Don't support adding domain controllers in different OU's,
  146. // domain controllers are always in the Domain Controllers OU
  147. // Can't specify a server name since the OU add must be run directly
  148. // on a DC.
  149. //
  150. Win32Err = ERROR_INVALID_PARAMETER;
  151. goto HandleAddExit;
  152. }
  153. else
  154. {
  155. Win32Err = NetpCreateComputerObjectInDs(pDcInfo,
  156. DomainUser.User,
  157. DomainUser.Password,
  158. Object,
  159. DefaultPassword,
  160. NULL,
  161. OU);
  162. }
  163. } else {
  164. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Server ));
  165. Win32Err = NetpManageIPCConnect( Server,
  166. DomainUser.User,
  167. DomainUser.Password,
  168. NETSETUPP_CONNECT_IPC );
  169. if ( Win32Err == ERROR_SUCCESS ) {
  170. wcsncpy( DefaultMachineAccountName, Object, MAX_COMPUTERNAME_LENGTH );
  171. DefaultMachineAccountName[ MAX_COMPUTERNAME_LENGTH ] = L'\0';
  172. wcscat( DefaultMachineAccountName, L"$" );
  173. RtlZeroMemory( &NetUI1, sizeof( NetUI1 ) );
  174. //
  175. // Initialize it..
  176. //
  177. NetUI1.usri1_name = DefaultMachineAccountName;
  178. NetUI1.usri1_password = DefaultPassword;
  179. if (CmdFlagOn(rgNetDomArgs, eAddDC))
  180. {
  181. NetUI1.usri1_flags = UF_SERVER_TRUST_ACCOUNT | UF_SCRIPT;
  182. }
  183. else
  184. {
  185. NetUI1.usri1_flags = UF_WORKSTATION_TRUST_ACCOUNT | UF_SCRIPT;
  186. }
  187. NetUI1.usri1_priv = USER_PRIV_USER;
  188. if ( Server && *Server != L'\\' ) {
  189. Win32Err = NetApiBufferAllocate( ( wcslen( Server ) + 3 ) * sizeof( WCHAR ),
  190. (PVOID*)&FullServer );
  191. if ( Win32Err == ERROR_SUCCESS ) {
  192. swprintf( FullServer, L"\\\\%ws", Server );
  193. }
  194. } else {
  195. FullServer = Server;
  196. }
  197. if ( Win32Err == ERROR_SUCCESS ) {
  198. LOG_VERBOSE(( MSG_VERBOSE_CREATE_ACCT, Object ));
  199. Win32Err = NetUserAdd( FullServer,
  200. 1,
  201. ( PBYTE )&NetUI1,
  202. NULL );
  203. }
  204. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Server ));
  205. NetpManageIPCConnect( Server,
  206. DomainUser.User,
  207. DomainUser.Password,
  208. NETSETUPP_DISCONNECT_IPC );
  209. }
  210. }
  211. HandleAddExit:
  212. NetApiBufferFree( Domain );
  213. NetApiBufferFree( OU );
  214. NetDompFreeAuthIdent( &DomainUser );
  215. if ( pDcInfo ) {
  216. NetApiBufferFree( pDcInfo );
  217. } else {
  218. NetApiBufferFree( Server );
  219. }
  220. if ( FullServer != Server ) {
  221. NetApiBufferFree( FullServer );
  222. }
  223. if (NO_ERROR != Win32Err)
  224. {
  225. NetDompDisplayErrorMessage(Win32Err);
  226. }
  227. return( Win32Err );
  228. }
  229. DWORD
  230. NetDompHandleRemove(ARG_RECORD * rgNetDomArgs)
  231. /*++
  232. Routine Description:
  233. This function will remove a machine from the domain
  234. Arguments:
  235. Args - List of command line arguments
  236. Return Value:
  237. ERROR_INVALID_PARAMETER - No object name was supplied
  238. --*/
  239. {
  240. DWORD Win32Err = ERROR_SUCCESS;
  241. PWSTR Domain = NULL;
  242. ND5_AUTH_INFO DomainUser, ObjectUser;
  243. WCHAR DefaultMachineAccountName[ MAX_COMPUTERNAME_LENGTH + 2 ];
  244. USER_INFO_1 NetUI1;
  245. BOOL NeedReboot = FALSE;
  246. RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
  247. RtlZeroMemory( &ObjectUser, sizeof( ND5_AUTH_INFO ) );
  248. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  249. eObject,
  250. eCommDomain,
  251. eCommUserNameO,
  252. eCommPasswordO,
  253. eCommUserNameD,
  254. eCommPasswordD,
  255. eCommRestart,
  256. eCommVerbose,
  257. eArgEnd);
  258. if ( Win32Err != ERROR_SUCCESS ) {
  259. DisplayHelp(ePriRemove);
  260. return( ERROR_INVALID_PARAMETER );
  261. }
  262. PWSTR Object = rgNetDomArgs[eObject].strValue;
  263. if ( !Object ) {
  264. DisplayHelp(ePriRemove);
  265. return( ERROR_INVALID_PARAMETER );
  266. }
  267. //
  268. // Make sure that we have a specified domain...
  269. //
  270. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  271. Object,
  272. TRUE,
  273. &Domain);
  274. if ( Win32Err != ERROR_SUCCESS ) {
  275. goto HandleRemoveExit;
  276. }
  277. //
  278. // Get the password and user if it exists
  279. //
  280. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
  281. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  282. eCommUserNameD,
  283. Domain,
  284. &DomainUser);
  285. if ( Win32Err != ERROR_SUCCESS ) {
  286. goto HandleRemoveExit;
  287. }
  288. }
  289. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameO) ) {
  290. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  291. eCommUserNameO,
  292. Object,
  293. &ObjectUser);
  294. if ( Win32Err != ERROR_SUCCESS ) {
  295. goto HandleRemoveExit;
  296. }
  297. }
  298. //
  299. // See if the reboot argument is specified
  300. //
  301. NeedReboot = NetDompGetArgumentBoolean(rgNetDomArgs,
  302. eCommRestart);
  303. //
  304. // Try and unjoin the specified machine from the network by speaking directly to that
  305. // machine
  306. //
  307. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Object ));
  308. Win32Err = NetpManageIPCConnect( Object,
  309. ObjectUser.User,
  310. ObjectUser.Password,
  311. NETSETUPP_CONNECT_IPC );
  312. if ( Win32Err == ERROR_SUCCESS ) {
  313. // NETSETUP_ACCT_DELETE means disable the old account object.
  314. //
  315. Win32Err = NetUnjoinDomain( Object,
  316. DomainUser.User,
  317. DomainUser.Password,
  318. NETSETUP_ACCT_DELETE );
  319. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Object ));
  320. NetpManageIPCConnect( Object,
  321. ObjectUser.User,
  322. ObjectUser.Password,
  323. NETSETUPP_DISCONNECT_IPC );
  324. } else {
  325. LOG_VERBOSE(( MSG_VERBOSE_SESSION_FAILED, Object ));
  326. ERROR_VERBOSE( Win32Err );
  327. }
  328. if ( NeedReboot ) {
  329. NetDompRestartAsRequired(rgNetDomArgs,
  330. Object,
  331. ObjectUser.User,
  332. Win32Err,
  333. MSG_DOMAIN_CHANGE_RESTART_MSG);
  334. }
  335. HandleRemoveExit:
  336. NetApiBufferFree( Domain );
  337. NetDompFreeAuthIdent( &DomainUser );
  338. NetDompFreeAuthIdent( &ObjectUser );
  339. if (NO_ERROR != Win32Err)
  340. {
  341. NetDompDisplayErrorMessage(Win32Err);
  342. }
  343. return( Win32Err );
  344. }
  345. DWORD
  346. NetDompHandleJoin(ARG_RECORD * rgNetDomArgs, BOOL AllowMove)
  347. /*++
  348. Routine Description:
  349. This function will join a machine to the domain
  350. Arguments:
  351. Args - List of command line arguments
  352. AllowMove - If TRUE, allow the join if the machine is already joined to a domain
  353. Return Value:
  354. ERROR_INVALID_PARAMETER - No object name was supplied
  355. --*/
  356. {
  357. DWORD Win32Err = ERROR_SUCCESS;
  358. USER_INFO_1 * pui1 = NULL;
  359. PWSTR pwzNewDomain = NULL, pwzOldDomain = NULL, OU = NULL;
  360. ND5_AUTH_INFO DomainUser, WkstaUser, FormerDomainUser;
  361. ULONG JoinOptions = 0;
  362. BOOL NeedReboot = FALSE, fConnectedO = FALSE;
  363. RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
  364. RtlZeroMemory( &WkstaUser, sizeof( ND5_AUTH_INFO ) );
  365. RtlZeroMemory( &FormerDomainUser, sizeof( ND5_AUTH_INFO ) );
  366. if (AllowMove)
  367. {
  368. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  369. eObject,
  370. eCommDomain,
  371. eCommOU,
  372. eCommUserNameO,
  373. eCommPasswordO,
  374. eCommUserNameD,
  375. eCommPasswordD,
  376. eMoveUserNameF,
  377. eMovePasswordF,
  378. eCommRestart,
  379. eCommVerbose,
  380. eArgEnd);
  381. }
  382. else
  383. {
  384. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  385. eObject,
  386. eCommDomain,
  387. eCommOU,
  388. eCommUserNameO,
  389. eCommPasswordO,
  390. eCommUserNameD,
  391. eCommPasswordD,
  392. eCommRestart,
  393. eCommVerbose,
  394. eArgEnd);
  395. }
  396. if ( Win32Err != ERROR_SUCCESS ) {
  397. DisplayHelp((AllowMove) ? ePriMove : ePriJoin);
  398. return( ERROR_INVALID_PARAMETER );
  399. }
  400. PWSTR pwzWksta = rgNetDomArgs[eObject].strValue;
  401. if ( !pwzWksta ) {
  402. DisplayHelp((AllowMove) ? ePriMove : ePriJoin);
  403. return( ERROR_INVALID_PARAMETER );
  404. }
  405. //
  406. // Ok, make sure that we have a specified domain...
  407. //
  408. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  409. NULL,
  410. FALSE,
  411. &pwzNewDomain);
  412. if ( Win32Err != ERROR_SUCCESS ) {
  413. goto HandleJoinExit;
  414. }
  415. //
  416. // Get the password and user for the new domain if specified on command line.
  417. //
  418. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
  419. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  420. eCommUserNameD,
  421. pwzNewDomain,
  422. &DomainUser);
  423. if ( Win32Err != ERROR_SUCCESS ) {
  424. goto HandleJoinExit;
  425. }
  426. }
  427. //
  428. // Get the password and user for the workstation and establish the
  429. // connection if the args are specified on the command line.
  430. //
  431. if ( CmdFlagOn(rgNetDomArgs, eCommUserNameO) ) {
  432. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  433. eCommUserNameO,
  434. pwzWksta,
  435. &WkstaUser);
  436. if ( Win32Err != ERROR_SUCCESS ) {
  437. goto HandleJoinExit;
  438. }
  439. LOG_VERBOSE((MSG_VERBOSE_ESTABLISH_SESSION, pwzWksta));
  440. Win32Err = NetpManageIPCConnect(pwzWksta,
  441. WkstaUser.User,
  442. WkstaUser.Password,
  443. NETSETUPP_CONNECT_IPC);
  444. if (ERROR_SUCCESS != Win32Err)
  445. {
  446. LOG_VERBOSE((MSG_VERBOSE_SESSION_FAILED, pwzWksta));
  447. goto HandleJoinExit;
  448. }
  449. fConnectedO = TRUE;
  450. }
  451. if (AllowMove)
  452. {
  453. // Get the machine's current domain membership. This must be done after
  454. // the NetpManageIPCConnect above so as to have rights to read the info.
  455. //
  456. Win32Err = NetDompGetDomainForOperation(NULL,
  457. pwzWksta,
  458. TRUE,
  459. &pwzOldDomain);
  460. if (ERROR_INVALID_PARAMETER == Win32Err)
  461. {
  462. // ERROR_INVALID_PARAMETER is returned by NetDompGetDomainForOperation
  463. // if the machine is not joined to a domain.
  464. //
  465. LOG_VERBOSE((MSG_VERBOSE_NOT_JOINED, pwzWksta, pwzNewDomain));
  466. pwzOldDomain = NULL;
  467. AllowMove = FALSE;
  468. }
  469. else
  470. {
  471. if (ERROR_SUCCESS != Win32Err)
  472. {
  473. ERROR_VERBOSE(Win32Err);
  474. goto HandleJoinExit;
  475. }
  476. if (_wcsicmp(pwzNewDomain, pwzOldDomain) == 0)
  477. {
  478. NetDompDisplayMessage(MSG_ALREADY_JOINED, pwzNewDomain);
  479. Win32Err = ERROR_DS_CROSS_DOM_MOVE_ERROR;
  480. goto HandleJoinExit;
  481. }
  482. }
  483. }
  484. if (AllowMove && CmdFlagOn(rgNetDomArgs, eMoveUserNameF))
  485. {
  486. //
  487. // Get the password and user for the former domain if specified on command line.
  488. //
  489. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  490. eMoveUserNameF,
  491. pwzOldDomain,
  492. &FormerDomainUser);
  493. if (ERROR_SUCCESS != Win32Err)
  494. {
  495. goto HandleJoinExit;
  496. }
  497. }
  498. //
  499. // See if the reboot argument is specified
  500. //
  501. NeedReboot = NetDompGetArgumentBoolean(rgNetDomArgs,
  502. eCommRestart);
  503. //
  504. // Get the OU if it exists
  505. //
  506. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  507. eCommOU,
  508. &OU);
  509. if ( Win32Err != ERROR_SUCCESS ) {
  510. goto HandleJoinExit;
  511. }
  512. //
  513. // Try and join the specified machine to the domain by speaking directly to that
  514. // machine
  515. //
  516. JoinOptions = NETSETUP_JOIN_DOMAIN | NETSETUP_ACCT_CREATE;
  517. if ( AllowMove ) {
  518. JoinOptions |= NETSETUP_DOMAIN_JOIN_IF_JOINED;
  519. }
  520. LOG_VERBOSE(( MSG_VERBOSE_DOMAIN_JOIN, pwzNewDomain ));
  521. Win32Err = NetJoinDomain( pwzWksta,
  522. pwzNewDomain,
  523. OU,
  524. DomainUser.User,
  525. DomainUser.Password,
  526. JoinOptions );
  527. if (Win32Err == RPC_S_PROCNUM_OUT_OF_RANGE)
  528. {
  529. //
  530. // Try the NT4 unjoin
  531. //
  532. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  533. NeedReboot = TRUE;
  534. LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, pwzNewDomain ));
  535. Win32Err = DsGetDcName( NULL,
  536. pwzNewDomain,
  537. NULL,
  538. NULL,
  539. DS_WRITABLE_REQUIRED | DS_DIRECTORY_SERVICE_PREFERRED,
  540. &pDcInfo );
  541. if ( Win32Err == ERROR_SUCCESS ) {
  542. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, pDcInfo->DomainControllerName ));
  543. Win32Err = NetpManageIPCConnect( pDcInfo->DomainControllerName,
  544. DomainUser.User,
  545. DomainUser.Password,
  546. NETSETUPP_CONNECT_IPC );
  547. if ( Win32Err == ERROR_SUCCESS ) {
  548. Win32Err = NetDompJoinDownlevel( pwzWksta,
  549. DomainUser.User,
  550. DomainUser.Password,
  551. pDcInfo->DomainControllerName,
  552. pDcInfo->Flags,
  553. AllowMove );
  554. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, pDcInfo->DomainControllerName ));
  555. NetpManageIPCConnect( pDcInfo->DomainControllerName,
  556. DomainUser.User,
  557. DomainUser.Password,
  558. NETSETUPP_DISCONNECT_IPC );
  559. } else {
  560. LOG_VERBOSE(( MSG_VERBOSE_SESSION_FAILED, pDcInfo->DomainControllerName ));
  561. ERROR_VERBOSE( Win32Err );
  562. }
  563. }
  564. NetApiBufferFree( pDcInfo );
  565. }
  566. else
  567. {
  568. if (ERROR_SUCCESS != Win32Err)
  569. {
  570. LOG_VERBOSE(( MSG_VERBOSE_MOVE_COMPUTER_FAILED, Win32Err ));
  571. goto HandleJoinExit;
  572. }
  573. //
  574. // Uplevel join successful. If a Move operation, disable the old account.
  575. //
  576. if (AllowMove && pwzOldDomain)
  577. {
  578. PDOMAIN_CONTROLLER_INFO pOldDcInfo = NULL;
  579. LOG_VERBOSE((MSG_VERBOSE_DISABLE_OLD_ACCT, pwzOldDomain));
  580. Win32Err = DsGetDcName(NULL,
  581. pwzOldDomain,
  582. NULL,
  583. NULL,
  584. DS_WRITABLE_REQUIRED,
  585. &pOldDcInfo);
  586. if (ERROR_SUCCESS == Win32Err)
  587. {
  588. LOG_VERBOSE((MSG_VERBOSE_ESTABLISH_SESSION, pOldDcInfo->DomainControllerName));
  589. Win32Err = NetpManageIPCConnect(pOldDcInfo->DomainControllerName,
  590. FormerDomainUser.User,
  591. FormerDomainUser.Password,
  592. NETSETUPP_CONNECT_IPC );
  593. if (ERROR_SUCCESS == Win32Err)
  594. {
  595. PWSTR pwzWkstaDollar;
  596. Win32Err = NetApiBufferAllocate((wcslen(pwzWksta) + 2) * sizeof(WCHAR),
  597. (PVOID*)&pwzWkstaDollar);
  598. if (ERROR_SUCCESS == Win32Err)
  599. {
  600. wcscpy(pwzWkstaDollar, pwzWksta);
  601. wcscat(pwzWkstaDollar, L"$");
  602. Win32Err = NetUserGetInfo(pOldDcInfo->DomainControllerName,
  603. pwzWkstaDollar, 1, (PBYTE *)&pui1);
  604. if (ERROR_SUCCESS == Win32Err)
  605. {
  606. pui1->usri1_flags |= UF_ACCOUNTDISABLE;
  607. Win32Err = NetUserSetInfo(pOldDcInfo->DomainControllerName,
  608. pwzWkstaDollar, 1, (PBYTE)pui1, NULL);
  609. NetApiBufferFree(pui1);
  610. }
  611. NetApiBufferFree(pwzWkstaDollar);
  612. }
  613. LOG_VERBOSE((MSG_VERBOSE_DELETE_SESSION, pOldDcInfo->DomainControllerName));
  614. NetpManageIPCConnect(pOldDcInfo->DomainControllerName,
  615. FormerDomainUser.User,
  616. FormerDomainUser.Password,
  617. NETSETUPP_DISCONNECT_IPC);
  618. }
  619. NetApiBufferFree(pOldDcInfo);
  620. }
  621. }
  622. }
  623. if (NeedReboot && (ERROR_SUCCESS == Win32Err))
  624. {
  625. NetDompRestartAsRequired(rgNetDomArgs,
  626. pwzWksta,
  627. WkstaUser.User,
  628. Win32Err,
  629. MSG_DOMAIN_CHANGE_RESTART_MSG);
  630. }
  631. HandleJoinExit:
  632. if (fConnectedO)
  633. {
  634. LOG_VERBOSE((MSG_VERBOSE_DELETE_SESSION, pwzWksta));
  635. NetpManageIPCConnect(pwzWksta,
  636. WkstaUser.User,
  637. WkstaUser.Password,
  638. NETSETUPP_DISCONNECT_IPC);
  639. }
  640. NetApiBufferFree(pwzNewDomain);
  641. NetDompFreeAuthIdent(&DomainUser);
  642. NetDompFreeAuthIdent(&FormerDomainUser);
  643. NetDompFreeAuthIdent(&WkstaUser);
  644. if (pwzOldDomain)
  645. {
  646. NetApiBufferFree(pwzOldDomain);
  647. }
  648. if (NO_ERROR != Win32Err)
  649. {
  650. NetDompDisplayErrorMessage(Win32Err);
  651. }
  652. return( Win32Err );
  653. }
  654. DWORD
  655. NetDompHandleMove(ARG_RECORD * rgNetDomArgs)
  656. /*++
  657. Routine Description:
  658. This function will move a machine from one domain to another
  659. Arguments:
  660. SelectedOptions - List of arguments present in the Args list
  661. Args - List of command line arguments
  662. ArgCount - Number of arguments in the list
  663. Object - Name of the machine to join to the domain
  664. Return Value:
  665. ERROR_INVALID_PARAMETER - No object name was supplied
  666. --*/
  667. {
  668. DWORD Win32Err = ERROR_SUCCESS;
  669. Win32Err = NetDompHandleJoin(rgNetDomArgs, TRUE);
  670. return( Win32Err );
  671. }
  672. DWORD
  673. NetDompResetServerSC(
  674. IN PWSTR Domain,
  675. IN PWSTR Server,
  676. IN PWSTR DomainController, OPTIONAL
  677. IN PND5_AUTH_INFO AuthInfo,
  678. IN ULONG OkMessageId,
  679. IN ULONG FailedMessageId
  680. )
  681. {
  682. DWORD Win32Err = ERROR_SUCCESS;
  683. PWSTR ScDomain = NULL;
  684. PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
  685. BOOL DomainMember = FALSE, SessionEstablished = FALSE;
  686. //
  687. // If it doesn't, get the name of a server for the domain
  688. //
  689. if ( DomainController != NULL ) {
  690. Win32Err = NetApiBufferAllocate( ( wcslen( Domain ) + 1 +
  691. wcslen( DomainController ) + 1 ) * sizeof( WCHAR ),
  692. (PVOID*)&ScDomain );
  693. if ( Win32Err == ERROR_SUCCESS ) {
  694. swprintf( ScDomain, L"%ws\\%ws", Domain, DomainController );
  695. }
  696. } else {
  697. ScDomain = Domain;
  698. }
  699. if ( Win32Err == ERROR_SUCCESS ) {
  700. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Server ));
  701. Win32Err = NetpManageIPCConnect( Server,
  702. AuthInfo->User,
  703. AuthInfo->Password,
  704. NETSETUPP_CONNECT_IPC );
  705. if ( Win32Err == ERROR_SUCCESS ) {
  706. SessionEstablished = TRUE;
  707. }
  708. }
  709. //
  710. // See if we're a domain member or not
  711. //
  712. if ( Win32Err == ERROR_SUCCESS ) {
  713. Win32Err = NetDompCheckDomainMembership( Server,
  714. AuthInfo,
  715. FALSE,
  716. &DomainMember );
  717. if ( Win32Err == ERROR_SUCCESS && !DomainMember ) {
  718. Win32Err = NERR_SetupNotJoined;
  719. }
  720. }
  721. if ( Win32Err == ERROR_SUCCESS ) {
  722. LOG_VERBOSE(( MSG_VERBOSE_RESET_SC, ScDomain ));
  723. Win32Err = I_NetLogonControl2( Server,
  724. NETLOGON_CONTROL_REDISCOVER,
  725. 2,
  726. ( LPBYTE )&ScDomain,
  727. ( LPBYTE *)&NetlogonInfo2 );
  728. if ( Win32Err == ERROR_NO_SUCH_DOMAIN && ScDomain != Domain ) {
  729. LOG_VERBOSE(( MSG_VERBOSE_RETRY_RESET_SC, ScDomain, Domain ));
  730. //
  731. // Must be using an downlevel domain, so try it again with out the server
  732. //
  733. Win32Err = I_NetLogonControl2( Server,
  734. NETLOGON_CONTROL_REDISCOVER,
  735. 2,
  736. ( LPBYTE )&Domain,
  737. ( LPBYTE *)&NetlogonInfo2 );
  738. if ( Win32Err == ERROR_SUCCESS ) {
  739. LOG_VERBOSE(( MSG_VERBOSE_RESET_NOT_NAMED, Server ));
  740. Win32Err = I_NetLogonControl2( Server,
  741. NETLOGON_CONTROL_TC_QUERY,
  742. 2,
  743. ( LPBYTE )&Domain,
  744. ( LPBYTE *)&NetlogonInfo2 );
  745. }
  746. }
  747. if ( Win32Err == ERROR_SUCCESS ) {
  748. NetDompDisplayMessage( OkMessageId, _wcsupr( Server ), _wcsupr( Domain ),
  749. _wcsupr( NetlogonInfo2->netlog2_trusted_dc_name ) );
  750. } else {
  751. if ( FailedMessageId ) {
  752. NetDompDisplayMessage( FailedMessageId, _wcsupr( Server ), _wcsupr( Domain ) );
  753. NetDompDisplayErrorMessage( Win32Err );
  754. }
  755. }
  756. }
  757. if ( SessionEstablished ) {
  758. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Server ));
  759. NetpManageIPCConnect( Server,
  760. AuthInfo->User,
  761. AuthInfo->Password,
  762. NETSETUPP_DISCONNECT_IPC );
  763. }
  764. NetApiBufferFree( NetlogonInfo2 );
  765. return( Win32Err );
  766. }
  767. DWORD
  768. NetDompHandleReset(ARG_RECORD * rgNetDomArgs)
  769. /*++
  770. Routine Description:
  771. This function will reset the secure channel with the domain
  772. Arguments:
  773. Args - List of command line arguments
  774. Return Value:
  775. ERROR_INVALID_PARAMETER - No object name was supplied
  776. --*/
  777. {
  778. DWORD Win32Err = ERROR_SUCCESS;
  779. PWSTR Domain = NULL;
  780. ND5_AUTH_INFO ObjectUser;
  781. PWSTR Server = NULL;
  782. RtlZeroMemory( &ObjectUser, sizeof( ND5_AUTH_INFO ) );
  783. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  784. eObject,
  785. eCommDomain,
  786. eCommUserNameO,
  787. eCommPasswordO,
  788. eCommServer,
  789. eCommVerbose,
  790. eArgEnd);
  791. if ( Win32Err != ERROR_SUCCESS ) {
  792. DisplayHelp(ePriReset);
  793. return( ERROR_INVALID_PARAMETER );
  794. }
  795. PWSTR Object = rgNetDomArgs[eObject].strValue;
  796. if ( !Object ) {
  797. DisplayHelp(ePriReset);
  798. return( ERROR_INVALID_PARAMETER );
  799. }
  800. //
  801. // Make sure that the object name we were given is valid
  802. //
  803. Win32Err = I_NetNameValidate( NULL,
  804. Object,
  805. NAMETYPE_COMPUTER,
  806. LM2X_COMPATIBLE );
  807. if ( Win32Err != ERROR_SUCCESS ) {
  808. goto HandleResetExit;
  809. }
  810. //
  811. // Ok, make sure that we have a specified domain...
  812. //
  813. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  814. Object,
  815. TRUE,
  816. &Domain);
  817. if ( Win32Err != ERROR_SUCCESS ) {
  818. goto HandleResetExit;
  819. }
  820. //
  821. // Get the password and user if it exists
  822. //
  823. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  824. eCommUserNameO,
  825. Domain,
  826. &ObjectUser);
  827. if ( Win32Err != ERROR_SUCCESS ) {
  828. goto HandleResetExit;
  829. }
  830. //
  831. // Get the server if it exists
  832. //
  833. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  834. eCommServer,
  835. &Server);
  836. if ( Win32Err != ERROR_SUCCESS ) {
  837. goto HandleResetExit;
  838. }
  839. Win32Err = NetDompResetServerSC( Domain,
  840. Object,
  841. Server,
  842. &ObjectUser,
  843. MSG_RESET_OK,
  844. MSG_RESET_BAD );
  845. HandleResetExit:
  846. NetDompFreeAuthIdent( &ObjectUser );
  847. NetApiBufferFree( Server );
  848. NetApiBufferFree( Domain );
  849. if (NO_ERROR != Win32Err)
  850. {
  851. NetDompDisplayErrorMessage(Win32Err);
  852. }
  853. return( Win32Err );
  854. }
  855. DWORD
  856. NetDompResetPwd(
  857. IN PWSTR DomainController,
  858. IN PND5_AUTH_INFO AuthInfo,
  859. IN ULONG OkMessageId,
  860. IN ULONG FailedMessageId
  861. )
  862. /*++
  863. Routine Description:
  864. This function reset machine account password for the local machine
  865. on the specified domain controller.
  866. Arguments:
  867. DomainController - name of dc
  868. AuthInfo - user/password that has admin access on
  869. the local machine and on DomainController
  870. OkMessageId - message to display on success
  871. FailedMessageId - message to display on failure
  872. Return Value:
  873. win32 error as returned by NetpSetComputerAccountPassword
  874. --*/
  875. {
  876. DWORD Win32Err = ERROR_SUCCESS;
  877. BOOL DomainMember = FALSE, SessionEstablished = FALSE;
  878. Win32Err = NetpSetComputerAccountPassword( NULL,
  879. DomainController,
  880. AuthInfo->User,
  881. AuthInfo->Password,
  882. NULL );
  883. if ( Win32Err == ERROR_SUCCESS ) {
  884. NetDompDisplayMessage( OkMessageId );
  885. } else {
  886. NetDompDisplayMessage( FailedMessageId );
  887. }
  888. return( Win32Err );
  889. }
  890. DWORD
  891. NetDompHandleResetPwd(ARG_RECORD * rgNetDomArgs)
  892. /*++
  893. Routine Description:
  894. This function resets the machine account password for the local.
  895. Currently there is no support for resetting machine password of
  896. a remote machine.
  897. Arguments:
  898. Args - List of command line arguments
  899. Return Value:
  900. ERROR_INVALID_PARAMETER - if any param is invalid
  901. --*/
  902. {
  903. DWORD Win32Err = ERROR_SUCCESS;
  904. PWSTR Domain = NULL;
  905. ND5_AUTH_INFO ObjectUser = {0};
  906. PWSTR Server = NULL;
  907. RtlZeroMemory( &ObjectUser, sizeof( ND5_AUTH_INFO ) );
  908. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  909. eCommServer,
  910. eCommUserNameD,
  911. eCommPasswordD,
  912. eCommVerbose,
  913. eArgEnd);
  914. if ( Win32Err != ERROR_SUCCESS ) {
  915. DisplayHelp(ePriResetPwd);
  916. return( ERROR_INVALID_PARAMETER );
  917. }
  918. //
  919. // Get the server
  920. //
  921. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  922. eCommServer,
  923. &Server);
  924. if (ERROR_SUCCESS != Win32Err)
  925. {
  926. NetDompDisplayErrorMessage(Win32Err);
  927. return Win32Err;
  928. }
  929. if (!Server)
  930. {
  931. DisplayHelp(ePriResetPwd);
  932. return ERROR_INVALID_PARAMETER;
  933. }
  934. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  935. NULL,
  936. TRUE,
  937. &Domain);
  938. if (ERROR_SUCCESS != Win32Err)
  939. {
  940. NetDompDisplayErrorMessage(Win32Err);
  941. return Win32Err;
  942. }
  943. //
  944. // Get the password and user
  945. //
  946. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  947. eCommUserNameD,
  948. Domain,
  949. &ObjectUser);
  950. if (ERROR_SUCCESS != Win32Err)
  951. {
  952. NetDompDisplayErrorMessage(Win32Err);
  953. goto HandleResetExit;
  954. }
  955. if (!ObjectUser.User)
  956. {
  957. DisplayHelp(ePriResetPwd);
  958. Win32Err = ERROR_INVALID_PARAMETER;
  959. goto HandleResetExit;
  960. }
  961. Win32Err = NetDompResetPwd( Server,
  962. &ObjectUser,
  963. MSG_RESETPWD_OK,
  964. MSG_RESETPWD_BAD );
  965. if (NO_ERROR != Win32Err)
  966. {
  967. NetDompDisplayErrorMessage(Win32Err);
  968. }
  969. HandleResetExit:
  970. NetDompFreeAuthIdent( &ObjectUser );
  971. NetApiBufferFree( Server );
  972. NetApiBufferFree( Domain );
  973. return( Win32Err );
  974. }
  975. DWORD
  976. NetDompVerifyServerSC(
  977. IN PWSTR Domain,
  978. IN PWSTR Server,
  979. IN PND5_AUTH_INFO AuthInfo,
  980. IN ULONG OkMessageId,
  981. IN ULONG FailedMessageId
  982. )
  983. {
  984. DWORD Win32Err = ERROR_SUCCESS;
  985. PNETLOGON_INFO_2 NetlogonInfo2 = NULL;
  986. BOOL DomainMember = FALSE, SessionEstablished = FALSE;
  987. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Server ));
  988. Win32Err = NetpManageIPCConnect( Server,
  989. AuthInfo->User,
  990. AuthInfo->Password,
  991. NETSETUPP_CONNECT_IPC );
  992. if ( Win32Err == ERROR_SUCCESS ) {
  993. SessionEstablished = TRUE;
  994. }
  995. //
  996. // See if we're a domain member or not
  997. //
  998. if ( Win32Err == ERROR_SUCCESS ) {
  999. Win32Err = NetDompCheckDomainMembership( Server,
  1000. AuthInfo,
  1001. FALSE,
  1002. &DomainMember );
  1003. if ( Win32Err == ERROR_SUCCESS && !DomainMember ) {
  1004. Win32Err = NERR_SetupNotJoined;
  1005. }
  1006. }
  1007. if ( Win32Err == ERROR_SUCCESS ) {
  1008. LOG_VERBOSE(( MSG_VERBOSE_CHECKING_SC, Domain ));
  1009. Win32Err = I_NetLogonControl2( Server,
  1010. NETLOGON_CONTROL_TC_QUERY,
  1011. 2,
  1012. ( LPBYTE )&Domain,
  1013. ( LPBYTE *)&NetlogonInfo2 );
  1014. if ( Win32Err == ERROR_SUCCESS ) {
  1015. Win32Err = NetlogonInfo2->netlog2_pdc_connection_status;
  1016. if ( Win32Err == ERROR_SUCCESS ) {
  1017. NetDompDisplayMessage( OkMessageId, _wcsupr( Server ), _wcsupr( Domain ),
  1018. _wcsupr( NetlogonInfo2->netlog2_trusted_dc_name ) );
  1019. } else {
  1020. if ( FailedMessageId ) {
  1021. NetDompDisplayMessage( FailedMessageId, _wcsupr( Server ), _wcsupr( Domain ) );
  1022. NetDompDisplayErrorMessage( Win32Err );
  1023. }
  1024. }
  1025. NetApiBufferFree( NetlogonInfo2 );
  1026. }
  1027. }
  1028. if ( SessionEstablished ) {
  1029. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Server ));
  1030. NetpManageIPCConnect( Server,
  1031. AuthInfo->User,
  1032. AuthInfo->Password,
  1033. NETSETUPP_DISCONNECT_IPC );
  1034. }
  1035. return( Win32Err );
  1036. }
  1037. DWORD
  1038. NetDompHandleVerify(ARG_RECORD * rgNetDomArgs)
  1039. /*++
  1040. Routine Description:
  1041. This function will verify the secure channel with the domain
  1042. Arguments:
  1043. Args - List of command line arguments
  1044. Return Value:
  1045. ERROR_INVALID_PARAMETER - No object name was supplied
  1046. --*/
  1047. {
  1048. DWORD Win32Err = ERROR_SUCCESS;
  1049. PWSTR Domain = NULL;
  1050. ND5_AUTH_INFO ObjectUser;
  1051. RtlZeroMemory( &ObjectUser, sizeof( ND5_AUTH_INFO ) );
  1052. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  1053. eObject,
  1054. eCommDomain,
  1055. eCommUserNameO,
  1056. eCommPasswordO,
  1057. eCommVerbose,
  1058. eArgEnd);
  1059. if ( Win32Err != ERROR_SUCCESS ) {
  1060. DisplayHelp(ePriVerify);
  1061. return( ERROR_INVALID_PARAMETER );
  1062. }
  1063. PWSTR Object = rgNetDomArgs[eObject].strValue;
  1064. if ( !Object ) {
  1065. DisplayHelp(ePriVerify);
  1066. return( ERROR_INVALID_PARAMETER );
  1067. }
  1068. //
  1069. // Make sure that the object name we were given is valid
  1070. //
  1071. Win32Err = I_NetNameValidate( NULL,
  1072. Object,
  1073. NAMETYPE_COMPUTER,
  1074. LM2X_COMPATIBLE );
  1075. if ( Win32Err != ERROR_SUCCESS ) {
  1076. goto HandleVerifyExit;
  1077. }
  1078. //
  1079. // Ok, make sure that we have a specified domain...
  1080. //
  1081. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  1082. Object,
  1083. TRUE,
  1084. &Domain);
  1085. if ( Win32Err != ERROR_SUCCESS ) {
  1086. goto HandleVerifyExit;
  1087. }
  1088. //
  1089. // Get the password and user if it exists
  1090. //
  1091. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  1092. eCommUserNameO,
  1093. Domain,
  1094. &ObjectUser);
  1095. if ( Win32Err != ERROR_SUCCESS ) {
  1096. goto HandleVerifyExit;
  1097. }
  1098. Win32Err = NetDompVerifyServerSC( Domain,
  1099. Object,
  1100. &ObjectUser,
  1101. MSG_SC_OK,
  1102. MSG_SC_BAD );
  1103. HandleVerifyExit:
  1104. NetDompFreeAuthIdent( &ObjectUser );
  1105. NetApiBufferFree( Domain );
  1106. if (NO_ERROR != Win32Err)
  1107. {
  1108. NetDompDisplayErrorMessage(Win32Err);
  1109. }
  1110. return( Win32Err );
  1111. }
  1112. DWORD
  1113. NetDompJoinDownlevel(
  1114. IN PWSTR Server,
  1115. IN PWSTR Account,
  1116. IN PWSTR Password,
  1117. IN PWSTR Dc,
  1118. IN ULONG DcFlags,
  1119. IN BOOL AllowMove
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This function will join an NT4 machine to the domain. It does this remotely
  1124. Arguments:
  1125. Server - Server to join
  1126. Account - Account to use to contact the domain controller
  1127. Password - Password to use with the above account
  1128. Dc - Domain controller to speak to
  1129. DcFlags - Flags specifying various properties of Dc
  1130. AllowMove - If TRUE, allow the machine to join the domain even if it's already
  1131. joined to a domain
  1132. Return Value:
  1133. ERROR_INVALID_PARAMETER - No object name was supplied
  1134. --*/
  1135. {
  1136. DWORD Win32Err = ERROR_SUCCESS;
  1137. NTSTATUS Status = STATUS_SUCCESS;
  1138. LSA_HANDLE ClientLsaHandle = NULL, ServerLsaHandle = NULL, SecretHandle = NULL;
  1139. PPOLICY_PRIMARY_DOMAIN_INFO CurrentPolicyPDI = NULL, DomainPolicyPDI = NULL;
  1140. OBJECT_ATTRIBUTES OA;
  1141. UNICODE_STRING ServerU, Secret;
  1142. WCHAR AccountPassword[ LM20_PWLEN + 1 ];
  1143. BOOL DefaultJoin = FALSE, ServiceSet = FALSE, GroupsSet = FALSE, SidSet = FALSE;
  1144. //
  1145. // We will do things in the following order:
  1146. //
  1147. // - Create the computer account on the domain controller
  1148. // - Set the domain sid
  1149. // - Configure the netlogon service
  1150. // - Set the group memberships
  1151. // - Set the local secret. No rollback after this succeeds.
  1152. InitializeObjectAttributes(
  1153. &OA,
  1154. NULL,
  1155. 0L,
  1156. NULL,
  1157. NULL
  1158. );
  1159. if ( Server ) {
  1160. RtlInitUnicodeString( &ServerU, Server );
  1161. }
  1162. //InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
  1163. Status = LsaOpenPolicy( Server ? &ServerU : NULL,
  1164. &OA,
  1165. MAXIMUM_ALLOWED,
  1166. &ClientLsaHandle );
  1167. if ( NT_SUCCESS( Status ) ) {
  1168. RtlInitUnicodeString( &ServerU, Dc );
  1169. InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
  1170. Status = LsaOpenPolicy( &ServerU,
  1171. &OA,
  1172. MAXIMUM_ALLOWED,
  1173. &ServerLsaHandle );
  1174. }
  1175. //
  1176. // Read the current LSA policy
  1177. //
  1178. if ( NT_SUCCESS( Status ) ) {
  1179. Status = LsaQueryInformationPolicy( ClientLsaHandle,
  1180. PolicyPrimaryDomainInformation,
  1181. ( PVOID * )&CurrentPolicyPDI );
  1182. if ( NT_SUCCESS( Status ) ) {
  1183. Status = LsaQueryInformationPolicy( ServerLsaHandle,
  1184. PolicyPrimaryDomainInformation,
  1185. ( PVOID * )&DomainPolicyPDI );
  1186. }
  1187. }
  1188. Win32Err = RtlNtStatusToDosError( Status );
  1189. if ( Win32Err == ERROR_SUCCESS ) {
  1190. if ( CurrentPolicyPDI->Sid && !AllowMove ) {
  1191. Win32Err = NERR_SetupAlreadyJoined;
  1192. }
  1193. }
  1194. //
  1195. // Ok, now generate the password to use on the account
  1196. //
  1197. if ( Win32Err == ERROR_SUCCESS ) {
  1198. Win32Err = NetpGetNt4RefusePasswordChangeStatus( Dc, &DefaultJoin );
  1199. if ( Win32Err == ERROR_SUCCESS ) {
  1200. if ( (Server != NULL) & DefaultJoin ) {
  1201. wcsncpy( AccountPassword, Server, LM20_PWLEN );
  1202. AccountPassword[ LM20_PWLEN ] = UNICODE_NULL;
  1203. _wcslwr( AccountPassword );
  1204. } else {
  1205. Win32Err = NetDompGenerateRandomPassword( AccountPassword,
  1206. LM20_PWLEN );
  1207. }
  1208. }
  1209. }
  1210. //
  1211. // Ok, if that worked, we'll start the actual set
  1212. //
  1213. if ( Win32Err == ERROR_SUCCESS ) {
  1214. //
  1215. // Manage the account
  1216. //
  1217. Win32Err = NetpManageMachineAccountWithSid( Server,
  1218. NULL,
  1219. Dc,
  1220. AccountPassword,
  1221. DomainPolicyPDI->Sid,
  1222. NETSETUPP_CREATE,
  1223. 0,
  1224. (DcFlags & DS_DS_FLAG) == 0 ?
  1225. TRUE : // NT4 or older DC
  1226. FALSE ); // NT5 DC
  1227. }
  1228. //
  1229. // Now, set the domain information
  1230. //
  1231. if ( Win32Err == ERROR_SUCCESS ) {
  1232. Status = LsaSetInformationPolicy( ClientLsaHandle,
  1233. PolicyPrimaryDomainInformation,
  1234. DomainPolicyPDI );
  1235. Win32Err = RtlNtStatusToDosError( Status );
  1236. }
  1237. if ( Win32Err == ERROR_SUCCESS ) {
  1238. SidSet = TRUE;
  1239. Win32Err = NetDompManageGroupMembership( Server,
  1240. DomainPolicyPDI->Sid,
  1241. FALSE );
  1242. }
  1243. //
  1244. // Configure netlogon
  1245. //
  1246. if ( Win32Err == ERROR_SUCCESS ) {
  1247. GroupsSet = TRUE;
  1248. Win32Err = NetDompControlService( Server,
  1249. SERVICE_NETLOGON,
  1250. SERVICE_AUTO_START );
  1251. }
  1252. //
  1253. // Finally, the secret
  1254. //
  1255. if ( Win32Err == ERROR_SUCCESS ) {
  1256. ServiceSet = TRUE;
  1257. Win32Err = NetDompManageMachineSecret(ClientLsaHandle,
  1258. AccountPassword,
  1259. NETSETUPP_CREATE);
  1260. }
  1261. //
  1262. // Unwind, if something failed
  1263. //
  1264. if ( Win32Err != ERROR_SUCCESS ) {
  1265. if ( ServiceSet ) {
  1266. NetDompControlService( Server,
  1267. SERVICE_NETLOGON,
  1268. SERVICE_DEMAND_START );
  1269. }
  1270. if ( GroupsSet ) {
  1271. NetDompManageGroupMembership( Server,
  1272. DomainPolicyPDI->Sid,
  1273. TRUE );
  1274. }
  1275. if ( SidSet ) {
  1276. LsaSetInformationPolicy( ClientLsaHandle,
  1277. PolicyPrimaryDomainInformation,
  1278. CurrentPolicyPDI );
  1279. }
  1280. }
  1281. LsaFreeMemory( CurrentPolicyPDI );
  1282. LsaFreeMemory( DomainPolicyPDI );
  1283. LsaClose( ClientLsaHandle );
  1284. LsaClose( ServerLsaHandle );
  1285. return( Win32Err );
  1286. }
  1287. DWORD
  1288. NetDompManageGroupMembership(
  1289. IN PWSTR Server,
  1290. IN PSID DomainSid,
  1291. IN BOOL Delete
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. Performs SAM account handling to either add or remove the DomainAdmins,
  1296. etc groups from the local groups.
  1297. Arguments:
  1298. Server - Server on which to perform the operation
  1299. DomainSid - SID of the domain being joined/left
  1300. Delete - Whether to add or remove the admin alias
  1301. Returns:
  1302. ERROR_SUCCESS -- Success
  1303. --*/
  1304. {
  1305. DWORD Win32Err = ERROR_SUCCESS;
  1306. //
  1307. // Keep these in synch with the rids and Sids below
  1308. //
  1309. ULONG LocalRids[] = {
  1310. DOMAIN_ALIAS_RID_ADMINS,
  1311. DOMAIN_ALIAS_RID_USERS
  1312. };
  1313. PWSTR LocalGroups[ sizeof( LocalRids ) / sizeof( ULONG )] = {
  1314. NULL,
  1315. NULL,
  1316. };
  1317. ULONG Rids[] = {
  1318. DOMAIN_GROUP_RID_ADMINS,
  1319. DOMAIN_GROUP_RID_USERS
  1320. };
  1321. static SID_IDENTIFIER_AUTHORITY BultinAuth = SECURITY_NT_AUTHORITY;
  1322. DWORD Sids[sizeof( SID )/sizeof( DWORD ) +
  1323. SID_MAX_SUB_AUTHORITIES ][ sizeof( Rids ) / sizeof( ULONG ) ];
  1324. DWORD DSidSize, *LastSub, i, j;
  1325. PUCHAR SubAuthCnt;
  1326. PWSTR LocalGroupName = NULL;
  1327. WCHAR DomainName[ sizeof( L"BUILTIN" )];
  1328. ULONG Size, DomainSize;
  1329. SID_NAME_USE SNE;
  1330. PWSTR FullServer = NULL;
  1331. if ( DomainSid == NULL ) {
  1332. return( Win32Err );
  1333. }
  1334. if ( Server && *Server != L'\\' ) {
  1335. Win32Err = NetApiBufferAllocate( ( wcslen( Server ) + 3 ) * sizeof( WCHAR ),
  1336. (PVOID*)&FullServer );
  1337. if ( Win32Err == ERROR_SUCCESS ) {
  1338. swprintf( FullServer, L"\\\\%ws", Server );
  1339. }
  1340. } else {
  1341. FullServer = Server;
  1342. }
  1343. DSidSize = RtlLengthSid( DomainSid );
  1344. for ( i = 0 ; i < sizeof(Rids) / sizeof(ULONG) && Win32Err == NERR_Success; i++) {
  1345. Size = 0;
  1346. DomainSize = sizeof( DomainName );
  1347. //
  1348. // Get the name of the local group first...
  1349. //
  1350. RtlInitializeSid( ( PSID )Sids[ i ], &BultinAuth, 2 );
  1351. *( RtlSubAuthoritySid( ( PSID )Sids[ i ], 0 ) ) = SECURITY_BUILTIN_DOMAIN_RID;
  1352. *( RtlSubAuthoritySid( ( PSID )Sids[ i ], 1 ) ) = LocalRids[ i ];
  1353. LookupAccountSidW( FullServer,
  1354. ( PSID )Sids[ i ],
  1355. NULL,
  1356. &Size,
  1357. DomainName,
  1358. &DomainSize,
  1359. &SNE );
  1360. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
  1361. Win32Err = NetApiBufferAllocate( Size * sizeof( WCHAR ),
  1362. (PVOID*)&LocalGroupName );
  1363. if ( Win32Err == NERR_Success ) {
  1364. if ( !LookupAccountSidW( FullServer, ( PSID )Sids[ i ], LocalGroupName,
  1365. &Size, DomainName, &DomainSize, &SNE ) ) {
  1366. Win32Err = GetLastError();
  1367. if ( Win32Err == ERROR_NONE_MAPPED ) {
  1368. Win32Err = NERR_Success;
  1369. continue;
  1370. }
  1371. } else {
  1372. LocalGroups[ i ] = LocalGroupName;
  1373. }
  1374. } else {
  1375. break;
  1376. }
  1377. }
  1378. RtlCopyMemory( ( PBYTE )Sids[i], DomainSid, DSidSize );
  1379. //
  1380. // Now, add the new domain relative rid
  1381. //
  1382. SubAuthCnt = GetSidSubAuthorityCount( ( PSID )Sids[ i ] );
  1383. ( *SubAuthCnt )++;
  1384. LastSub = GetSidSubAuthority( ( PSID )Sids[ i ], ( *SubAuthCnt ) - 1 );
  1385. *LastSub = Rids[ i ];
  1386. if ( !Delete ) {
  1387. LOG_VERBOSE(( MSG_VERBOSE_ADD_LOCALGRP, LocalGroups[ i ] ));
  1388. Win32Err = NetLocalGroupAddMember( FullServer,
  1389. LocalGroups[i],
  1390. ( PSID )Sids[ i ] );
  1391. if ( Win32Err == ERROR_MEMBER_IN_ALIAS ) {
  1392. Win32Err = NERR_Success;
  1393. }
  1394. } else {
  1395. LOG_VERBOSE(( MSG_VERBOSE_REMOVE_LOCALGRP, LocalGroups[ i ] ));
  1396. Win32Err = NetLocalGroupDelMember( FullServer,
  1397. LocalGroups[i],
  1398. ( PSID )Sids[ i ] );
  1399. if ( Win32Err == ERROR_MEMBER_NOT_IN_ALIAS ) {
  1400. Win32Err = NERR_Success;
  1401. }
  1402. }
  1403. }
  1404. //
  1405. // If something failed, try to restore what was deleted
  1406. //
  1407. if ( Win32Err != NERR_Success ) {
  1408. for ( j = 0; j < i; j++ ) {
  1409. if ( !Delete ) {
  1410. NetLocalGroupAddMember( FullServer,
  1411. LocalGroups[ j ],
  1412. ( PSID )Sids[ j ] );
  1413. } else {
  1414. NetLocalGroupDelMember( FullServer,
  1415. LocalGroups[ j ],
  1416. ( PSID )Sids[ j ] );
  1417. }
  1418. }
  1419. }
  1420. for ( i = 0; i < sizeof( LocalRids ) / sizeof( ULONG ); i++ ) {
  1421. if ( LocalGroups[ i ] ) {
  1422. NetApiBufferFree( LocalGroups[ i ] );
  1423. }
  1424. }
  1425. if ( FullServer != Server ) {
  1426. NetApiBufferFree( FullServer );
  1427. }
  1428. return( Win32Err );
  1429. }
  1430. DWORD
  1431. NetDompManageMachineSecret(
  1432. IN LSA_HANDLE PolicyHandle,
  1433. IN LPWSTR lpPassword,
  1434. IN INT fControl
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. Create/delete the machine secret
  1439. Arguments:
  1440. PolicyHandle -- Optional open handle to the policy
  1441. lpPassword -- Machine password to use.
  1442. fControl -- create/remove flags
  1443. Returns:
  1444. NERR_Success -- Success
  1445. --*/
  1446. {
  1447. NTSTATUS Status = STATUS_SUCCESS;
  1448. LSA_HANDLE SecretHandle = NULL;
  1449. UNICODE_STRING Key, Data;
  1450. BOOLEAN SecretCreated = FALSE;
  1451. //
  1452. // open/create the secret
  1453. //
  1454. RtlInitUnicodeString( &Key, L"$MACHINE.ACC" );
  1455. RtlInitUnicodeString( &Data, lpPassword );
  1456. Status = LsaOpenSecret(PolicyHandle,
  1457. &Key,
  1458. fControl == NETSETUPP_CREATE ?
  1459. SECRET_SET_VALUE | SECRET_QUERY_VALUE :
  1460. DELETE,
  1461. &SecretHandle );
  1462. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  1463. {
  1464. if ( fControl == NETSETUPP_DELETE )
  1465. {
  1466. Status = STATUS_SUCCESS;
  1467. }
  1468. else
  1469. {
  1470. Status = LsaCreateSecret( PolicyHandle, &Key,
  1471. SECRET_SET_VALUE, &SecretHandle );
  1472. if ( NT_SUCCESS( Status ) )
  1473. {
  1474. SecretCreated = TRUE;
  1475. }
  1476. }
  1477. }
  1478. if ( !NT_SUCCESS( Status ) )
  1479. {
  1480. NetpLog(( "NetpManageMachineSecret: Open/Create secret failed: 0x%lx\n", Status ));
  1481. }
  1482. if ( NT_SUCCESS( Status ) )
  1483. {
  1484. if ( fControl == NETSETUPP_CREATE )
  1485. {
  1486. #if !defined(USE_LSA_STORE_PRIVATE_DATA)
  1487. //
  1488. // cannot read the current value over the net for NT4 machine,
  1489. // so save the new value as current value
  1490. //
  1491. Status = LsaSetSecret( SecretHandle, &Data, &Data );
  1492. #else
  1493. //
  1494. // LsaStorePrivateData sets the old pw to be the current pw and then
  1495. // stores the new pw as the current.
  1496. //
  1497. Status = LsaStorePrivateData(PolicyHandle, &Key, &Data);
  1498. #endif
  1499. }
  1500. else
  1501. {
  1502. //
  1503. // No secret handle means we failed earlier in
  1504. // some intermediate state. That's ok, just press on.
  1505. //
  1506. if ( SecretHandle != NULL )
  1507. {
  1508. Status = LsaDelete( SecretHandle );
  1509. if ( NT_SUCCESS( Status ) )
  1510. {
  1511. SecretHandle = NULL;
  1512. }
  1513. }
  1514. }
  1515. }
  1516. if ( SecretHandle )
  1517. {
  1518. LsaClose( SecretHandle );
  1519. }
  1520. return( RtlNtStatusToDosError( Status ) );
  1521. }