Leaked source code of windows server 2003
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.

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