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.

4581 lines
151 KiB

  1. /*++
  2. Copyright (c) 1997 - 1997 Microsoft Corporation
  3. Module Name:
  4. netjoin.c
  5. Abstract:
  6. Implementation of the private Net setup apis for joining/unjoinging
  7. domains.
  8. Author:
  9. Mac McLain (MacM) 19-Feb-1997
  10. Environment:
  11. User mode only.
  12. Revision History:
  13. --*/
  14. // Netlib uses DsGetDcName AND is linked into netapi32 where DsGetDcName is
  15. // implemented. So define that we aren't importing the API.
  16. #define _DSGETDCAPI_
  17. #include <netsetp.h>
  18. #include <lmaccess.h>
  19. #include <lmsname.h>
  20. #include <winreg.h>
  21. #include <wincrypt.h>
  22. #include <icanon.h>
  23. #include <dnsapi.h>
  24. #include <netlib.h>
  25. #include <dsgetdcp.h>
  26. #include <dsrole.h>
  27. #include <names.h>
  28. #include "joinp.h"
  29. /* -----------------------------------------------------------------
  30. Joining a domain
  31. ----------------
  32. When a computer joins a domain, the following changes occur on
  33. the computer and the dc of that domain. The changes are not made
  34. in the order shown here.
  35. changes on client computer:
  36. ---------------------------
  37. NT4 & NT5
  38. ~~~~~~~~~
  39. - create a LSA secret named $MACHINE.ACC. The value of this
  40. secret is the password to be used for accessing the machine
  41. account for this computer on the dc.
  42. - set LSA PolicyPrimaryDomainInformation. this includes:
  43. - domain name
  44. - domain SID
  45. - add certain user groups in the new domain to local groups
  46. - enable and start netlogon service
  47. NT5 only
  48. ~~~~~~~~~
  49. - update the netlogon cache to indicate the new domain details
  50. - set LSA PolicyDnsDomainInformation. this includes:
  51. - domain name
  52. - domain SID
  53. - dns domain name
  54. - dns forest name
  55. - domain guid
  56. - set ComputerNamePhysicalDnsDomain if changed.
  57. - enable and start w32time service
  58. - for performance reasons, record locally info about the dc
  59. on which machine account is created.
  60. whistler only
  61. -------------
  62. - instead of starting w32time, call w32time!W32TimeVerifyJoinConfig
  63. (when unjoining, call w32time!W32TimeVerifyUnjoinConfig instead)
  64. changes on dc:
  65. --------------
  66. NT4 & NT5
  67. ~~~~~~~~~
  68. - create a computer object. the name of this object is generated by
  69. appending a '$' to the uppercased name of the client computer.
  70. This object is protected by a password that is stored in $MACHINE.ACC
  71. as explained earlier.
  72. NT5 only
  73. ~~~~~~~~~
  74. - create SPN of the computer object
  75. this is not directly created by the netjoin code. netjoin code
  76. waits on netlogon to perform this creation.
  77. ----------------------------------------------------------------- */
  78. NET_API_STATUS
  79. NET_API_FUNCTION
  80. NetpJoinWorkgroup(
  81. IN LPWSTR lpMachine,
  82. IN LPWSTR lpWrkgrp
  83. )
  84. /*++
  85. Routine Description:
  86. Joins the machine to the specified workgroup
  87. Arguments:
  88. lpMachine -- Name of the machine being run on
  89. lpWrkgrp -- Workgroup to join
  90. Returns:
  91. NERR_Success -- Success
  92. --*/
  93. {
  94. NET_API_STATUS NetStatus = NERR_Success;
  95. NetSetuppOpenLog();
  96. NetpLog(( "NetpJoinWorkgroup: joining computer '%ws' to workgroup '%ws'\n",
  97. lpMachine, lpWrkgrp ));
  98. //
  99. // First, check the name...
  100. //
  101. NetStatus = NetpValidateName( lpMachine, lpWrkgrp, NULL, NULL,
  102. NetSetupWorkgroup );
  103. if ( NetStatus == NERR_Success )
  104. {
  105. NetStatus = NetpSetLsaPrimaryDomain(lpWrkgrp, NULL, NULL, NULL);
  106. if ( NetStatus == NERR_Success )
  107. {
  108. NetStatus = NetpControlServices( NETSETUP_SVC_MANUAL,
  109. NETSETUPP_SVC_NETLOGON );
  110. if ( NetStatus == ERROR_SERVICE_DOES_NOT_EXIST )
  111. {
  112. NetStatus = STATUS_SUCCESS;
  113. }
  114. }
  115. }
  116. NetpLog(( "NetpJoinWorkgroup: status: 0x%lx\n",
  117. NetStatus ));
  118. NetSetuppCloseLog();
  119. return( NetStatus );
  120. }
  121. NET_API_STATUS
  122. NET_API_FUNCTION
  123. NetpMachineValidToJoin(
  124. IN LPWSTR lpMachine,
  125. IN BOOL fJoiningDomain
  126. )
  127. /*++
  128. Routine Description:
  129. Determines whether it is valid for this machine to attempt to
  130. join a domain/workgroup
  131. Arguments:
  132. lpMachine -- Name of the machine being run on
  133. Returns:
  134. NERR_Success -- Success
  135. NERR_SetupAlreadyJoined -- The machine is already joined to a domain
  136. --*/
  137. {
  138. NET_API_STATUS NetStatus = NERR_Success;
  139. PPOLICY_PRIMARY_DOMAIN_INFO pPolicy;
  140. PPOLICY_DNS_DOMAIN_INFO pDns;
  141. BOOL fIsDC=FALSE;
  142. NT_PRODUCT_TYPE ProductType;
  143. if ( fJoiningDomain == TRUE )
  144. {
  145. //
  146. // Determine if we are running Personal SKU. If so, return error (Personal SKU not allowed to join domain)
  147. //
  148. OSVERSIONINFOEXW osvi;
  149. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
  150. if(GetVersionExW((OSVERSIONINFOW*)&osvi))
  151. {
  152. if ( osvi.wProductType == VER_NT_WORKSTATION && (osvi.wSuiteMask & VER_SUITE_PERSONAL))
  153. {
  154. return NERR_PersonalSku;
  155. }
  156. }
  157. }
  158. NetpLog(( "NetpMachineValidToJoin: '%ws'\n", GetStrPtr(lpMachine) ));
  159. //
  160. // check to see if the machine being joined is a DC
  161. // if it is, we cannot let this join another domain/workgroup.
  162. //
  163. if (!RtlGetNtProductType(&ProductType))
  164. {
  165. NetStatus = GetLastError();
  166. }
  167. else if (ProductType == NtProductLanManNt)
  168. {
  169. NetStatus = NERR_SetupDomainController;
  170. NetpLog(( "NetpMachineValidToJoin: the specified machine is a domain controller.\n"));
  171. }
  172. if (NetStatus == NERR_Success)
  173. {
  174. NetStatus = NetpGetLsaPrimaryDomain(NULL, &pPolicy, &pDns, NULL);
  175. if ( NetStatus == NERR_Success )
  176. {
  177. //
  178. // See if we have a domain SID
  179. //
  180. if ( IS_CLIENT_JOINED(pPolicy) )
  181. {
  182. NetStatus = NERR_SetupAlreadyJoined;
  183. NetpLog(( "NetpMachineValidToJoin: the specified machine is already joined to '%wZ'!\n", &pPolicy->Name));
  184. }
  185. LsaFreeMemory( pPolicy );
  186. LsaFreeMemory( pDns );
  187. }
  188. }
  189. NetpLog(( "NetpMachineValidToJoin: status: 0x%lx\n", NetStatus));
  190. return( NetStatus );
  191. }
  192. void
  193. NetpLogBuildInformation(
  194. VOID
  195. )
  196. /*++
  197. Routine Description:
  198. Logs information to the setup log regarding the OS version and build number
  199. Arguments:
  200. VOID
  201. Returns:
  202. VOID
  203. --*/
  204. {
  205. #ifdef NETSETUP_VERBOSE_LOGGING
  206. OSVERSIONINFO OsVersionInfo;
  207. OsVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
  208. if ( GetVersionEx( &OsVersionInfo ) ) {
  209. NetpLog(( "\tOS Version: %lu.%lu\n",
  210. OsVersionInfo.dwMajorVersion,
  211. OsVersionInfo.dwMinorVersion ));
  212. NetpLog(( "\tBuild number: %lu\n",
  213. OsVersionInfo.dwBuildNumber ));
  214. if ( OsVersionInfo.szCSDVersion[ 0 ] != L'\0' ) {
  215. NetpLog(( "\tServicePack: %ws\n",
  216. OsVersionInfo.szCSDVersion ));
  217. }
  218. }
  219. #endif
  220. }
  221. NET_API_STATUS
  222. NetpQueryService(
  223. IN LPWSTR ServiceName,
  224. OUT SERVICE_STATUS *ServiceStatus,
  225. OUT LPQUERY_SERVICE_CONFIG *ServiceConfig
  226. )
  227. /*++
  228. Routine Description:
  229. Query the status and the configuration of the specified service
  230. Arguments:
  231. ServiceName - The name of the service to query
  232. ServiceStatus - Returns the status of the service. The buffer
  233. pointed to by this parameter must be supplied by the caller.
  234. ServiceConfig - Returns the configuration of the service.
  235. Must be freed by the caller by calling LocalFree.
  236. Return Status:
  237. NO_ERROR - Indicates service successfully queried.
  238. Otherwise, an error is returned.
  239. --*/
  240. {
  241. NET_API_STATUS NetStatus = NO_ERROR;
  242. SC_HANDLE ScManagerHandle = NULL;
  243. SC_HANDLE ServiceHandle = NULL;
  244. LPQUERY_SERVICE_CONFIG LocalServiceConfig = NULL;
  245. DWORD ServiceConfigSize = 0;
  246. //
  247. // Open a handle to the Service.
  248. //
  249. ScManagerHandle = OpenSCManager(
  250. NULL,
  251. NULL,
  252. SC_MANAGER_CONNECT );
  253. if ( ScManagerHandle == NULL ) {
  254. NetStatus = GetLastError();
  255. NetpLog(( "NetpQueryService: %ws: OpenSCManager failed: %lu\n",
  256. ServiceName,
  257. NetStatus ));
  258. goto Cleanup;
  259. }
  260. ServiceHandle = OpenService(
  261. ScManagerHandle,
  262. ServiceName,
  263. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  264. if ( ServiceHandle == NULL ) {
  265. NetStatus = GetLastError();
  266. NetpLog(( "NetpQueryService: %ws: OpenService failed: %lu\n",
  267. ServiceName,
  268. NetStatus ));
  269. goto Cleanup;
  270. }
  271. //
  272. // Pre-allocate the service config struct since QueryServiceConfig
  273. // won't allow a null pointer, yet.
  274. //
  275. LocalServiceConfig = LocalAlloc( 0, sizeof(*LocalServiceConfig) );
  276. if ( LocalServiceConfig == NULL ) {
  277. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  278. goto Cleanup;
  279. }
  280. if ( !QueryServiceConfig( ServiceHandle,
  281. LocalServiceConfig,
  282. sizeof(*LocalServiceConfig),
  283. &ServiceConfigSize) ) {
  284. //
  285. // Handle the error
  286. //
  287. NetStatus = GetLastError();
  288. if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
  289. NetpLog(( "NetpQueryService: %ws: QueryServiceConfig failed: %lu\n",
  290. ServiceName,
  291. NetStatus ));
  292. goto Cleanup;
  293. }
  294. if ( LocalServiceConfig != NULL ) {
  295. LocalFree( LocalServiceConfig );
  296. LocalServiceConfig = NULL;
  297. }
  298. LocalServiceConfig = LocalAlloc( 0, ServiceConfigSize );
  299. if ( LocalServiceConfig == NULL ) {
  300. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  301. goto Cleanup;
  302. }
  303. if ( !QueryServiceConfig( ServiceHandle,
  304. LocalServiceConfig,
  305. ServiceConfigSize,
  306. &ServiceConfigSize) ) {
  307. NetStatus = GetLastError();
  308. NetpLog(( "NetpQueryService: %ws: QueryServiceConfig failed again: %lu\n",
  309. ServiceName,
  310. NetStatus ));
  311. goto Cleanup;
  312. }
  313. }
  314. //
  315. // Query the status of the service.
  316. //
  317. if ( !QueryServiceStatus(ServiceHandle, ServiceStatus) ) {
  318. NetStatus = GetLastError();
  319. NetpLog(( "NetpQueryService: %ws: QueryServiceStatus failed: %lu\n",
  320. ServiceName,
  321. NetStatus ));
  322. goto Cleanup;
  323. }
  324. //
  325. // Success
  326. //
  327. NetStatus = NO_ERROR;
  328. Cleanup:
  329. if ( ScManagerHandle != NULL ) {
  330. (VOID) CloseServiceHandle(ScManagerHandle);
  331. }
  332. if ( ServiceHandle != NULL ) {
  333. (VOID) CloseServiceHandle(ServiceHandle);
  334. }
  335. if ( NetStatus == NO_ERROR ) {
  336. *ServiceConfig = LocalServiceConfig;
  337. } else if ( LocalServiceConfig != NULL ) {
  338. LocalFree( LocalServiceConfig );
  339. }
  340. return NetStatus;
  341. }
  342. NET_API_STATUS
  343. NET_API_FUNCTION
  344. NetpJoinDomain(
  345. IN LPWSTR lpMachine,
  346. IN LPWSTR lpDomainSpecifier,
  347. IN LPWSTR lpMachineAccountOU, OPTIONAL
  348. IN LPWSTR lpAccount,
  349. IN LPWSTR lpPassword,
  350. IN DWORD fJoinOpts
  351. )
  352. /*++
  353. Routine Description:
  354. Joins the machine to the specified domain
  355. Arguments:
  356. lpMachine -- Name of the machine being joined
  357. lpDomainSpecifier -- Domain to join.
  358. syntax of the parameter is:
  359. domain-name[\preferred-domain-controller-name]
  360. e.g.:
  361. ntdev\ntdsdc01 or ntdev
  362. lpMachineAccountOU -- Optional OU in which to create the machine account
  363. lpAccount -- User account for validation
  364. lpPassword -- Password to use for validation.
  365. The password has been encoded and the
  366. first WCHAR of the password buffer is the seed
  367. fJoinOptions -- Options to employ when joining, see below
  368. NETSETUP_JOIN_DOMAIN if set join domain otherwise join workgroup
  369. NETSETUP_ACCT_CREATE Do the server side account creation/rename
  370. NETSETUP_ACCT_DELETE Delete the account when a domain is left
  371. NETSETUP_WIN9X_UPGRADE use only during upgrade of win9x to NT
  372. NETSETUP_DOMAIN_JOIN_IF_JOINED Allow the client to join a new domain
  373. even if it is already joined to a domain
  374. NETSETUP_JOIN_UNSECURE Performs an unsecure join
  375. NETSETUP_INSTALL_INVOCATION use only during system install
  376. (not currently used)
  377. NETSETUP_MACHINE_PWD_PASSED Indicates that the machine password is passed
  378. in lpPassword. Valid only for unsecure joins (i.e.
  379. NETSETUP_JOIN_UNSECURE must also be set). If set,
  380. the passed in password will be used for machine
  381. password and the user credentials will be assumed
  382. to be NULL (i.e. join will happen over null session
  383. to the DC which is the case for unsecure joins)
  384. NETSETUP_DEFER_SPN_SET Specifies that writting SPN and DnsHostName
  385. attributes on the computer object should be
  386. defered until rename that will follow this join.
  387. This flag will be set bu the UI in case the user
  388. joins and renames the machine at the same time. In
  389. this case we don't want to set SPN at join time because
  390. the new computer name (as specified by "NV Domain" in
  391. System\\CurrentControlSet\\Services\\Tcpip\\Parameters
  392. registry) may contain the new value that doesn't
  393. correspond to the current SamAccountName.
  394. Returns:
  395. NERR_Success -- Success
  396. Notes:
  397. --*/
  398. {
  399. NET_API_STATUS NetStatus = NERR_Success, NetStatus2;
  400. PWSTR DomainControllerName = NULL;
  401. ULONG DcFlags = 0;
  402. NETSETUP_SAVED_JOIN_STATE SavedState;
  403. PPOLICY_PRIMARY_DOMAIN_INFO pPolicyPDI = NULL, pPolicyLocalPDI = NULL;
  404. PPOLICY_DNS_DOMAIN_INFO pPolicyDns = NULL, pPolicyLocalDns = NULL;
  405. BOOLEAN SecretCreated = FALSE, AccountCreated = FALSE;
  406. BOOLEAN GroupsSet = FALSE, DomainInfoSet = FALSE;
  407. BOOLEAN IpcConnect = FALSE;
  408. LSA_HANDLE hLsa = NULL, hDC = NULL;
  409. WCHAR MachinePasswordBuffer[ PWLEN + 1], *lpMachinePassword = NULL;
  410. ULONG MachinePasswordLen=0;
  411. ULONG IPCConnectFlags = NETSETUPP_CONNECT_IPC;
  412. ULONG GetDcFlags = 0;
  413. UNICODE_STRING EncodedPassword;
  414. UNICODE_STRING EncodedMachinePassword = {0};
  415. UCHAR Seed, MachinePasswordSeed;
  416. BOOL UseDefaultPassword = FALSE;
  417. BOOL fIsNt4Dc=FALSE;
  418. BOOL fRandomPwdPreferred=TRUE;
  419. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  420. PDOMAIN_CONTROLLER_INFO NetbiosDcInfo = NULL;
  421. LPWSTR DomainName = NULL;
  422. LPWSTR NetbiosDomainName = NULL;
  423. LPWSTR DnsHostName = NULL;
  424. LPWSTR SamAccountName = NULL;
  425. LPWSTR MachineAccount = NULL;
  426. BOOL DomainControllerPassed = FALSE;
  427. BOOLEAN SpnSet = FALSE;
  428. BOOLEAN NetlogonStopped = FALSE;
  429. BOOLEAN NetlogonStarted = FALSE;
  430. BOOLEAN NetlogonEnabled = FALSE;
  431. BOOLEAN AutoenrolConfigUpdated = FALSE;
  432. SERVICE_STATUS OldNetlogonServiceStatus;
  433. LPQUERY_SERVICE_CONFIG OldNetlogonServiceConfig = NULL;
  434. NetpLog(( "NetpJoinDomain\n" ));
  435. NetpLog(( "\tMachine: %ws\n", GetStrPtr(lpMachine)));
  436. NetpLog(( "\tDomain: %ws\n", GetStrPtr(lpDomainSpecifier)));
  437. NetpLog(( "\tMachineAccountOU: %ws\n",
  438. GetStrPtr(lpMachineAccountOU)));
  439. NetpLog(( "\tAccount: %ws\n", GetStrPtr(lpAccount)));
  440. NetpLog(( "\tOptions: 0x%lx\n", fJoinOpts ));
  441. NetpLogBuildInformation();
  442. //
  443. // Process the special case when the machine password is passed
  444. //
  445. if ( FLAG_ON(fJoinOpts, NETSETUP_MACHINE_PWD_PASSED) ) {
  446. //
  447. // Verify that this is unsecure join
  448. //
  449. if ( !FLAG_ON(fJoinOpts, NETSETUP_JOIN_UNSECURE) ) {
  450. NetpLog(( "NetpJoinDomain: Machine password is passed for secure join. Error out.\n" ));
  451. NetStatus = ERROR_INVALID_PARAMETER;
  452. goto Cleanup;
  453. }
  454. //
  455. // Verify that the account name is not passed
  456. //
  457. if ( lpAccount != NULL ) {
  458. NetpLog(( "NetpJoinDomain: Machine password and the user account are passed. Error out.\n" ));
  459. NetStatus = ERROR_INVALID_PARAMETER;
  460. goto Cleanup;
  461. }
  462. //
  463. // The password must be specified
  464. //
  465. if ( lpPassword == NULL ) {
  466. NetpLog(( "NetpJoinDomain: NULL machine password is passed. Error out.\n" ));
  467. NetStatus = ERROR_PASSWORD_RESTRICTION;
  468. goto Cleanup;
  469. }
  470. //
  471. // Switch the passwords
  472. //
  473. lpMachinePassword = lpPassword;
  474. lpPassword = NULL;
  475. MachinePasswordLen = wcslen(lpMachinePassword);
  476. if ( MachinePasswordLen < 1 ) {
  477. NetpLog(( "NetpJoinDomain: zero length machine password is passed. Error out.\n" ));
  478. NetStatus = ERROR_PASSWORD_RESTRICTION;
  479. goto Cleanup;
  480. }
  481. MachinePasswordSeed = ( UCHAR )*lpMachinePassword;
  482. RtlInitUnicodeString( &EncodedMachinePassword, lpMachinePassword + 1 );
  483. RtlRunDecodeUnicodeString( MachinePasswordSeed, &EncodedMachinePassword );
  484. //
  485. // Advance the pointer to the machine password
  486. // passing the encode byte
  487. //
  488. lpMachinePassword ++;
  489. MachinePasswordLen --;
  490. }
  491. if ( lpPassword )
  492. {
  493. if ( wcslen( lpPassword ) < 1 )
  494. {
  495. NetStatus = ERROR_INVALID_PARAMETER;
  496. goto Cleanup;
  497. }
  498. Seed = ( UCHAR )*lpPassword;
  499. RtlInitUnicodeString( &EncodedPassword, lpPassword + 1 );
  500. }
  501. else
  502. {
  503. RtlZeroMemory( &EncodedPassword, sizeof( UNICODE_STRING ) );
  504. Seed = 0;
  505. }
  506. RtlZeroMemory( &SavedState, sizeof( NETSETUP_SAVED_JOIN_STATE ) );
  507. if ( !FLAG_ON( fJoinOpts, NETSETUP_ACCT_CREATE ) )
  508. {
  509. IPCConnectFlags |= NETSETUPP_NULL_SESSION_IPC;
  510. }
  511. // check to see if a preferred-dc name is supplied by specifying
  512. // lpDomainSpecifier in the format 'domain\dc'
  513. NetStatus = NetpCrackDomainSpecifier( lpDomainSpecifier, &DomainName,
  514. &DomainControllerName );
  515. //
  516. // First, check the name of the domain to which we want to join
  517. //
  518. if ( NetStatus == NERR_Success )
  519. {
  520. //
  521. // Indicate that the DC name was passed
  522. //
  523. if ( DomainControllerName != NULL ) {
  524. DomainControllerPassed = TRUE;
  525. }
  526. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  527. NetStatus = NetpValidateName( lpMachine, DomainName, lpAccount,
  528. EncodedPassword.Buffer, NetSetupDomain );
  529. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  530. if ( NetStatus == DNS_ERROR_NON_RFC_NAME )
  531. {
  532. NetStatus = NERR_Success;
  533. }
  534. }
  535. if ( NetStatus != NERR_Success )
  536. {
  537. goto Cleanup;
  538. }
  539. GetDcFlags = FLAG_ON( fJoinOpts, NETSETUP_ACCT_CREATE ) ?
  540. NETSETUPP_DSGETDC_FLAGS : NETSETUP_DSGETDC_FLAGS_ACCOUNT_EXISTS;
  541. //
  542. // If DC was not passed, discover one
  543. //
  544. if ( !DomainControllerPassed )
  545. {
  546. //
  547. // otherwise, find a DC in the domain using these steps:
  548. // - find a writable dc that has this machine account
  549. // - if we cannot find such dc, find any writable dc
  550. //
  551. NetStatus = NetpDsGetDcName( NULL,
  552. DomainName, lpMachine, GetDcFlags,
  553. &DcFlags, &DomainControllerName, &DcInfo );
  554. }
  555. //
  556. // First establish connection with the dc we found
  557. //
  558. if ( NetStatus == NERR_Success )
  559. {
  560. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  561. NetStatus = NetpManageIPCConnect( DomainControllerName,
  562. lpAccount, EncodedPassword.Buffer,
  563. IPCConnectFlags );
  564. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  565. NetpLog(( "NetpJoinDomain: status of connecting to dc '%ws': 0x%lx\n", DomainControllerName, NetStatus ));
  566. if ( NetStatus == NERR_Success ) {
  567. IpcConnect = TRUE;
  568. }
  569. }
  570. //
  571. // If the DC is passed, execute DsGetDcName on that DC to get the
  572. // DC info. Do this after setting up a connection to avoid access
  573. // denied problems. Verify that the passed computer name is indeed
  574. // a DC by comparing the name that the computer returns with the one
  575. // passed to us.
  576. //
  577. if ( NetStatus == NERR_Success && DomainControllerPassed ) {
  578. BOOL NameVerified = FALSE;
  579. DNS_STATUS DnsStatus;
  580. //
  581. // If the passed DC name is valid DNS name, try getting
  582. // the DNS name from that DC. Skipp \\ in the name.
  583. //
  584. DnsStatus = DnsValidateDnsName_W( DomainControllerName+2 );
  585. if ( DnsStatus == ERROR_SUCCESS ||
  586. DnsStatus == DNS_ERROR_NON_RFC_NAME ) {
  587. NetStatus = DsGetDcName( DomainControllerName,
  588. DomainName,
  589. NULL,
  590. NULL,
  591. DS_RETURN_DNS_NAME,
  592. &DcInfo );
  593. //
  594. // Check if this returned the info about the DC we wanted
  595. //
  596. if ( NetStatus == NERR_Success ) {
  597. if ( DnsNameCompare_W( DomainControllerName+2,
  598. DcInfo->DomainControllerName+2 ) ) {
  599. NetpLog(( "NetpJoinDomain: Passed DC '%ws' verified as DNS name '%ws'\n",
  600. DomainControllerName,
  601. DcInfo->DomainControllerName ));
  602. NameVerified = TRUE;
  603. } else {
  604. NetpLog(( "NetpJoinDomain: Passed DC '%ws' NOT verified as DNS name '%ws'\n",
  605. DomainControllerName,
  606. DcInfo->DomainControllerName ));
  607. }
  608. //
  609. // If the DC runs NT4 and thus does not have the server part of DsGetDcName,
  610. // passing the prefered DC name is not supported -- there is only one
  611. // NT4.0 DC that can be used for join - the PDC.
  612. //
  613. } else if ( NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
  614. NetpLog(( "NetpJoinDomain: Passed DC '%ws' is not NT5\n",
  615. DomainControllerName ));
  616. NetStatus = ERROR_NOT_SUPPORTED;
  617. goto Cleanup;
  618. } else {
  619. NetpLog(( "NetpJoinDomain: DsGetDcName on passed DC '%ws' failed: 0x%lx\n",
  620. DomainControllerName,
  621. NetStatus ));
  622. }
  623. } else {
  624. NetpLog(( "NetpJoinDomain: Passed DC name '%ws' is not valid DNS name.\n",
  625. DomainControllerName ));
  626. }
  627. //
  628. // If DNS didn't work, try Netbios name
  629. //
  630. if ( !NameVerified ) {
  631. //
  632. // Skipp \\ in the name.
  633. //
  634. if ( NetpIsComputerNameValid( DomainControllerName+2 ) ) {
  635. if ( DcInfo != NULL ) {
  636. NetApiBufferFree( DcInfo );
  637. DcInfo = NULL;
  638. }
  639. NetStatus = DsGetDcName( DomainControllerName,
  640. DomainName,
  641. NULL,
  642. NULL,
  643. DS_RETURN_FLAT_NAME,
  644. &DcInfo );
  645. //
  646. // Check if this returned the info about the DC we wanted
  647. //
  648. if ( NetStatus == NERR_Success ) {
  649. if ( I_NetNameCompare( NULL,
  650. DomainControllerName+2,
  651. DcInfo->DomainControllerName+2,
  652. NAMETYPE_COMPUTER, 0 ) == 0 ) {
  653. NetpLog(( "NetpJoinDomain: Passed DC '%ws' verified as Netbios name '%ws'\n",
  654. DomainControllerName,
  655. DcInfo->DomainControllerName ));
  656. NameVerified = TRUE;
  657. } else {
  658. NetpLog(( "NetpJoinDomain: Passed DC '%ws' NOT verified as Netbios name '%ws'\n",
  659. DomainControllerName,
  660. DcInfo->DomainControllerName ));
  661. }
  662. } else {
  663. NetpLog(( "NetpJoinDomain: DsGetDcName on passed DC '%ws' failed: 0x%lx\n",
  664. DomainControllerName,
  665. NetStatus ));
  666. }
  667. } else {
  668. NetpLog(( "NetpJoinDomain: Passed DC name '%ws' is not valid Netbios name.\n",
  669. DomainControllerName ));
  670. }
  671. }
  672. if ( !NameVerified || DcInfo == NULL ) {
  673. NetpLog(( "NetpJoinDomain: Passed DC '%ws' is not verified: 0x%lx\n",
  674. DomainControllerName,
  675. NetStatus ));
  676. NetStatus = ERROR_INVALID_DOMAIN_ROLE;
  677. goto Cleanup;
  678. }
  679. //
  680. // Name has been verified. Save the DC flags.
  681. //
  682. DcFlags = DcInfo->Flags;
  683. }
  684. //
  685. // REVIEW kahrent 03-March-00
  686. // The design below doesn't work if a DC with different default
  687. // locale exists but is not the one the join is using for join.
  688. // The correct solution seems to be to use the locale insensitive
  689. // string comparison in netlogon, DS, SAM. The locale insensitive
  690. // string comparison is bug 23108 in Windows Bugs.
  691. //
  692. //$ kumarp 02-June-1999
  693. // the following requires admin access to the dc so that the
  694. // right regkeys could be read to decide the default locale.
  695. // We need to get a remoted API to get default locale
  696. // on the dc.
  697. //
  698. // make sure that the machine name is OEM codepage compatible with
  699. // the default codepage being used on the dc. The way we determine this
  700. // is by translating the machine name to oem string using the
  701. // local code page and the dc code page and then binary comparing
  702. // the resultant strings. if the strings are different, we
  703. // will fail join.
  704. //
  705. // Note that this is not a limitation of join apis. netlogon uses
  706. // oem translated netbios machine name internally. the translation
  707. // is different if the code page on the dc and the local machine are
  708. // not compatible. this causes lack of access to net resources.
  709. //
  710. /*
  711. if (NetStatus == NERR_Success)
  712. {
  713. NetStatus = NetpVerifyStrOemCompatibleOnMachine(DomainControllerName,
  714. lpMachine);
  715. NetpLog(( "NetpJoinDomain: status of verifying OEM compatibility of computer name: 0x%lx\n", NetStatus ));
  716. }
  717. */
  718. if (NetStatus != NERR_Success)
  719. {
  720. goto Cleanup;
  721. }
  722. fIsNt4Dc = !FLAG_ON( DcFlags, DS_DS_FLAG);
  723. //
  724. // If the OU is specified we must have an NT5 DC
  725. //
  726. if ( lpMachineAccountOU != NULL && fIsNt4Dc ) {
  727. NetpLog(( "NetpJoinDomain: OU is specified but couldn't get NT5 DC\n" ));
  728. NetStatus = ERROR_NO_SUCH_DOMAIN;
  729. goto Cleanup;
  730. }
  731. //
  732. // Ensure that the domain and machine names are different
  733. // If we already have the Netbios domain info, just use it
  734. //
  735. // BLACKCOMB: Move this check into NetpGetComputerObjectDn
  736. // where we carck the DNS domain name into the Netbios
  737. // domain name as needed.
  738. //
  739. if ( (DcFlags & DS_DNS_DOMAIN_FLAG) == 0 ) {
  740. NetbiosDomainName = DcInfo->DomainName;
  741. //
  742. // Otherwise call DsGetDcName again to get the Netbios domain info.
  743. // (This will return cached info unless the DC was passed to us)
  744. //
  745. } else {
  746. NetStatus = DsGetDcName( NULL,
  747. DomainName,
  748. NULL,
  749. NULL,
  750. DS_RETURN_FLAT_NAME,
  751. &NetbiosDcInfo );
  752. if ( NetStatus != NO_ERROR ) {
  753. NetpLog(( "NetpJoinDomain: DsGetDcName (for Netbios domain name) failed: 0x%lx\n",
  754. NetStatus ));
  755. goto Cleanup;
  756. }
  757. NetbiosDomainName = NetbiosDcInfo->DomainName;
  758. }
  759. //
  760. // Verify that the computer name is not the Netbios domain name
  761. //
  762. if ( I_NetNameCompare( NULL,
  763. lpMachine,
  764. NetbiosDomainName,
  765. NAMETYPE_COMPUTER, 0 ) == 0 ) {
  766. NetpLog(( "NetpJoinDomain: Computer name is same as Netbios domain name %ws %ws\n",
  767. lpMachine,
  768. NetbiosDomainName ));
  769. NetStatus = ERROR_INVALID_DOMAINNAME;
  770. goto Cleanup;
  771. }
  772. //
  773. // Get the lsa domain info on the DC
  774. //
  775. if ( NetStatus == NERR_Success )
  776. {
  777. NetStatus = NetpGetLsaPrimaryDomain(DomainControllerName,
  778. &pPolicyPDI, &pPolicyDns, &hDC);
  779. }
  780. //
  781. // Determine DnsHostName of this machine
  782. //
  783. if ( !fIsNt4Dc && pPolicyDns != NULL ) {
  784. NetStatus = NetpGetDnsHostName( NULL, // read tne new host name from registry
  785. &pPolicyDns->DnsDomainName,
  786. FALSE, // Don't use the GP value as we are changing domains
  787. &DnsHostName );
  788. }
  789. if (NetStatus == NERR_Success)
  790. {
  791. //
  792. // If we are joining an NT4 domain and we are not doing a machine
  793. // account creation, we'll treat this as a win95 upgrade
  794. //
  795. if ( fIsNt4Dc &&
  796. !FLAG_ON( fJoinOpts, NETSETUP_ACCT_CREATE ) )
  797. {
  798. fJoinOpts |= NETSETUP_JOIN_UNSECURE;
  799. }
  800. //
  801. // Generate the machine password if it was not passed
  802. //
  803. if ( lpMachinePassword == NULL ) {
  804. fRandomPwdPreferred = !( FLAG_ON( fJoinOpts, NETSETUP_WIN9X_UPGRADE ) ||
  805. FLAG_ON( fJoinOpts, NETSETUP_JOIN_UNSECURE ) );
  806. //
  807. // Generate the password to use on the machine account.
  808. // This can either be the default password
  809. // (the 1st 14 characters of the machine name, lower cased),
  810. // or a randomly generated password.
  811. //
  812. NetStatus = NetpGeneratePassword( lpMachine,
  813. fRandomPwdPreferred,
  814. DomainControllerName,
  815. fIsNt4Dc,
  816. MachinePasswordBuffer );
  817. if ( NetStatus == NERR_Success )
  818. {
  819. lpMachinePassword = MachinePasswordBuffer;
  820. MachinePasswordLen = wcslen(lpMachinePassword);
  821. }
  822. }
  823. }
  824. //
  825. // if we are already joined to a domain, save the join state.
  826. //
  827. if ((NetStatus == NERR_Success) &&
  828. FLAG_ON( fJoinOpts, NETSETUP_DOMAIN_JOIN_IF_JOINED))
  829. {
  830. NetStatus = NetpHandleJoinedStateInfo( &SavedState,
  831. TRUE, &hLsa );
  832. }
  833. //
  834. // set the local machine secret, create if not already present
  835. //
  836. if ( NetStatus == NERR_Success )
  837. {
  838. //
  839. // If the machine password is passed, use the default
  840. // password (lowercased machine name) as the old password.
  841. // We do this because the passed in password is unsecure
  842. // since it is read from an unsecure unattend.txt file by
  843. // setup (that calls us). When netlogon starts, it will
  844. // detect that the old password is the default one, it will
  845. // set the new password to a new value it will generate, and
  846. // it will set the old value to the one which used to be the
  847. // new value (that was passed to us). The net effect is that
  848. // the password passed to us will be set as the old value
  849. // and the new value will be updated by netlogon.
  850. //
  851. NetStatus = NetpManageMachineSecret(
  852. lpMachine,
  853. lpMachinePassword,
  854. NETSETUPP_CREATE,
  855. FLAG_ON(fJoinOpts, NETSETUP_MACHINE_PWD_PASSED) ?
  856. TRUE : // use the default for old password
  857. FALSE,
  858. &hLsa );
  859. }
  860. //
  861. // set the machine account on the dc, create if not present
  862. //
  863. if ( NetStatus == NERR_Success )
  864. {
  865. SecretCreated = TRUE;
  866. if ( FLAG_ON( fJoinOpts, NETSETUP_ACCT_CREATE ) )
  867. {
  868. //
  869. // if OU is specified, create the account in OU, otherwise
  870. // create it globally
  871. //
  872. if ( lpMachineAccountOU )
  873. {
  874. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  875. NetStatus = NetpCreateComputerObjectInDs( DcInfo,
  876. lpAccount,
  877. EncodedPassword.Buffer,
  878. lpMachine,
  879. lpMachinePassword,
  880. DnsHostName,
  881. lpMachineAccountOU );
  882. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  883. NetpLog(( "NetpJoinDomain: status of creating account in OU: 0x%lx\n", NetStatus ));
  884. //
  885. // On success, indicate that we have set SPN
  886. //
  887. if ( NetStatus == NO_ERROR && DnsHostName != NULL ) {
  888. SpnSet = TRUE;
  889. }
  890. }
  891. else
  892. {
  893. NetStatus = NetpManageMachineAccountWithSid( lpMachine,
  894. NULL,
  895. DomainControllerName,
  896. lpMachinePassword,
  897. pPolicyPDI->Sid,
  898. NETSETUPP_CREATE,
  899. fJoinOpts,
  900. fIsNt4Dc );
  901. NetpLog(( "NetpJoinDomain: status of creating account: 0x%lx\n", NetStatus ));
  902. }
  903. if (( NetStatus == NERR_Success ) &&
  904. ( MachinePasswordLen != wcslen(lpMachinePassword) ))
  905. {
  906. //
  907. // the password was weakened by NetpManageMachineAccountWithSid
  908. // because the dc did not accpet strong password.
  909. // we need to update the local secret to reflect this.
  910. //
  911. NetStatus = NetpManageMachineSecret( lpMachine,
  912. lpMachinePassword,
  913. NETSETUPP_CREATE, FALSE, &hLsa );
  914. NetpLog(( "NetpJoinDomain: status of updating secret: 0x%lx\n",
  915. NetStatus ));
  916. }
  917. }
  918. else if ( FLAG_ON( fJoinOpts, NETSETUP_WIN9X_UPGRADE ) ||
  919. FLAG_ON( fJoinOpts, NETSETUP_JOIN_UNSECURE ) )
  920. {
  921. NetStatus = NetpValidateMachineAccount( DomainControllerName,
  922. DomainName,
  923. lpMachine,
  924. lpMachinePassword );
  925. NetpLog(( "NetpJoinDomain: w9x: status of validating account: 0x%lx\n", NetStatus ));
  926. }
  927. else
  928. {
  929. // if we are not creating the machine account,
  930. // just set the password
  931. NetStatus = NetpSetMachineAccountPasswordAndTypeEx(
  932. DomainControllerName, pPolicyPDI->Sid,
  933. lpMachine, lpMachinePassword,
  934. ACCOUNT_STATE_ENABLED,
  935. fIsNt4Dc
  936. );
  937. NetpLog(( "NetpJoinDomain: status of setting machine password: 0x%lx\n", NetStatus ));
  938. }
  939. if ( NetStatus == NERR_Success )
  940. {
  941. AccountCreated = TRUE;
  942. }
  943. //
  944. // If this is not an explicit OU case, we haven't yet set DnsHostName and SPN.
  945. // Do it here.
  946. //
  947. // ISSUE: The original idea was to use the machine credentials (account=SamAccountName,
  948. // password=MachinePassword) since we may not have user credentials at this point (for
  949. // unsecure join). However problems with Kerberos authentication while binding to the
  950. // DC with machine credentials do not currently allow this behavior. So for now we will
  951. // set SPN here only if we have user credentials.
  952. //
  953. if ( NetStatus == NERR_Success &&
  954. !FLAG_ON(fJoinOpts, NETSETUP_DEFER_SPN_SET) &&
  955. !fIsNt4Dc &&
  956. lpMachineAccountOU == NULL &&
  957. DnsHostName != NULL &&
  958. lpAccount != NULL && lpPassword != NULL ) {
  959. //
  960. // Use the machine credentials (account=SamAccountName, password=MachinePassword)
  961. // since we may not have user credentials at this point (for unsecure join).
  962. //
  963. NetStatus = NetpGetMachineAccountName( lpMachine, &SamAccountName );
  964. if ( NetStatus != NO_ERROR ) {
  965. goto Cleanup;
  966. }
  967. NetStatus = NetApiBufferAllocate(
  968. (wcslen(DomainName) + 1 + wcslen(SamAccountName) + 1) * sizeof(WCHAR),
  969. &MachineAccount );
  970. if ( NetStatus != NO_ERROR ) {
  971. goto Cleanup;
  972. }
  973. swprintf( MachineAccount, L"%ws\\%ws", DomainName, SamAccountName );
  974. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  975. NetStatus = NetpSetDnsHostNameAndSpn( DcInfo,
  976. lpAccount, // MachineAccount
  977. EncodedPassword.Buffer, // lpMachinePassword
  978. lpMachine,
  979. DnsHostName );
  980. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  981. NetpLog(( "NetpJoinDomain: status of setting DnsHostName and SPN: 0x%lx\n", NetStatus ));
  982. //
  983. // If the problem was that values were invalid,
  984. // return a distinctive error indicating where that happened
  985. //
  986. if ( NetStatus == ERROR_INVALID_PARAMETER ) {
  987. NetStatus = ERROR_DS_COULDNT_UPDATE_SPNS;
  988. }
  989. //
  990. // On success, indicate that we have set SPN
  991. //
  992. if ( NetStatus == NO_ERROR ) {
  993. SpnSet = TRUE;
  994. }
  995. }
  996. }
  997. //
  998. // Read our old primary domain info in case we have to restore
  999. //
  1000. if ( NetStatus == NERR_Success ) {
  1001. NetStatus = NetpGetLsaPrimaryDomain( NULL,
  1002. &pPolicyLocalPDI,
  1003. &pPolicyLocalDns,
  1004. &hLsa );
  1005. }
  1006. //
  1007. // Remember the current sevice states in case we have rollback on failure
  1008. //
  1009. if ( NetStatus == NERR_Success ) {
  1010. NetStatus = NetpQueryService( SERVICE_NETLOGON,
  1011. &OldNetlogonServiceStatus,
  1012. &OldNetlogonServiceConfig );
  1013. }
  1014. //
  1015. // Stop the Netlogon service if it's not alredy stopped
  1016. //
  1017. if ( NetStatus == NERR_Success &&
  1018. OldNetlogonServiceStatus.dwCurrentState != SERVICE_STOPPED ) {
  1019. NetStatus = NetpControlServices( NETSETUP_SVC_STOPPED,
  1020. NETSETUPP_SVC_NETLOGON );
  1021. if ( NetStatus == NERR_Success ) {
  1022. NetlogonStopped = TRUE;
  1023. }
  1024. }
  1025. //
  1026. // If we are already joined, clean up the AutoEnrol data
  1027. // (which is a list of GUID for DCs stored in registry).
  1028. // Note that this is temp code. The AutoEntrol itself
  1029. // should do the cleanup on service start. It should write
  1030. // the name of the domain the GUIDs are for and clean up
  1031. // if the domain name is different from the primary
  1032. // domain name. This is Windows Bug 668489.
  1033. // After this bug is fixed, all code using NetpUpdateAutoenrolConfig()
  1034. // should be removed.
  1035. //
  1036. if ( NetStatus == NERR_Success &&
  1037. IS_CLIENT_JOINED(pPolicyLocalPDI) ) {
  1038. NET_API_STATUS NetStatusTmp = NetpUpdateAutoenrolConfig( TRUE );
  1039. //
  1040. // Ignore failure
  1041. //
  1042. if ( NetStatusTmp == NERR_Success ) {
  1043. AutoenrolConfigUpdated = TRUE;
  1044. } else {
  1045. NetpLog(( "NetpJoinDomain: Failed to clean up AutoEnrol data: 0x%lx. Ignored.\n",
  1046. NetStatusTmp ));
  1047. }
  1048. }
  1049. //
  1050. // Set the primary domain info from the Dc to the client
  1051. //
  1052. if ( NetStatus == NERR_Success ) {
  1053. NetStatus = NetpSetLsaPrimaryDomain(pPolicyPDI->Name.Buffer,
  1054. pPolicyPDI->Sid,
  1055. pPolicyDns,
  1056. &hLsa);
  1057. NetpLog(( "NetpJoinDomain: status of setting LSA pri. domain: 0x%lx\n", NetStatus ));
  1058. if ( NetStatus == NERR_Success ) {
  1059. DomainInfoSet = TRUE;
  1060. }
  1061. }
  1062. //
  1063. // Then we adjust our local group memberships
  1064. //
  1065. if ( NetStatus == NERR_Success )
  1066. {
  1067. NetStatus = NetpManageLocalGroups( pPolicyPDI->Sid, NETSETUPP_CREATE );
  1068. NetpLog(( "NetpJoinDomain: status of managing local groups: 0x%lx\n", NetStatus ));
  1069. if ( NetStatus == NERR_Success )
  1070. {
  1071. GroupsSet = TRUE;
  1072. }
  1073. }
  1074. //
  1075. // The netlogon cache needs to be initialized
  1076. //
  1077. if ( NetStatus == NERR_Success )
  1078. {
  1079. NetStatus = NetpSetNetlogonDomainCache( DomainControllerName );
  1080. NetpLog(( "NetpJoinDomain: status of setting netlogon cache: 0x%lx\n", NetStatus ));
  1081. }
  1082. //
  1083. // Save off the name of the initial domain controller we contacted
  1084. // if we successfully joined the domain. Ignore failure.
  1085. //
  1086. if ( NetStatus == NERR_Success && DcInfo != NULL ) {
  1087. NET_API_STATUS TmpNetStatus = NetpStoreIntialDcRecord( DcInfo );
  1088. if ( TmpNetStatus != NERR_Success ) {
  1089. NetpLog(( "NetpJoinDomain: NON FATAL: failed to store the initial Dc record for '%ws': 0x%lx\n",
  1090. DomainControllerName,
  1091. TmpNetStatus ));
  1092. }
  1093. }
  1094. //
  1095. // Next, if the Dns domain name changed, we'll need to potentially update the
  1096. // computer name as well...
  1097. //
  1098. if ( NetStatus == NERR_Success ) {
  1099. //
  1100. // If we have a new name, set it if it's different from the old one
  1101. //
  1102. if ( pPolicyDns != NULL ) {
  1103. if ( pPolicyLocalDns == NULL ||
  1104. RtlCompareUnicodeString( &pPolicyLocalDns->DnsDomainName,
  1105. &pPolicyDns->DnsDomainName,
  1106. TRUE ) != 0 ) {
  1107. NetStatus = NetpSetDnsComputerNameAsRequired( (PWSTR)pPolicyDns->DnsDomainName.Buffer );
  1108. NetpLog(( "NetpJoinDomain: status of setting ComputerNamePhysicalDnsDomain to '%wZ': 0x%lx\n",
  1109. &pPolicyDns->DnsDomainName,
  1110. NetStatus ));
  1111. }
  1112. //
  1113. // If we don't have a new name (must be an NT4 domain/DC),
  1114. // clear the old name, if any.
  1115. //
  1116. // Note, if this is an NT5 domain but we simply don't have
  1117. // an NT5 DC at this time, netlogon will eventually discover
  1118. // an NT5 DC and netlogon will set the new name then.
  1119. //
  1120. } else if ( pPolicyLocalDns != NULL ) {
  1121. NetStatus = NetpSetDnsComputerNameAsRequired( L"\0" );
  1122. NetpLog(( "NetpJoinDomain: status of clearing ComputerNamePhysicalDnsDomain: 0x%lx\n",
  1123. NetStatus ));
  1124. }
  1125. }
  1126. //
  1127. // Then, the netlogon servic needs to be set to automatic
  1128. //
  1129. if ( NetStatus == NERR_Success &&
  1130. OldNetlogonServiceConfig->dwStartType != SERVICE_AUTO_START ) {
  1131. NetStatus = NetpControlServices( NETSETUP_SVC_ENABLED,
  1132. NETSETUPP_SVC_NETLOGON );
  1133. if ( NetStatus == NERR_Success ) {
  1134. NetlogonEnabled = TRUE;
  1135. } else {
  1136. NetpLog(( "NetpJoinDomain: status of enabling Netlogon: 0x%lx\n", NetStatus ));
  1137. }
  1138. }
  1139. //
  1140. // Start netlogon
  1141. //
  1142. if ( NetStatus == NERR_Success ) {
  1143. NetStatus = NetpControlServices( NETSETUP_SVC_STARTED,
  1144. NETSETUPP_SVC_NETLOGON );
  1145. if ( NetStatus == NERR_Success ) {
  1146. NetlogonStarted = TRUE;
  1147. }
  1148. }
  1149. //
  1150. // call w32time!W32TimeVerifyJoinConfig so that it can update
  1151. // its internal config to match the join state
  1152. //
  1153. if ( NetStatus == NERR_Success ) {
  1154. NetpUpdateW32timeConfig( "W32TimeVerifyJoinConfig" );
  1155. }
  1156. // -----------------------------------------------------------------
  1157. // the real work of netjoin is over, now do some misc. stuff
  1158. // if this fails it does not cause a rollback
  1159. // -----------------------------------------------------------------
  1160. //
  1161. // If we successfully added ourselves to a new domain while we were joined to the
  1162. // old, then we'll remove the old domains group membership. This is not a
  1163. // catastrophic failure. Note that we don't try and remove the machine account
  1164. // if we are joining the domain we are already joined to...
  1165. //
  1166. if ( (NetStatus == NERR_Success) &&
  1167. FLAG_ON( fJoinOpts, NETSETUP_DOMAIN_JOIN_IF_JOINED ) &&
  1168. (SavedState.PrimaryDomainInfo != NULL) &&
  1169. (SavedState.PrimaryDomainInfo->Sid != NULL) &&
  1170. (pPolicyPDI != NULL) &&
  1171. !RtlEqualSid( pPolicyPDI->Sid, SavedState.PrimaryDomainInfo->Sid ) &&
  1172. (pPolicyPDI->Name.Buffer != NULL) &&
  1173. (SavedState.PrimaryDomainInfo->Name.Buffer != NULL) &&
  1174. _wcsicmp( pPolicyPDI->Name.Buffer,
  1175. SavedState.PrimaryDomainInfo->Name.Buffer ) )
  1176. {
  1177. NetStatus = NetpManageLocalGroups( SavedState.PrimaryDomainInfo->Sid,
  1178. NETSETUPP_DELETE );
  1179. NetpLog(( "NetpJoinDomain: status of removing groups related to domain '%wZ' from local groups: 0x%lx\n",
  1180. &SavedState.PrimaryDomainInfo->Name, NetStatus ));
  1181. //
  1182. // Try and remove the old domain's computer account as well
  1183. //
  1184. if ( FLAG_ON( fJoinOpts, NETSETUP_ACCT_DELETE ) )
  1185. {
  1186. PWSTR OldDomainControllerName = NULL;
  1187. ULONG OldDomainControllerFlags = 0;
  1188. //
  1189. // Find a domain controller in the old domain
  1190. //
  1191. NetStatus = NetpDsGetDcName( NULL,
  1192. SavedState.PrimaryDomainInfo->Name.Buffer,
  1193. lpMachine, GetDcFlags,
  1194. &OldDomainControllerFlags,
  1195. &OldDomainControllerName, NULL );
  1196. if ( NetStatus == NERR_Success )
  1197. {
  1198. NetStatus = NetpManageMachineAccount( lpMachine, NULL,
  1199. OldDomainControllerName,
  1200. NULL, NETSETUPP_DELETE,
  1201. fJoinOpts, fIsNt4Dc );
  1202. NetApiBufferFree( OldDomainControllerName );
  1203. }
  1204. NetpLog(( "NetpJoinDomain: status of disabling account for '%ws' on old domain '%wZ': 0x%lx\n",
  1205. lpMachine,
  1206. &SavedState.PrimaryDomainInfo->Name,
  1207. NetStatus ));
  1208. }
  1209. //
  1210. // Nothing in here is considered fatal if it fails
  1211. //
  1212. NetStatus = NERR_Success;
  1213. }
  1214. // ============== ROLLBACK CODE ====================================
  1215. //
  1216. // If something failed, we'll have to rollback.
  1217. // Note that we ignore all error codes
  1218. //
  1219. if ( NetStatus != NERR_Success )
  1220. {
  1221. NetpLog(( "NetpJoinDomain: initiaing a rollback due to earlier errors\n"));
  1222. //
  1223. // Reset netlogon's start type
  1224. //
  1225. if ( NetlogonEnabled ) {
  1226. DWORD SvcOpts = 0;
  1227. if ( OldNetlogonServiceConfig->dwStartType == SERVICE_DISABLED ) {
  1228. SvcOpts = NETSETUP_SVC_DISABLED;
  1229. } else if ( OldNetlogonServiceConfig->dwStartType == SERVICE_DEMAND_START ) {
  1230. SvcOpts = NETSETUP_SVC_MANUAL;
  1231. }
  1232. if ( SvcOpts != 0 ) {
  1233. NetStatus2 = NetpControlServices( SvcOpts,
  1234. NETSETUPP_SVC_NETLOGON );
  1235. NetpLog(( "NetpJoinDomain: rollback: status of setting netlogon start type to 0x%lx: 0x%lx\n",
  1236. SvcOpts,
  1237. NetStatus2));
  1238. }
  1239. }
  1240. //
  1241. // Restart netlogon
  1242. //
  1243. // Note that we don't need to worry abbout the time service
  1244. // state since we update it as the last non-critical operation.
  1245. //
  1246. if ( NetlogonStopped ) {
  1247. DWORD SvcOpts = 0;
  1248. if ( OldNetlogonServiceStatus.dwCurrentState == SERVICE_RUNNING ) {
  1249. SvcOpts = NETSETUP_SVC_STARTED;
  1250. }
  1251. if ( SvcOpts != 0 ) {
  1252. NetStatus2 = NetpControlServices( SvcOpts,
  1253. NETSETUPP_SVC_NETLOGON );
  1254. NetpLog(( "NetpJoinDomain: rollback: status of starting netlogon: 0x%lx\n", NetStatus2));
  1255. }
  1256. }
  1257. if ( NetlogonStarted ) {
  1258. DWORD SvcOpts = 0;
  1259. if ( OldNetlogonServiceStatus.dwCurrentState == SERVICE_STOPPED ) {
  1260. SvcOpts = NETSETUP_SVC_STOPPED;
  1261. }
  1262. if ( SvcOpts != 0 ) {
  1263. NetStatus2 = NetpControlServices( SvcOpts,
  1264. NETSETUPP_SVC_NETLOGON );
  1265. NetpLog(( "NetpJoinDomain: rollback: status of stopping netlogon: 0x%lx\n", NetStatus2));
  1266. }
  1267. }
  1268. //
  1269. // Take back what we told Netlogon about SPN setting
  1270. //
  1271. if ( SpnSet ) {
  1272. NetpAvoidNetlogonSpnSet( FALSE );
  1273. }
  1274. if ( GroupsSet )
  1275. {
  1276. NetStatus2 = NetpManageLocalGroups( pPolicyPDI->Sid,
  1277. NETSETUPP_DELETE );
  1278. NetpLog(( "NetpJoinDomain: rollback: local group management: 0x%lx\n", NetStatus2));
  1279. }
  1280. if ( DomainInfoSet )
  1281. {
  1282. //
  1283. // Set a NULL domain sid
  1284. //
  1285. NetStatus2 =
  1286. NetpSetLsaPrimaryDomain( pPolicyLocalPDI->Name.Buffer,
  1287. NULL, NULL, &hLsa );
  1288. NetpLog(( "NetpJoinDomain: rollback: status of setting NULL domain sid: 0x%lx\n", NetStatus2));
  1289. }
  1290. if ( AccountCreated &&
  1291. FLAG_ON( fJoinOpts, NETSETUP_ACCT_CREATE ) )
  1292. {
  1293. if ( lpMachineAccountOU )
  1294. {
  1295. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  1296. NetStatus2 = NetpDeleteComputerObjectInOU(
  1297. DomainControllerName, lpMachineAccountOU,
  1298. lpMachine, lpAccount, EncodedPassword.Buffer );
  1299. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  1300. NetpLog(( "NetpJoinDomain: rollback: status of deleting the computer account from OU: 0x%lx\n", NetStatus2));
  1301. }
  1302. else
  1303. {
  1304. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  1305. NetStatus2 = NetpManageMachineAccount(
  1306. lpMachine, NULL, DomainControllerName,
  1307. EncodedPassword.Buffer, NETSETUPP_DELETE, 0, fIsNt4Dc );
  1308. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  1309. NetpLog(( "NetpJoinDomain: rollback: status of deleting computer account: 0x%lx\n", NetStatus2));
  1310. }
  1311. }
  1312. if ( SecretCreated )
  1313. {
  1314. if ( SavedState.MachineSecret )
  1315. {
  1316. NetStatus2 = NetpHandleJoinedStateInfo( &SavedState,
  1317. FALSE, &hLsa );
  1318. NetpLog(( "NetpJoinDomain: rollback: status of restoring secret: 0x%lx\n", NetStatus2));
  1319. }
  1320. else
  1321. {
  1322. NetStatus2 = NetpManageMachineSecret( lpMachine, NULL,
  1323. NETSETUPP_DELETE, FALSE, &hLsa );
  1324. NetpLog(( "NetpJoinDomain: rollback: status of deleting secret: 0x%lx\n", NetStatus2));
  1325. }
  1326. }
  1327. //
  1328. // Reset AutoEnrol data
  1329. //
  1330. if ( AutoenrolConfigUpdated ) {
  1331. NetStatus2 = NetpUpdateAutoenrolConfig( FALSE );
  1332. if ( NetStatus2 != NERR_Success ) {
  1333. NetpLog(( "NetpJoinDomain: rollback: failed to reset AutoEnrol data: 0x%lx\n", NetStatus2));
  1334. }
  1335. }
  1336. }
  1337. // =================================================================
  1338. Cleanup:
  1339. if ( pPolicyPDI != NULL ) {
  1340. LsaFreeMemory( pPolicyPDI );
  1341. }
  1342. if ( pPolicyLocalPDI != NULL ) {
  1343. LsaFreeMemory( pPolicyLocalPDI );
  1344. }
  1345. if ( pPolicyDns != NULL ) {
  1346. LsaFreeMemory( pPolicyDns );
  1347. }
  1348. if ( pPolicyLocalDns != NULL ) {
  1349. LsaFreeMemory( pPolicyLocalDns );
  1350. }
  1351. if ( hLsa != NULL )
  1352. {
  1353. LsaClose( hLsa );
  1354. }
  1355. if ( hDC != NULL )
  1356. {
  1357. LsaClose( hDC );
  1358. }
  1359. //
  1360. // Now, we'll no longer need our session to our dc
  1361. //
  1362. if ( IpcConnect )
  1363. {
  1364. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  1365. NetStatus2 = NetpManageIPCConnect( DomainControllerName, lpAccount,
  1366. EncodedPassword.Buffer,
  1367. NETSETUPP_DISCONNECT_IPC );
  1368. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  1369. NetpLog(( "NetpJoinDomain: status of disconnecting from '%ws': 0x%lx\n", DomainControllerName, NetStatus2));
  1370. }
  1371. // Note: NetApiBufferFree checks for NULL
  1372. NetApiBufferFree( DcInfo );
  1373. NetApiBufferFree( DomainControllerName );
  1374. NetApiBufferFree( DomainName );
  1375. NetApiBufferFree( SamAccountName );
  1376. NetApiBufferFree( MachineAccount );
  1377. NetApiBufferFree( DnsHostName );
  1378. NetApiBufferFree( NetbiosDcInfo );
  1379. if ( OldNetlogonServiceConfig != NULL ) {
  1380. LocalFree( OldNetlogonServiceConfig );
  1381. }
  1382. //
  1383. // If the passed in machine password was decrypted,
  1384. // encrypt is back
  1385. //
  1386. if ( EncodedMachinePassword.Buffer != NULL ) {
  1387. RtlRunEncodeUnicodeString( &MachinePasswordSeed, &EncodedMachinePassword );
  1388. }
  1389. return( NetStatus );
  1390. }
  1391. NET_API_STATUS
  1392. NET_API_FUNCTION
  1393. NetpCrackDomainSpecifier(
  1394. IN LPWSTR DomainSpecifier,
  1395. OUT LPWSTR* DomainName,
  1396. OUT LPWSTR* DomainControllerName
  1397. )
  1398. /*++
  1399. Routine Description:
  1400. Parse DomainSpecifier and separate out DomainName / DomainControllerName.
  1401. Caller must free the out arguments using NetApiBufferFree.
  1402. Arguments:
  1403. lpDomainSpecifier -- Domain to join.
  1404. syntax of the parameter is:
  1405. domain-name[\preferred-domain-controller-name]
  1406. e.g.:
  1407. ntdev\ntdsdc01 or ntdev
  1408. DomainName -- domain name extracted from lpDomainSpecifier
  1409. DomainControllerName -- domain controller name extracted from lpDomainSpecifier
  1410. Returns:
  1411. NERR_Success on success, otherwise NET_API_STATUS code
  1412. --*/
  1413. {
  1414. NET_API_STATUS Status;
  1415. LPWSTR pwsz;
  1416. LPWSTR pwszSave;
  1417. LPWSTR pwszDomain = NULL;
  1418. LPWSTR pwszDC = NULL;
  1419. pwszSave = pwsz = wcschr( DomainSpecifier, L'\\' );
  1420. if ( pwsz != NULL )
  1421. {
  1422. //
  1423. // Check if the passed DC name is NULL
  1424. //
  1425. if ( *(pwsz+1) == L'\0' ) {
  1426. return ERROR_INVALID_PARAMETER;
  1427. }
  1428. *pwsz = L'\0';
  1429. }
  1430. Status = NetpDuplicateString(DomainSpecifier, -1, &pwszDomain);
  1431. if ( Status == NERR_Success )
  1432. {
  1433. if ( pwsz != NULL )
  1434. {
  1435. pwsz++;
  1436. Status = NetApiBufferAllocate(
  1437. ( wcslen( pwsz ) + 2 + 1 ) * sizeof( WCHAR ),
  1438. &pwszDC
  1439. );
  1440. if ( Status == NERR_Success )
  1441. {
  1442. wcscpy( pwszDC, L"\\\\" );
  1443. wcscat( pwszDC, pwsz );
  1444. }
  1445. else
  1446. {
  1447. NetApiBufferFree( pwszDomain );
  1448. pwszDomain = NULL;
  1449. }
  1450. }
  1451. }
  1452. if ( pwszSave != NULL )
  1453. {
  1454. *pwszSave = L'\\';
  1455. }
  1456. *DomainName = pwszDomain;
  1457. *DomainControllerName = pwszDC;
  1458. return( Status );
  1459. }
  1460. NET_API_STATUS
  1461. NET_API_FUNCTION
  1462. NetpManageMachineAccountWithSid(
  1463. IN LPWSTR lpMachine,
  1464. IN LPWSTR lpOldMachine,
  1465. IN LPWSTR lpDcName,
  1466. IN LPWSTR lpPassword,
  1467. IN PSID DomainSid,
  1468. IN ULONG fControl,
  1469. IN ULONG AccountOptions,
  1470. IN BOOL fIsNt4Dc
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. Manages the creation/deletion, and manipulation of the machine account
  1475. Arguments:
  1476. lpMachine -- Name of the current machine /
  1477. name of the new machine for rename
  1478. lpOldMachine -- Old machine name for rename
  1479. lpDcName -- Name of a DC in the domain
  1480. lpPassword -- Password to use for machine object. If NULL, use the default.
  1481. DomainSid -- Sid for the domain holding the user account
  1482. fControl -- Whether to create/delete/rename
  1483. AccountOptions -- Options to determine the particular behavior of the account creation
  1484. fIsNt4Dc -- TRUE if the DC is NT4 or earlier
  1485. Returns:
  1486. NERR_Success -- Success
  1487. ERROR_INVALID_PASSWORD -- The machine account could not have a random password set
  1488. on it, so it must resort to using the default password
  1489. --*/
  1490. {
  1491. NET_API_STATUS NetStatus = NERR_Success;
  1492. LPWSTR lpMachAcc = NULL, lpOldMachAcc = NULL;
  1493. USER_INFO_1 NetUI1, *CurrentUI1;
  1494. USER_INFO_0 NetUI0;
  1495. DWORD BadParam = 0;
  1496. //
  1497. // Build the machine account name
  1498. //
  1499. NetStatus = NetpGetMachineAccountName(lpMachine, &lpMachAcc);
  1500. if ( NetStatus == NERR_Success )
  1501. {
  1502. if ( fControl == NETSETUPP_RENAME)
  1503. {
  1504. NetStatus = NetpGetMachineAccountName(lpOldMachine, &lpOldMachAcc);
  1505. }
  1506. }
  1507. //
  1508. // Now, either create or delete it
  1509. //
  1510. if ( NetStatus == NERR_Success )
  1511. {
  1512. if ( fControl == NETSETUPP_DELETE )
  1513. {
  1514. NetStatus = NetpSetMachineAccountPasswordAndTypeEx(
  1515. lpDcName, DomainSid, lpMachAcc,
  1516. NULL, ACCOUNT_STATE_DISABLED, fIsNt4Dc );
  1517. NetpLog(( "NetpManageMachineAccountWithSid: status of disabling account '%ws' on '%ws': 0x%lx\n",
  1518. lpMachAcc, lpDcName, NetStatus ));
  1519. }
  1520. else if (fControl == NETSETUPP_CREATE )
  1521. {
  1522. RtlZeroMemory( &NetUI1, sizeof( NetUI1 ) );
  1523. //
  1524. // Initialize it..
  1525. //
  1526. NetUI1.usri1_name = lpMachAcc;
  1527. NetUI1.usri1_password = lpPassword;
  1528. NetUI1.usri1_flags = UF_WORKSTATION_TRUST_ACCOUNT | UF_SCRIPT;
  1529. NetUI1.usri1_priv = USER_PRIV_USER;
  1530. NetStatus = NetUserAdd( lpDcName, 1, (PBYTE)&NetUI1, &BadParam );
  1531. if ( NetStatus != NERR_Success )
  1532. {
  1533. NetpLog(( "NetpManageMachineAccountWithSid: NetUserAdd on '%ws' for '%ws' failed: 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1534. if ( NetStatus == NERR_PasswordTooShort )
  1535. {
  1536. //
  1537. // SAM did not accpet a long password, try LM20_PWLEN
  1538. //
  1539. // Please refer to comments in NetpSetMachineAccountPasswordAndTypeEx
  1540. // regarding the reasons why we weaken the passwords in
  1541. // this order.
  1542. //
  1543. lpPassword[LM20_PWLEN] = UNICODE_NULL;
  1544. NetStatus = NetUserAdd( lpDcName, 1, (PBYTE)&NetUI1,
  1545. &BadParam );
  1546. if ( NetStatus == NERR_PasswordTooShort )
  1547. {
  1548. NetpLog(( "NetpManageMachineAccountWithSid: NetUserAdd on '%ws' for '%ws' failed:2: 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1549. //
  1550. // SAM did not accpet a LM20_PWLEN password,
  1551. // try a shorter one
  1552. //
  1553. lpPassword[LM20_PWLEN/2] = UNICODE_NULL;
  1554. NetStatus = NetUserAdd( lpDcName, 1, (PBYTE)&NetUI1,
  1555. &BadParam );
  1556. if ( NetStatus == NERR_PasswordTooShort )
  1557. {
  1558. NetpLog(( "NetpManageMachineAccountWithSid: NetUserAdd on '%ws' for '%ws' failed:3: 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1559. //
  1560. // SAM did not accpet a short pwd, try default pwd
  1561. //
  1562. NetpGenerateDefaultPassword(lpMachAcc, lpPassword);
  1563. NetStatus = NetUserAdd( lpDcName, 1, (PBYTE)&NetUI1,
  1564. &BadParam );
  1565. }
  1566. }
  1567. if (NetStatus == NERR_Success)
  1568. {
  1569. NetpLog(( "NetpManageMachineAccountWithSid: successfully created computer account\n" ));
  1570. }
  1571. else
  1572. {
  1573. NetpLog(( "NetpManageMachineAccountWithSid: NetUserAdd on '%ws' for '%ws' failed:4: 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1574. }
  1575. }
  1576. //
  1577. // See if it exists and we just need to adjust the password
  1578. //
  1579. else if ( NetStatus == NERR_UserExists || NetStatus == ERROR_LOGON_FAILURE )
  1580. {
  1581. NetStatus = NetpSetMachineAccountPasswordAndTypeEx(
  1582. lpDcName,
  1583. DomainSid,
  1584. lpMachAcc,
  1585. lpPassword,
  1586. ACCOUNT_STATE_ENABLED,
  1587. fIsNt4Dc );
  1588. NetpLog(( "NetpManageMachineAccountWithSid: status of attempting to set password on '%ws' for '%ws': 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1589. }
  1590. }
  1591. } else if ( fControl == NETSETUPP_RENAME )
  1592. {
  1593. NetUI0.usri0_name = lpMachAcc;
  1594. NetStatus = NetUserSetInfo( lpDcName, lpOldMachAcc,
  1595. 0, (PBYTE)&NetUI0, NULL );
  1596. NetpLog(( "NetpManageMachineAccountWithSid: status of NetUserSetInfo on '%ws' for '%ws': 0x%lx\n", lpDcName, lpOldMachAcc, NetStatus ));
  1597. //
  1598. // Update the display name as well.
  1599. // Ignore error as this is not critical.
  1600. //
  1601. if ( NetStatus == NERR_Success ) {
  1602. NET_API_STATUS TmpNetStatus;
  1603. PUSER_INFO_10 usri10 = NULL;
  1604. //
  1605. // First get the current display name
  1606. //
  1607. TmpNetStatus = NetUserGetInfo( lpDcName, lpMachAcc,
  1608. 10, (PBYTE *)&usri10 );
  1609. if ( TmpNetStatus != NERR_Success ) {
  1610. NetpLog(( "NetpManageMachineAccountWithSid: failed to get display name (ignored) 0x%lx\n", TmpNetStatus ));
  1611. //
  1612. // If the display name exists and is
  1613. // different from the new one, update it
  1614. //
  1615. } else if ( usri10->usri10_full_name != NULL &&
  1616. _wcsicmp(usri10->usri10_full_name, lpMachAcc) != 0 ) {
  1617. USER_INFO_1011 usri1011;
  1618. usri1011.usri1011_full_name = lpMachAcc; // new name
  1619. TmpNetStatus = NetUserSetInfo( lpDcName, lpMachAcc,
  1620. 1011, (PBYTE)&usri1011, NULL );
  1621. if ( TmpNetStatus != NERR_Success ) {
  1622. NetpLog(( "NetpManageMachineAccountWithSid: failed to update display name (ignored) 0x%lx\n", TmpNetStatus ));
  1623. }
  1624. }
  1625. //
  1626. // Free the user info we got
  1627. //
  1628. if ( usri10 != NULL ) {
  1629. NetApiBufferFree( usri10 );
  1630. }
  1631. }
  1632. }
  1633. else if ( fControl == NETSETUPP_SET_PASSWORD )
  1634. {
  1635. NetStatus = NetpSetMachineAccountPasswordAndType( lpDcName, DomainSid,
  1636. lpMachAcc, lpPassword );
  1637. NetpLog(( "NetpManageMachineAccountWithSid: status of setting password on '%ws' for '%ws': 0x%lx\n", lpDcName, lpMachAcc, NetStatus ));
  1638. }
  1639. else
  1640. {
  1641. NetStatus = ERROR_INVALID_PARAMETER;
  1642. }
  1643. }
  1644. NetApiBufferFree( lpMachAcc );
  1645. NetApiBufferFree( lpOldMachAcc );
  1646. return( NetStatus );
  1647. }
  1648. NET_API_STATUS
  1649. NET_API_FUNCTION
  1650. NetpManageMachineAccount(
  1651. IN LPWSTR lpMachine,
  1652. IN LPWSTR lpOldMachine,
  1653. IN LPWSTR lpDcName,
  1654. IN LPWSTR lpPassword,
  1655. IN ULONG fControl,
  1656. IN ULONG AccountOptions,
  1657. IN BOOL fIsNt4Dc
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. Manages the creation/deletion, and manipulation of the machine account
  1662. Arguments:
  1663. lpMachine -- Name of the current machine /
  1664. name of the new machine for rename
  1665. lpOldMachine -- Old machine name for rename
  1666. lpDcName -- Name of a DC in the domain
  1667. lpPassword -- Password to use for machine object. If NULL, use the default.
  1668. fControl -- Whether to create/delete/rename
  1669. AccountOptions -- Options to determine the particular behavior of the account creation
  1670. fIsNt4Dc -- TRUE if the DC is NT4 or earlier
  1671. Returns:
  1672. NERR_Success -- Success
  1673. ERROR_INVALID_PASSWORD -- The machine account could not have a random password set
  1674. on it, so it must resort to using the default password
  1675. --*/
  1676. {
  1677. NET_API_STATUS NetStatus = NERR_Success;
  1678. PPOLICY_PRIMARY_DOMAIN_INFO pPolicy;
  1679. PPOLICY_DNS_DOMAIN_INFO pDns;
  1680. NetStatus = NetpGetLsaPrimaryDomain( lpDcName, &pPolicy, &pDns, NULL );
  1681. if ( NetStatus == NERR_Success )
  1682. {
  1683. NetStatus = NetpManageMachineAccountWithSid( lpMachine, lpOldMachine,
  1684. lpDcName, lpPassword,
  1685. pPolicy->Sid, fControl,
  1686. AccountOptions,
  1687. fIsNt4Dc );
  1688. LsaFreeMemory( pPolicy );
  1689. LsaFreeMemory( pDns );
  1690. }
  1691. return( NetStatus );
  1692. }
  1693. NET_API_STATUS
  1694. NET_API_FUNCTION
  1695. NetpUnJoinDomain(
  1696. IN PPOLICY_PRIMARY_DOMAIN_INFO pPolicyPDI,
  1697. IN LPWSTR lpAccount,
  1698. IN LPWSTR lpPassword,
  1699. IN DWORD fJoinOpts
  1700. )
  1701. {
  1702. NET_API_STATUS NetStatus = NERR_Success;
  1703. NET_JOIN_STATE JoinState = { 0 };
  1704. WCHAR szMachineNameBuf[MAX_COMPUTERNAME_LENGTH + 1];
  1705. LPWSTR szMachineName=szMachineNameBuf;
  1706. DWORD dwJoinAction=0;
  1707. POLICY_PRIMARY_DOMAIN_INFO PolicyPDI;
  1708. NT_PRODUCT_TYPE ProductType;
  1709. PolicyPDI = *pPolicyPDI;
  1710. PolicyPDI.Sid = NULL;
  1711. NetSetuppOpenLog();
  1712. NetpLog(("NetpUnJoinDomain: unjoin from '%wZ' using '%ws' creds, options: 0x%lx\n", &pPolicyPDI->Name, lpAccount, fJoinOpts));
  1713. NetpLogBuildInformation();
  1714. //
  1715. // Validate flags. If there is a flag set that we don't
  1716. // recognize and we are not asked to ignore it, the flags
  1717. // are invalid.
  1718. //
  1719. if ( (fJoinOpts & ~NETSETUP_VALID_UNJOIN_FLAGS) != 0 ) {
  1720. if ( (fJoinOpts & NETSETUP_IGNORE_UNSUPPORTED_FLAGS) != 0 ) {
  1721. NetpLog(( "NetpUnJoinDomain: Ignoring unrecognized flags: 0x%lx\n",
  1722. (fJoinOpts & ~NETSETUP_VALID_UNJOIN_FLAGS) ));
  1723. } else {
  1724. NetpLog(( "NetpUnJoinDomain: Flags are invalid: 0x%lx\n", fJoinOpts ));
  1725. NetStatus = ERROR_INVALID_FLAGS;
  1726. }
  1727. }
  1728. //
  1729. // check to see if the machine being joined is a DC
  1730. // if it is, we cannot let this join another domain/workgroup.
  1731. //
  1732. if ( NetStatus == NERR_Success ) {
  1733. if (!RtlGetNtProductType(&ProductType))
  1734. {
  1735. NetStatus = GetLastError();
  1736. }
  1737. else if (ProductType == NtProductLanManNt)
  1738. {
  1739. NetStatus = NERR_SetupDomainController;
  1740. NetpLog(( "NetpUnJoinDomain: the specified machine is a domain controller.\n"));
  1741. }
  1742. }
  1743. if (NetStatus == NERR_Success)
  1744. {
  1745. //
  1746. // get the computer name
  1747. //
  1748. NetStatus = NetpGetComputerNameAllocIfReqd(
  1749. &szMachineName, MAX_COMPUTERNAME_LENGTH+1);
  1750. NetpLog(( "NetpUnJoinDomain: status of getting computer name: 0x%lx\n", NetStatus ));
  1751. if (NetStatus == NERR_Success)
  1752. {
  1753. dwJoinAction =
  1754. NJA_SetNetlogonState |
  1755. NJA_SetTimeSvcUnjoin |
  1756. NJA_SetAutoenrolSvcUnjoin |
  1757. NJA_SetPolicyDomainInfo |
  1758. NJA_RemoveFromLocalGroups |
  1759. NJA_DeleteMachinePassword |
  1760. NJA_RemoveDnsRegistrations |
  1761. NJA_RollbackOnFailure;
  1762. if ( FLAG_ON( fJoinOpts, NETSETUP_ACCT_DELETE ) )
  1763. {
  1764. dwJoinAction |= NJA_DeleteAccount;
  1765. }
  1766. JoinState.szDomainName = pPolicyPDI->Name.Buffer;
  1767. JoinState.pPolicyPDI = &PolicyPDI;
  1768. JoinState.uiNetlogonStartType = NETSETUP_SVC_MANUAL;
  1769. JoinState.uiNetlogonState = NETSETUP_SVC_STOPPED;
  1770. NetStatus = NetpApplyJoinState(&JoinState, dwJoinAction,
  1771. szMachineName,
  1772. lpAccount, lpPassword, NULL);
  1773. }
  1774. }
  1775. NetpLog(( "NetpUnJoinDomain: status: 0x%lx\n", NetStatus));
  1776. NetSetuppCloseLog();
  1777. if (szMachineName != szMachineNameBuf)
  1778. {
  1779. NetApiBufferFree(szMachineName);
  1780. }
  1781. return NetStatus;
  1782. }
  1783. NET_API_STATUS
  1784. NET_API_FUNCTION
  1785. NetpControlServices(
  1786. IN DWORD SvcOpts,
  1787. IN DWORD Services
  1788. )
  1789. /*++
  1790. Routine Description:
  1791. Controls the state of the netlogon service
  1792. Arguments:
  1793. SvcOpts -- What to do to the service, such as start/stop or
  1794. enable/disable
  1795. Services -- Which services to control
  1796. Returns:
  1797. NERR_Success -- Success
  1798. --*/
  1799. {
  1800. NET_API_STATUS NetStatus = NERR_Success;
  1801. SC_HANDLE hScMgr=NULL, hSvc=NULL;
  1802. DWORD i, OpenMode=0;
  1803. PWSTR ppwszServices[] = {
  1804. SERVICE_NETLOGON
  1805. };
  1806. //
  1807. // Open the service control manager
  1808. //
  1809. hScMgr = OpenSCManager( NULL,
  1810. SERVICES_ACTIVE_DATABASE,
  1811. GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE );
  1812. if ( hScMgr == NULL )
  1813. {
  1814. NetStatus = GetLastError();
  1815. NetpLog(( "NetpControlServices: open SCManager failed: 0x%lx\n", NetStatus ));
  1816. }
  1817. else
  1818. {
  1819. i = 0;
  1820. while ( Services != 0 )
  1821. {
  1822. if ( FLAG_ON( Services, 0x00000001 ) )
  1823. {
  1824. if ( i > sizeof( ppwszServices ) / sizeof( PWSTR ) )
  1825. {
  1826. NetStatus = ERROR_INVALID_PARAMETER;
  1827. ASSERT( FALSE && "Invalid Service" );
  1828. break;
  1829. }
  1830. OpenMode = 0;
  1831. //
  1832. // Set the open mode
  1833. //
  1834. if( FLAG_ON( SvcOpts, NETSETUP_SVC_STOPPED ) )
  1835. {
  1836. OpenMode = SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS |
  1837. SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG;
  1838. } else if( FLAG_ON( SvcOpts, NETSETUP_SVC_STARTED ) )
  1839. {
  1840. OpenMode = SERVICE_START;
  1841. }
  1842. if ( FLAG_ON( SvcOpts, NETSETUP_SVC_ENABLED |
  1843. NETSETUP_SVC_DISABLED |
  1844. NETSETUP_SVC_MANUAL ) )
  1845. {
  1846. OpenMode |= SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG;
  1847. }
  1848. if ( FLAG_ON( SvcOpts, NETSETUP_SVC_STOPPED ) )
  1849. {
  1850. NetStatus = NetpStopService( ppwszServices[ i ], hScMgr );
  1851. if ( NetStatus != NERR_Success )
  1852. {
  1853. break;
  1854. }
  1855. }
  1856. //
  1857. // Open the service
  1858. //
  1859. hSvc = OpenService( hScMgr, ppwszServices[i], OpenMode );
  1860. if ( hSvc == NULL )
  1861. {
  1862. NetStatus = GetLastError();
  1863. NetpLog(( "NetpControlServices: open service '%ws' failed: 0x%lx\n", ppwszServices[i], NetStatus ));
  1864. }
  1865. else
  1866. {
  1867. if ( FLAG_ON( SvcOpts, NETSETUP_SVC_ENABLED |
  1868. NETSETUP_SVC_DISABLED |
  1869. NETSETUP_SVC_MANUAL ) )
  1870. {
  1871. DWORD StartControl = 0;
  1872. if ( FLAG_ON( SvcOpts, NETSETUP_SVC_ENABLED ) )
  1873. {
  1874. StartControl = SERVICE_AUTO_START;
  1875. }
  1876. else if ( FLAG_ON( SvcOpts, NETSETUP_SVC_DISABLED ) )
  1877. {
  1878. StartControl = SERVICE_DISABLED;
  1879. }
  1880. else if ( FLAG_ON( SvcOpts, NETSETUP_SVC_MANUAL ) )
  1881. {
  1882. StartControl = SERVICE_DEMAND_START;
  1883. }
  1884. if ( ChangeServiceConfig( hSvc, SERVICE_NO_CHANGE,
  1885. StartControl,
  1886. SERVICE_NO_CHANGE,
  1887. NULL, NULL, 0, NULL, NULL, NULL,
  1888. NULL ) == FALSE )
  1889. {
  1890. NetStatus = GetLastError();
  1891. NetpLog(( "NetpControlServices: configuring service '%ws' [ 0x%lx ] failed: 0x%lx\n",
  1892. ppwszServices[i], StartControl, NetStatus ));
  1893. }
  1894. }
  1895. if ( FLAG_ON( SvcOpts, NETSETUP_SVC_STARTED ) )
  1896. {
  1897. //
  1898. // See about changing its state
  1899. //
  1900. if ( StartService( hSvc, 0, NULL ) == FALSE )
  1901. {
  1902. NetStatus = GetLastError();
  1903. if ( NetStatus == ERROR_SERVICE_ALREADY_RUNNING )
  1904. {
  1905. NetStatus = NERR_Success;
  1906. }
  1907. else
  1908. {
  1909. NetpLog(( "NetpControlServices: start service '%ws' failed: 0x%lx\n", ppwszServices[i], NetStatus ));
  1910. }
  1911. }
  1912. }
  1913. CloseServiceHandle( hSvc );
  1914. }
  1915. }
  1916. i++;
  1917. Services >>= 1;
  1918. }
  1919. CloseServiceHandle( hScMgr );
  1920. }
  1921. return(NetStatus);
  1922. }
  1923. NET_API_STATUS
  1924. NET_API_FUNCTION
  1925. NetpChangeMachineName(
  1926. IN LPWSTR lpCurrentMachine,
  1927. IN LPWSTR lpNewHostName,
  1928. IN LPWSTR lpDomain,
  1929. IN LPWSTR lpAccount,
  1930. IN LPWSTR lpPassword,
  1931. IN DWORD fOptions
  1932. )
  1933. /*++
  1934. Routine Description:
  1935. Handles the machine rename case
  1936. Arguments:
  1937. lpCurrentMachine -- The current Netbios machine name
  1938. lpNewHostName -- The new (untruncated) machine name (may be longer than 15 chars)
  1939. lpDomain -- Domain the machine is a member of
  1940. lpAccount -- Account to use for machine account manipulation
  1941. lpPassword -- Password to use for machine account manipulation.
  1942. The password has been encoded and the first WCHAR
  1943. of the password buffer is the seed
  1944. fOptions -- Whether to mess with the machine account or not
  1945. Returns:
  1946. NERR_Success -- Success
  1947. --*/
  1948. {
  1949. NET_API_STATUS NetStatus = NERR_Success;
  1950. PWSTR DomainControllerName = NULL;
  1951. ULONG DcFlags = 0;
  1952. ULONG cLen;
  1953. BOOLEAN IpcConnect = FALSE;
  1954. UCHAR Seed;
  1955. UNICODE_STRING EncodedPassword;
  1956. BOOL fIsOemCompatible=FALSE;
  1957. BOOL NameChanged = FALSE;
  1958. WCHAR lpNewMachine[MAX_COMPUTERNAME_LENGTH + 1];
  1959. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  1960. PPOLICY_PRIMARY_DOMAIN_INFO pPolicyLocalPDI = NULL;
  1961. PPOLICY_DNS_DOMAIN_INFO pPolicyLocalDns = NULL;
  1962. LPWSTR DnsHostName = NULL;
  1963. NT_PRODUCT_TYPE NtProductType;
  1964. if ( lpPassword )
  1965. {
  1966. if ( wcslen( lpPassword ) < 1 )
  1967. {
  1968. return( ERROR_INVALID_PARAMETER );
  1969. }
  1970. Seed = ( UCHAR )*lpPassword;
  1971. RtlInitUnicodeString( &EncodedPassword, lpPassword + 1 );
  1972. }
  1973. else
  1974. {
  1975. RtlZeroMemory( &EncodedPassword, sizeof( UNICODE_STRING ) );
  1976. Seed = 0;
  1977. }
  1978. NetSetuppOpenLog();
  1979. NetpLog(( "NetpChangeMachineName: from '%ws' to '%ws' using '%ws' [0x%lx]\n",
  1980. GetStrPtr(lpCurrentMachine),
  1981. GetStrPtr(lpNewHostName),
  1982. GetStrPtr(lpAccount), fOptions));
  1983. //
  1984. // Only do this if we have create/manage account specified
  1985. //
  1986. if ( FLAG_ON(fOptions, NETSETUP_ACCT_CREATE) )
  1987. {
  1988. //
  1989. // Find a DC in that domain
  1990. //
  1991. NetStatus = NetpDsGetDcName( NULL,
  1992. lpDomain,
  1993. lpCurrentMachine,
  1994. FLAG_ON( fOptions, NETSETUP_ACCT_CREATE ) ?
  1995. NETSETUPP_DSGETDC_FLAGS :
  1996. NETSETUP_DSGETDC_FLAGS_ACCOUNT_EXISTS,
  1997. &DcFlags,
  1998. &DomainControllerName,
  1999. &DcInfo );
  2000. //
  2001. // If this is a DC, ensure we are using it.
  2002. // This is done to avoid cases when we modify our computer
  2003. // object on some other downlevel DC which doesn't update
  2004. // the server object in the config container. Besides, we
  2005. // don't really know how this DC would behave itself after
  2006. // its computer object gets updated on incoming replication
  2007. // change from some other DC.
  2008. //
  2009. if ( NetStatus == NERR_Success &&
  2010. RtlGetNtProductType(&NtProductType) &&
  2011. NtProductType == NtProductLanManNt ) { // DC
  2012. //
  2013. // If we got Netbios name,
  2014. // compare it with the one we have
  2015. //
  2016. if ( (DcInfo->Flags & DS_DNS_DOMAIN_FLAG) == 0 ) {
  2017. if ( I_NetNameCompare(NULL,
  2018. lpCurrentMachine,
  2019. DcInfo->DomainControllerName+2, // skip '\\'
  2020. NAMETYPE_COMPUTER, 0) != 0 ) {
  2021. NetpLog(( "NetpChangeMachineName: Got other Netbios DC '%ws' than local machine '%ws'\n",
  2022. DcInfo->DomainControllerName+2,
  2023. lpCurrentMachine ));
  2024. NetStatus = ERROR_NO_SUCH_DOMAIN;
  2025. }
  2026. //
  2027. // Otherwise, get the local DNS host name and
  2028. // compare it with the one from DC locator
  2029. //
  2030. } else {
  2031. WCHAR LocalDnsHostName[DNS_MAX_NAME_BUFFER_LENGTH];
  2032. ULONG LocalDnsHostNameLen = DNS_MAX_NAME_BUFFER_LENGTH;
  2033. if ( GetComputerNameExW(ComputerNameDnsFullyQualified,
  2034. LocalDnsHostName,
  2035. &LocalDnsHostNameLen) ) {
  2036. if ( !DnsNameCompare_W(DcInfo->DomainControllerName+2,
  2037. LocalDnsHostName) ) {
  2038. NetpLog(( "NetpChangeMachineName: Got other DNS DC '%ws' than local machine '%ws'\n",
  2039. DcInfo->DomainControllerName+2,
  2040. LocalDnsHostName ));
  2041. NetStatus = ERROR_NO_SUCH_DOMAIN;
  2042. }
  2043. } else {
  2044. NetStatus = GetLastError();
  2045. NetpLog(( "NetpChangeMachineName: GetComputerNameExW failed 0x%lx\n", NetStatus ));
  2046. }
  2047. }
  2048. }
  2049. //
  2050. // Get the computer name from the host name (truncate as needed)
  2051. //
  2052. if ( NetStatus == NERR_Success ) {
  2053. ULONG Size = MAX_COMPUTERNAME_LENGTH + 1;
  2054. BOOL Result;
  2055. Result = DnsHostnameToComputerNameW( lpNewHostName,
  2056. lpNewMachine,
  2057. &Size );
  2058. if ( Result != TRUE ) {
  2059. NetStatus = GetLastError();
  2060. NetpLog(( "NetpChangeMachineName: DnsHostnameToComputerNameW failed: 0x%lx\n", NetStatus ));
  2061. }
  2062. }
  2063. if ( NetStatus == NERR_Success )
  2064. {
  2065. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  2066. NetStatus = NetpManageIPCConnect( DomainControllerName,
  2067. lpAccount, EncodedPassword.Buffer,
  2068. NETSETUPP_CONNECT_IPC );
  2069. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  2070. NetpLog(( "NetpChangeMachineName: status of connecting to dc '%ws': 0x%lx\n", DomainControllerName, NetStatus ));
  2071. if ( NetStatus == NERR_Success )
  2072. {
  2073. IpcConnect = TRUE;
  2074. //
  2075. // REVIEW kahrent 03-March-00
  2076. // See review comment above with the same date
  2077. //
  2078. //$ kumarp 02-June-1999
  2079. // the following requires admin access to the dc so that the
  2080. // right regkeys could be read to decide the default locale.
  2081. // We need to get a remoted API to get default locale
  2082. // on the dc.
  2083. //
  2084. // make sure that the machine name is OEM codepage compatible with
  2085. // the default codepage being used on the dc. We determine this
  2086. // by translating the machine name to oem string using the
  2087. // local code page and the dc code page and then binary comparing
  2088. // the resultant strings. if the strings are different, we
  2089. // will fail the rename.
  2090. //
  2091. // Note that this is not a limitation of join apis. netlogon uses
  2092. // oem translated netbios machine name internally. the translation
  2093. // is different if the code page on the dc and the local machine are
  2094. // not compatible. This causes lack of access to net resources.
  2095. //
  2096. /*
  2097. NetStatus = NetpVerifyStrOemCompatibleOnMachine(
  2098. DomainControllerName, lpNewMachine);
  2099. NetpLog(( "NetpChangeMachineName: status of verifying OEM compatibility of computer name: 0x%lx\n", NetStatus ));
  2100. */
  2101. }
  2102. }
  2103. if ( NetStatus == NERR_Success )
  2104. {
  2105. NetStatus = NetpManageMachineAccount( lpNewMachine, lpCurrentMachine,
  2106. DomainControllerName,
  2107. NULL, NETSETUPP_RENAME, 0,
  2108. TRUE ); // NT4 DC; but doesn't really matter for rename
  2109. if ( NetStatus == NERR_Success ) {
  2110. NameChanged = TRUE;
  2111. }
  2112. }
  2113. //
  2114. // Set DnsHostName and SPN attributes
  2115. //
  2116. // First get the local DNS domain name to be used
  2117. // in case primary DNS suffix defaults to DNS domain name.
  2118. //
  2119. if ( NetStatus == NERR_Success ) {
  2120. NetStatus = NetpGetLsaPrimaryDomain( NULL,
  2121. &pPolicyLocalPDI,
  2122. &pPolicyLocalDns,
  2123. NULL );
  2124. }
  2125. //
  2126. // Determine DnsHostName of this machine
  2127. //
  2128. if ( NetStatus == NERR_Success &&
  2129. (DcFlags & DS_DS_FLAG) != 0 &&
  2130. pPolicyLocalDns != NULL ) {
  2131. NetStatus = NetpGetDnsHostName( lpNewHostName,
  2132. &pPolicyLocalDns->DnsDomainName,
  2133. TRUE, // Use the GP value
  2134. &DnsHostName );
  2135. }
  2136. //
  2137. // Now set DnsHostName and SPNs.
  2138. //
  2139. // (Comments in NetpJoinDomain where we call
  2140. // NetpSetDnsHostNameAndSpn all aply here, too)
  2141. //
  2142. if ( NetStatus == NERR_Success &&
  2143. DnsHostName != NULL &&
  2144. lpAccount != NULL && lpPassword != NULL ) {
  2145. //
  2146. // Tell netlogon that it should avoid
  2147. // setting DnsHostName and SPN until the reboot
  2148. //
  2149. NetpAvoidNetlogonSpnSet( TRUE );
  2150. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  2151. NetStatus = NetpSetDnsHostNameAndSpn( DcInfo,
  2152. lpAccount,
  2153. EncodedPassword.Buffer,
  2154. lpNewMachine,
  2155. DnsHostName );
  2156. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  2157. NetpLog(( "NetpChangeMachineName: status of setting DnsHostName and SPN: 0x%lx\n", NetStatus ));
  2158. //
  2159. // If the problem was that values were invalid,
  2160. // return a distinctive error indicating where that happened
  2161. //
  2162. if ( NetStatus == ERROR_INVALID_PARAMETER ) {
  2163. NetStatus = ERROR_DS_COULDNT_UPDATE_SPNS;
  2164. }
  2165. //
  2166. // On error, take back what we told Netlogon
  2167. //
  2168. if ( NetStatus != NO_ERROR ) {
  2169. NetpAvoidNetlogonSpnSet( FALSE );
  2170. }
  2171. }
  2172. }
  2173. //
  2174. // Rollback on error to set DnsHostName and SPN
  2175. //
  2176. if ( NetStatus != NO_ERROR && NameChanged ) {
  2177. NET_API_STATUS NetStatusTmp = NetpManageMachineAccount(
  2178. lpCurrentMachine, lpNewMachine, // Names switched
  2179. DomainControllerName,
  2180. NULL, NETSETUPP_RENAME, 0,
  2181. TRUE ); // NT4 DC; but doesn't really matter for rename
  2182. if ( NetStatusTmp != NERR_Success ) {
  2183. NetpLog(( "NetpChangeMachineName: Failed to rollback the machine name 0x%lx\n", NetStatusTmp ));
  2184. } else {
  2185. NetpLog(( "NetpChangeMachineName: Rolled back the machine name successfully\n" ));
  2186. }
  2187. }
  2188. if ( IpcConnect )
  2189. {
  2190. RtlRunDecodeUnicodeString( Seed, &EncodedPassword );
  2191. NetpManageIPCConnect( DomainControllerName, lpAccount,
  2192. EncodedPassword.Buffer, NETSETUPP_DISCONNECT_IPC );
  2193. RtlRunEncodeUnicodeString( &Seed, &EncodedPassword );
  2194. }
  2195. //
  2196. // Free up memory
  2197. //
  2198. NetApiBufferFree( DomainControllerName );
  2199. NetApiBufferFree( DcInfo );
  2200. NetApiBufferFree( DnsHostName );
  2201. if ( pPolicyLocalPDI != NULL ) {
  2202. LsaFreeMemory( pPolicyLocalPDI );
  2203. }
  2204. if ( pPolicyLocalDns != NULL ) {
  2205. LsaFreeMemory( pPolicyLocalDns );
  2206. }
  2207. NetSetuppCloseLog( );
  2208. return( NetStatus );
  2209. }
  2210. NET_API_STATUS
  2211. NET_API_FUNCTION
  2212. NetpDsGetDcName(
  2213. IN LPWSTR ComputerName, OPTIONAL
  2214. IN LPWSTR DomainName,
  2215. IN LPWSTR MachineName, OPTIONAL
  2216. IN ULONG Flags,
  2217. OUT PULONG DcFlags,
  2218. OUT PWSTR *DcName,
  2219. OUT PDOMAIN_CONTROLLER_INFO *DcInfo OPTIONAL
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. Find a dc in the specified domain using the following steps:
  2224. - get the machine account name
  2225. - find a writable dc that has this machine account
  2226. - if we cannot find such dc, find any writable dc
  2227. Arguments:
  2228. ComputerName -- name of the remote server to process this function.
  2229. typically this is the name of the preferred dc.
  2230. DomainName -- Domain for which we want to find a dc
  2231. MachineName -- current machine name
  2232. Flags -- flags to be passed to DsGetDcName* functions
  2233. DcFlags -- flags returned by DsGetDcName* functions
  2234. DcName -- name of the DC found
  2235. DcInfo -- info about the DC found
  2236. Returns:
  2237. NERR_Success -- Success
  2238. --*/
  2239. {
  2240. NET_API_STATUS NetStatus = NERR_Success;
  2241. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  2242. WCHAR wszMachine[MAX_COMPUTERNAME_LENGTH + 2];
  2243. PWSTR pwszMachine = wszMachine;
  2244. ULONG Len;
  2245. NetpLog(( "NetpDsGetDcName: trying to find DC in domain '%ws', flags: 0x%lx\n", DomainName, Flags ));
  2246. //
  2247. // generate the machine account name
  2248. //
  2249. if ( MachineName == NULL )
  2250. {
  2251. // note: NetpGetComputerNameAllocIfReqd allocates 1 extra
  2252. // char for the $
  2253. NetStatus = NetpGetComputerNameAllocIfReqd(&pwszMachine,
  2254. MAX_COMPUTERNAME_LENGTH+1);
  2255. }
  2256. else
  2257. {
  2258. Len = wcslen( MachineName );
  2259. if ( Len > MAX_COMPUTERNAME_LENGTH )
  2260. {
  2261. NetStatus = NetApiBufferAllocate( ( Len + 2 ) * sizeof(WCHAR),
  2262. ( PBYTE * )&pwszMachine );
  2263. }
  2264. if ( NetStatus == NERR_Success )
  2265. {
  2266. wcscpy(pwszMachine, MachineName);
  2267. }
  2268. }
  2269. if ( NetStatus == NERR_Success )
  2270. {
  2271. wcscat(pwszMachine, L"$");
  2272. }
  2273. MachineName = pwszMachine;
  2274. //
  2275. // Now that we have the machine account name, see if we can
  2276. // find a dc that has this account
  2277. //
  2278. if ( NetStatus == NERR_Success )
  2279. {
  2280. NetStatus = DsGetDcNameWithAccountW( ComputerName, MachineName,
  2281. UF_WORKSTATION_TRUST_ACCOUNT |
  2282. UF_SERVER_TRUST_ACCOUNT,
  2283. DomainName,
  2284. NULL, NULL, Flags, &pDCInfo );
  2285. if ( NetStatus == ERROR_NO_SUCH_USER )
  2286. {
  2287. NetpLog(( "NetpDsGetDcName: failed to find a DC having account '%ws': 0x%lx\n",
  2288. MachineName, NetStatus ));
  2289. //
  2290. // we didnt find a dc with that account.
  2291. // try to find any writable dc in that domain
  2292. //
  2293. NetStatus = DsGetDcName( ComputerName, DomainName,
  2294. NULL, NULL, Flags, &pDCInfo );
  2295. }
  2296. //
  2297. // on success, set the out parameters
  2298. //
  2299. if ( NetStatus == NERR_Success )
  2300. {
  2301. *DcFlags = pDCInfo->Flags;
  2302. NetStatus = NetpDuplicateString(pDCInfo->DomainControllerName,
  2303. -1, DcName);
  2304. if ( DcInfo )
  2305. {
  2306. *DcInfo = pDCInfo;
  2307. }
  2308. else
  2309. {
  2310. NetApiBufferFree( pDCInfo );
  2311. }
  2312. }
  2313. }
  2314. if ( NetStatus == NERR_Success )
  2315. {
  2316. NetpLog(( "NetpDsGetDcName: found DC '%ws' in the specified domain\n",
  2317. *DcName));
  2318. }
  2319. else
  2320. {
  2321. NetpLog(( "NetpDsGetDcName: failed to find a DC in the specified domain: 0x%lx\n", NetStatus));
  2322. }
  2323. //
  2324. // Free any memory we may have allocated
  2325. //
  2326. if ( pwszMachine != wszMachine )
  2327. {
  2328. NetApiBufferFree( pwszMachine );
  2329. }
  2330. return( NetStatus );
  2331. }
  2332. NET_API_STATUS
  2333. NET_API_FUNCTION
  2334. NetpStopService(
  2335. IN LPWSTR Service,
  2336. IN SC_HANDLE SCManager
  2337. )
  2338. /*++
  2339. Routine Description:
  2340. Stops the specified service and all of its depenendencies
  2341. Arguments:
  2342. Service -- Name of the service to stop
  2343. SCManager -- Open handle to the Service Controller
  2344. Returns:
  2345. NERR_Success -- Success
  2346. --*/
  2347. {
  2348. NET_API_STATUS NetStatus = NERR_Success;
  2349. SERVICE_STATUS SvcStatus;
  2350. SC_HANDLE Svc;
  2351. LPENUM_SERVICE_STATUS DependentServices = NULL;
  2352. ULONG DependSvcSize = 0, DependSvcCount = 0, i;
  2353. ULONG LoopCount = 0;
  2354. //
  2355. // Open the service
  2356. //
  2357. Svc = OpenService( SCManager,
  2358. Service,
  2359. SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_QUERY_STATUS );
  2360. if ( Svc == NULL ) {
  2361. NetStatus = GetLastError();
  2362. NetpLog(( "Failed to open SCManager\n", NetStatus ));
  2363. } else {
  2364. //
  2365. // Enumerate all of the dependent services first
  2366. //
  2367. if(EnumDependentServices( Svc,
  2368. SERVICE_ACTIVE,
  2369. NULL,
  2370. 0,
  2371. &DependSvcSize,
  2372. &DependSvcCount ) == FALSE ) {
  2373. NetStatus = GetLastError();
  2374. }
  2375. if ( NetStatus == ERROR_MORE_DATA ) {
  2376. NetStatus = NetApiBufferAllocate( DependSvcSize,
  2377. (PBYTE *)&DependentServices );
  2378. if ( NetStatus == NERR_Success ) {
  2379. if( EnumDependentServices( Svc,
  2380. SERVICE_ACTIVE,
  2381. DependentServices,
  2382. DependSvcSize,
  2383. &DependSvcSize,
  2384. &DependSvcCount ) == FALSE ) {
  2385. NetStatus = GetLastError();
  2386. } else {
  2387. for ( i = 0; i < DependSvcCount; i++) {
  2388. NetStatus = NetpStopService( DependentServices[i].lpServiceName,
  2389. SCManager );
  2390. if ( NetStatus != NERR_Success ) {
  2391. break;
  2392. }
  2393. }
  2394. }
  2395. NetApiBufferFree( DependentServices );
  2396. }
  2397. }
  2398. if ( NetStatus == NERR_Success ) {
  2399. //
  2400. // Try in a loop for a max of 20 sec to stop the service
  2401. // special casing some netlogon condition
  2402. //
  2403. for ( LoopCount = 0; LoopCount < 20; LoopCount++ ) {
  2404. if ( ControlService( Svc,
  2405. SERVICE_CONTROL_STOP,
  2406. &SvcStatus ) == FALSE ) {
  2407. NetStatus = GetLastError();
  2408. //
  2409. // Special case ERROR_INVALID_SERVICE_CONTROL if
  2410. // we are stopping netlogon. This error means
  2411. // that netlogon is in the process of starting
  2412. // and hasn't yet registered with the service
  2413. // controller. This may happen, in particular,
  2414. // if we restarted netlogon on roll back on an
  2415. // error to unjoin (perhaps because the user creds
  2416. // supplied were not valid to delete the machine account).
  2417. // If the unjoin is now retried immediately (this time
  2418. // without asking to delete the account), we are stopping
  2419. // netlogon here that may not have started yet.
  2420. //
  2421. if ( NetStatus == ERROR_INVALID_SERVICE_CONTROL &&
  2422. _wcsicmp(Service, SERVICE_NETLOGON) == 0 ) {
  2423. //
  2424. // Just sleep a second and retry
  2425. //
  2426. Sleep( 1000 );
  2427. //
  2428. // It's not an error if the service wasn't running
  2429. //
  2430. } else if ( NetStatus == ERROR_SERVICE_NOT_ACTIVE ) {
  2431. NetStatus = ERROR_SUCCESS;
  2432. break;
  2433. } else {
  2434. NetpLog(( "Stop service '%ws' failed with 0x%lx\n",
  2435. Service, NetStatus ));
  2436. break;
  2437. }
  2438. } else {
  2439. NetStatus = ERROR_SUCCESS;
  2440. break;
  2441. }
  2442. }
  2443. if ( LoopCount == 20 ) {
  2444. NetpLog(( "NetpStopService: Failed to retry to stop service %ws 0x%lx\n",
  2445. Service, NetStatus ));
  2446. }
  2447. //
  2448. // Wait for max of 1 min for the service to stop
  2449. //
  2450. if ( NetStatus == ERROR_SUCCESS ) {
  2451. for ( LoopCount = 0; LoopCount < 60; LoopCount++ ) {
  2452. if( QueryServiceStatus( Svc, &SvcStatus ) == FALSE ) {
  2453. NetStatus = GetLastError();
  2454. }
  2455. if ( NetStatus != ERROR_SUCCESS ||
  2456. SvcStatus.dwCurrentState == SERVICE_STOPPED) {
  2457. break;
  2458. }
  2459. Sleep( 1000 );
  2460. }
  2461. if ( LoopCount == 60 ) {
  2462. NetpLog(( "NetpStopService: Failed to wait until service %ws stops 0x%lx\n",
  2463. Service, NetStatus ));
  2464. }
  2465. }
  2466. } else {
  2467. NetpLog(( "Failed to enumerate dependentServices for '%ws': 0x%lx\n",
  2468. Service, NetStatus ));
  2469. }
  2470. CloseServiceHandle( Svc );
  2471. }
  2472. return( NetStatus );
  2473. }
  2474. NET_API_STATUS
  2475. NET_API_FUNCTION
  2476. NetpValidateName(
  2477. IN LPWSTR lpMachine,
  2478. IN LPWSTR lpName,
  2479. IN LPWSTR lpAccount, OPTIONAL
  2480. IN LPWSTR lpPassword, OPTIONAL
  2481. IN NETSETUP_NAME_TYPE NameType
  2482. )
  2483. /*++
  2484. Routine Description:
  2485. Ensures that the given name is valid for a name of that type
  2486. Arguments:
  2487. lpMachine -- Name of the machine being run on
  2488. lpName -- Name to validate
  2489. NameType -- Type of the name to validate
  2490. Returns:
  2491. NERR_Success -- Name is valid
  2492. ERROR_INVALID_PARAMETER -- A bad parameter was given
  2493. NERR_InvalidComputer -- The name format given is bad
  2494. ERROR_DUP_NAME -- The name is invalid for this type
  2495. --*/
  2496. {
  2497. NET_API_STATUS NetStatus = NERR_Success, ReturnStatus;
  2498. PWSTR LocalComputerName = NULL;
  2499. ULONG ValidateNameType;
  2500. BOOLEAN NBNameFailed = FALSE;
  2501. BOOLEAN NonRfcDnsName = FALSE;
  2502. PSTR NameTypeString;
  2503. WCHAR szMachineNameBuf[MAX_COMPUTERNAME_LENGTH + 1];
  2504. LPWSTR szMachineName=szMachineNameBuf;
  2505. NetSetuppOpenLog();
  2506. NetpLog(( "NetpValidateName: checking to see if '%ws' is valid as type %d name\n", GetStrPtr(lpName), (UINT) NameType ));
  2507. if (lpName == NULL) {
  2508. NetpLog(( "NetpValidateName: invalid null name passed\n" ));
  2509. NetSetuppCloseLog( );
  2510. return ERROR_INVALID_PARAMETER;
  2511. }
  2512. //
  2513. // Name valid as a Netbios or DNS name
  2514. //
  2515. if ( NameType != NetSetupDnsMachine )
  2516. {
  2517. switch ( NameType )
  2518. {
  2519. case NetSetupMachine:
  2520. ValidateNameType = NAMETYPE_COMPUTER;
  2521. ReturnStatus = NERR_InvalidComputer;
  2522. NameTypeString = "machine";
  2523. break;
  2524. case NetSetupWorkgroup:
  2525. ValidateNameType = NAMETYPE_WORKGROUP;
  2526. ReturnStatus = NERR_InvalidWorkgroupName;
  2527. NameTypeString = "workgroup";
  2528. break;
  2529. case NetSetupDomain:
  2530. case NetSetupNonExistentDomain:
  2531. ValidateNameType = NAMETYPE_DOMAIN;
  2532. ReturnStatus = ERROR_INVALID_DOMAINNAME;
  2533. NameTypeString = "domain";
  2534. break;
  2535. default:
  2536. NetpLog(( "NetpValidateName: invalid name type %lu\n", NameType ));
  2537. NetSetuppCloseLog( );
  2538. return ERROR_INVALID_PARAMETER;
  2539. }
  2540. NetStatus = I_NetNameValidate( NULL, lpName, ValidateNameType,
  2541. LM2X_COMPATIBLE );
  2542. if ( NetStatus == NERR_Success &&
  2543. NameType == NetSetupMachine &&
  2544. wcslen( lpName ) > CNLEN )
  2545. {
  2546. NetStatus = NERR_InvalidComputer;
  2547. }
  2548. if ( NetStatus != NERR_Success )
  2549. {
  2550. NetpLog(( "NetpValidateName: '%ws' is not a valid NetBIOS %s name: 0x%lx\n", lpName, NameTypeString, NetStatus ));
  2551. //
  2552. // If we are checking for a domain name, we'll automaticly
  2553. // pass it on to the Dns name validation. This is because
  2554. // the name has to only be valid for one name type
  2555. //
  2556. NetStatus = ReturnStatus;
  2557. if ( NameType == NetSetupDomain ||
  2558. NameType == NetSetupNonExistentDomain )
  2559. {
  2560. NBNameFailed = TRUE;
  2561. NetStatus = NERR_Success;
  2562. }
  2563. }
  2564. }
  2565. if ( NetStatus == NERR_Success )
  2566. {
  2567. NetStatus = DnsValidateDnsName_W( lpName );
  2568. if ( NetStatus != NERR_Success )
  2569. {
  2570. switch ( NameType )
  2571. {
  2572. case NetSetupMachine:
  2573. case NetSetupWorkgroup:
  2574. NetStatus = NERR_Success;
  2575. break;
  2576. case NetSetupDomain:
  2577. case NetSetupNonExistentDomain:
  2578. /*
  2579. the following if stmt fixes bug #382695.
  2580. this bug was postponed therefore I am commenting out
  2581. the fix. Uncomment this after NT5 RTM
  2582. if (NetStatus == ERROR_INVALID_NAME)
  2583. {
  2584. NetStatus = ERROR_INVALID_DOMAINNAME;
  2585. }
  2586. */
  2587. break;
  2588. case NetSetupDnsMachine:
  2589. default:
  2590. break;
  2591. }
  2592. if ( NetStatus != NERR_Success )
  2593. {
  2594. NetpLog(( "NetpValidateName: '%ws' is not a valid Dns %s name: 0x%lx\n", lpName, NameType == NetSetupMachine ? "machine" : "domain", NetStatus ));
  2595. //
  2596. // If the the NetBIOS domain name validation succeeded but
  2597. // the Dns failed, consider it success.
  2598. //
  2599. if ( !NBNameFailed &&
  2600. ( NameType == NetSetupDomain ||
  2601. NameType == NetSetupNonExistentDomain ) )
  2602. {
  2603. NetStatus = NERR_Success;
  2604. }
  2605. if (NetStatus == DNS_ERROR_NON_RFC_NAME)
  2606. {
  2607. NonRfcDnsName = TRUE;
  2608. NetStatus = NERR_Success;
  2609. }
  2610. }
  2611. }
  2612. }
  2613. //
  2614. // Name unique from computer name
  2615. //
  2616. if ( NetStatus == NERR_Success && NameType == NetSetupWorkgroup )
  2617. {
  2618. if ( lpMachine == NULL )
  2619. {
  2620. NetStatus = NetpGetNewMachineName( &LocalComputerName );
  2621. if ( NetStatus == NERR_Success )
  2622. {
  2623. lpMachine = LocalComputerName;
  2624. }
  2625. }
  2626. if ( NetStatus == NERR_Success && lpMachine )
  2627. {
  2628. if ( _wcsicmp( lpName, lpMachine ) == 0 )
  2629. {
  2630. //
  2631. // Not legal
  2632. //
  2633. NetpLog(( "NetpValidateName: Workgroup same as computer name\n" ));
  2634. NetStatus = NERR_InvalidWorkgroupName;
  2635. }
  2636. else
  2637. {
  2638. NetStatus = NetpCheckNetBiosNameNotInUse( lpName, TRUE, FALSE );
  2639. NetpLog(( "NetpCheckNetBiosNameNotInUse for '%ws' [ Workgroup as MACHINE] returned 0x%lx\n",
  2640. lpName, NetStatus ));
  2641. //$ REVIEW kumarp 25-May-1999
  2642. // this is absolutely the wrong thing to do!!
  2643. // the caller has to decide whether to treat
  2644. // NERR_NetworkError as error or not. The code
  2645. // below hides a fatal error.
  2646. //
  2647. // Handle the wkgrp name during setup before
  2648. // networking is installed case.
  2649. //
  2650. if ( NetStatus == NERR_NetworkError )
  2651. {
  2652. NetStatus = NERR_Success;
  2653. }
  2654. }
  2655. }
  2656. }
  2657. //
  2658. // Name not in use as a netbios name
  2659. //
  2660. // Do this by adding the <lpName>[00] name as a Netbios unique name.
  2661. //
  2662. if ( NetStatus == NERR_Success &&
  2663. ( NameType == NetSetupMachine ||
  2664. NameType == NetSetupNonExistentDomain ) )
  2665. {
  2666. NetStatus = NetpCheckNetBiosNameNotInUse(
  2667. lpName, TRUE, (BOOLEAN) ( NameType == NetSetupMachine ));
  2668. if ((NetStatus == NERR_Success) &&
  2669. (NameType == NetSetupNonExistentDomain))
  2670. {
  2671. //
  2672. // make sure that the domain name is not the same as the local
  2673. // computer name
  2674. //
  2675. NetStatus = NetpGetComputerNameAllocIfReqd(
  2676. &szMachineName, MAX_COMPUTERNAME_LENGTH+1);
  2677. if (NetStatus == NERR_Success)
  2678. {
  2679. if (!_wcsicmp(szMachineName, lpName))
  2680. {
  2681. NetStatus = ERROR_DUP_NAME;
  2682. }
  2683. }
  2684. }
  2685. NetpLog(( "NetpCheckNetBiosNameNotInUse for '%ws' [MACHINE] returned 0x%lx\n",
  2686. lpName, NetStatus ));
  2687. }
  2688. //
  2689. // The idea behind the following block of code was to ensure
  2690. // that if this was to be a new domain name or a new machine name,
  2691. // we should check to see if the <lpName>[1C] name is registered or not.
  2692. // If the name is indeed registered, then this cannot be a valid
  2693. // machine/new domain name. Unfortunately, it doesn't quite work.
  2694. // The problem is that registering the name as a unique name causes
  2695. // problems down the road (WINS??) when we actually try to register
  2696. // this as a group name. So, the only thing we can do is registry
  2697. // it as a group name, but that doesn't do us any good.
  2698. // So, the net result is that this call is useless.
  2699. //
  2700. #if 0
  2701. if ( NetStatus == NERR_Success &&
  2702. ( NameType == NetSetupMachine ||
  2703. NameType == NetSetupNonExistentDomain ) )
  2704. {
  2705. NetStatus = NetpCheckNetBiosNameNotInUse( lpName, FALSE, FALSE );
  2706. NetpLog(( "NetpCheckNetBiosNameNotInUse for '%ws' [MACHINE/DOMAIN] returned 0x%lx\n",
  2707. lpName, NetStatus ));
  2708. }
  2709. #endif
  2710. //
  2711. // Next, the valid domain name
  2712. //
  2713. if ( NetStatus == NERR_Success && NameType == NetSetupDomain )
  2714. {
  2715. if ( _wcsicmp( lpName, L"BUILTIN" ) == 0 )
  2716. {
  2717. NetStatus = NERR_InvalidComputer;
  2718. }
  2719. else
  2720. {
  2721. NetStatus = NetpCheckDomainNameIsValid( lpName, lpAccount,
  2722. lpPassword, TRUE );
  2723. }
  2724. NetpLog(( "NetpCheckDomainNameIsValid [ Exists ] for '%ws' returned 0x%lx\n",
  2725. lpName, NetStatus ));
  2726. }
  2727. //
  2728. // Then, the invalid domain name
  2729. //
  2730. if ( NetStatus == NERR_Success && NameType == NetSetupNonExistentDomain )
  2731. {
  2732. if ( _wcsicmp( lpName, L"BUILTIN" ) == 0 )
  2733. {
  2734. NetStatus = NERR_InvalidComputer;
  2735. }
  2736. else
  2737. {
  2738. NetStatus = NetpCheckDomainNameIsValid( lpName, lpAccount,
  2739. lpPassword, FALSE );
  2740. }
  2741. NetpLog(( "NetpCheckDomainNameIsValid [ NON-Existant ]for '%ws' returned 0x%lx\n", lpName, NetStatus ));
  2742. //$ REVIEW kumarp 01-October-1999
  2743. //
  2744. // the if stmt below should be in an outer scope.
  2745. // currently it only affects the NetSetupNonExistentDomain case.
  2746. //
  2747. // we have verified that a domain with this name does not exist,
  2748. // restore the non-rfc error code if we got it earlier.
  2749. //
  2750. if ((NetStatus == NERR_Success) && NonRfcDnsName)
  2751. {
  2752. NetpLog(( "NetpValidateName: a domain with the specified non-RFC compliant name does not exist\n" ));
  2753. NetStatus = DNS_ERROR_NON_RFC_NAME;
  2754. }
  2755. }
  2756. if ( NetStatus == NERR_Success )
  2757. {
  2758. NetpLog(( "NetpValidateName: name '%ws' is valid for type %lu\n",
  2759. lpName, NameType ));
  2760. }
  2761. NetApiBufferFree( LocalComputerName );
  2762. if (szMachineName != szMachineNameBuf)
  2763. {
  2764. NetApiBufferFree(szMachineName);
  2765. }
  2766. NetSetuppCloseLog( );
  2767. return( NetStatus );
  2768. }
  2769. NET_API_STATUS
  2770. NET_API_FUNCTION
  2771. NetpGetJoinInformation(
  2772. IN LPWSTR lpServer OPTIONAL,
  2773. OUT LPWSTR *lpNameBuffer,
  2774. OUT PNETSETUP_JOIN_STATUS BufferType
  2775. )
  2776. /*++
  2777. Routine Description:
  2778. Gets information on the state of the workstation. The information
  2779. obtainable is whether the machine is joined to a workgroup or a domain,
  2780. and optionally, the name of that workgroup/domain.
  2781. Arguments:
  2782. lpServer -- ignored, set to NULL
  2783. lpNameBuffer -- Where the domain/workgroup name is returned.
  2784. memory allocated for this must be freed by the caller
  2785. by calling NetApiBufferFree
  2786. BufferType -- Whether the machine is joined to a workgroup or a domain
  2787. Returns:
  2788. NERR_Success -- Name is valid
  2789. ERROR_INVALID_PARAMETER -- A bad parameter was given
  2790. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  2791. --*/
  2792. {
  2793. NET_API_STATUS NetStatus = NERR_Success;
  2794. PPOLICY_PRIMARY_DOMAIN_INFO pPolicyPDI=NULL;
  2795. PPOLICY_DNS_DOMAIN_INFO pPolicyDns=NULL;
  2796. //
  2797. // Check the parameters
  2798. //
  2799. if ( ( lpNameBuffer == NULL ) || ( BufferType == NULL ) )
  2800. {
  2801. return( ERROR_INVALID_PARAMETER );
  2802. }
  2803. //
  2804. // Get the current domain information
  2805. //
  2806. NetStatus = NetpGetLsaPrimaryDomain( NULL, &pPolicyPDI,
  2807. &pPolicyDns, NULL );
  2808. if ( NetStatus == NERR_Success )
  2809. {
  2810. if ( pPolicyPDI->Sid == NULL )
  2811. {
  2812. if ( pPolicyPDI->Name.Length == 0 )
  2813. {
  2814. *BufferType = NetSetupUnjoined;
  2815. }
  2816. else
  2817. {
  2818. *BufferType = NetSetupWorkgroupName;
  2819. }
  2820. }
  2821. else
  2822. {
  2823. if ( pPolicyPDI->Name.Length == 0 )
  2824. {
  2825. *BufferType = NetSetupUnjoined;
  2826. }
  2827. else
  2828. {
  2829. *BufferType = NetSetupDomainName;
  2830. }
  2831. }
  2832. //
  2833. // Copy the string
  2834. //
  2835. if ( *BufferType == NetSetupUnjoined || pPolicyPDI->Name.Length == 0 )
  2836. {
  2837. *lpNameBuffer = NULL;
  2838. }
  2839. else
  2840. {
  2841. NetStatus = NetpDuplicateString(pPolicyPDI->Name.Buffer,
  2842. pPolicyPDI->Name.Length / sizeof(WCHAR),
  2843. lpNameBuffer);
  2844. }
  2845. LsaFreeMemory( pPolicyPDI );
  2846. LsaFreeMemory( pPolicyDns );
  2847. }
  2848. return( NetStatus );
  2849. }
  2850. NET_API_STATUS
  2851. NET_API_FUNCTION
  2852. NetpDoDomainJoin(
  2853. IN LPWSTR lpServer,
  2854. IN LPWSTR lpDomain,
  2855. IN LPWSTR lpMachineAccountOU, OPTIONAL
  2856. IN LPWSTR lpAccount,
  2857. IN LPWSTR lpPassword,
  2858. IN DWORD fOptions
  2859. )
  2860. /*++
  2861. Routine Description:
  2862. Joins the machine to the domain.
  2863. Arguments:
  2864. lpServer -- Name of the machine being run on
  2865. lpDomain -- Domain to join
  2866. lpMachineAccountOU -- Optional OU under which to create the machine account
  2867. lpAccount -- Account to use for join
  2868. lpPassword -- Password matching the account. The password has been encoded and the
  2869. first WCHAR of the password buffer is the seed
  2870. fOptions -- Options to use when joining the domain
  2871. Returns:
  2872. NERR_Success -- Success
  2873. ERROR_INVALID_PARAMETER -- A bad parameter was given
  2874. --*/
  2875. {
  2876. NET_API_STATUS NetStatus = NERR_Success;
  2877. LPTSTR ComputerName = NULL;
  2878. NetSetuppOpenLog();
  2879. NetpLog(( "NetpDoDomainJoin\n" ));
  2880. //
  2881. // Check the parameters we can
  2882. //
  2883. if (lpDomain == NULL )
  2884. {
  2885. NetStatus = ERROR_INVALID_PARAMETER;
  2886. }
  2887. #if(_WIN32_WINNT < 0x0500)
  2888. if ( lpMachineAccountOU != NULL )
  2889. {
  2890. NetStatus = ERROR_INVALID_PARAMETER;
  2891. }
  2892. #endif
  2893. //
  2894. // If we have no machine name, get the current name
  2895. //
  2896. if ((NetStatus == NERR_Success) && (lpServer == NULL))
  2897. {
  2898. NetStatus = NetpGetNewMachineName( &ComputerName );
  2899. if ( NetStatus == NERR_Success )
  2900. {
  2901. lpServer = ComputerName;
  2902. }
  2903. }
  2904. //
  2905. // Then, see about the join...
  2906. //
  2907. if ( NetStatus == NERR_Success )
  2908. {
  2909. if ( FLAG_ON( fOptions, NETSETUP_JOIN_DOMAIN ) )
  2910. {
  2911. //
  2912. // A domain join
  2913. //
  2914. NetStatus = NetpMachineValidToJoin( lpServer, TRUE );
  2915. if ((NERR_SetupAlreadyJoined == NetStatus) &&
  2916. (FLAG_ON(fOptions, NETSETUP_IGNORE_JOIN) ||
  2917. FLAG_ON(fOptions, NETSETUP_DOMAIN_JOIN_IF_JOINED)))
  2918. {
  2919. NetStatus = NERR_Success;
  2920. }
  2921. if ( NetStatus == NERR_Success )
  2922. {
  2923. NetStatus = NetpJoinDomain( lpServer, lpDomain, lpMachineAccountOU,
  2924. lpAccount, lpPassword, fOptions );
  2925. }
  2926. }
  2927. else
  2928. {
  2929. //
  2930. // Doing a workgroup join
  2931. //
  2932. NetStatus = NetpMachineValidToJoin( lpServer, FALSE );
  2933. if ( NetStatus == NERR_Success )
  2934. {
  2935. NetStatus = NetpJoinWorkgroup( lpServer, lpDomain );
  2936. }
  2937. }
  2938. }
  2939. NetApiBufferFree( ComputerName );
  2940. NetpLog(( "NetpDoDomainJoin: status: 0x%lx\n", NetStatus ));
  2941. NetSetuppCloseLog( );
  2942. return( NetStatus );
  2943. }
  2944. NET_API_STATUS
  2945. NET_API_FUNCTION
  2946. NetpSetMachineAccountPassword(
  2947. IN LPWSTR lpDc,
  2948. IN LPWSTR lpMachine,
  2949. IN LPWSTR lpPassword
  2950. )
  2951. /*++
  2952. Routine Description:
  2953. Sets the password on the machine account object
  2954. Arguments:
  2955. lpDcName -- Name of a DC in the domain
  2956. lpMachine -- Current name of the machine
  2957. lpPassword -- Password to use for machine object.
  2958. Returns:
  2959. NERR_Success -- Success
  2960. --*/
  2961. {
  2962. NET_API_STATUS NetStatus = NERR_Success;
  2963. LPWSTR lpMachAcc = NULL;
  2964. USER_INFO_1003 UserInfo1003 = {NULL};
  2965. //
  2966. // Build the machine account name
  2967. //
  2968. NetStatus = NetpGetMachineAccountName(lpMachine, &lpMachAcc);
  2969. //
  2970. // Now, either create or delete it
  2971. //
  2972. if ( NetStatus == NERR_Success )
  2973. {
  2974. UserInfo1003.usri1003_password = lpPassword;
  2975. NetStatus = NetUserSetInfo( lpDc,
  2976. lpMachAcc,
  2977. 1003,
  2978. (PBYTE) &UserInfo1003,
  2979. NULL );
  2980. if ( NetStatus != NERR_Success ) {
  2981. NetpLog(( "NetpSetMachineAccountPassword: NetUserSetInfo (level 1003) on '%ws' for '%ws' failed: 0x%lx\n",
  2982. lpDc, lpMachAcc, NetStatus ));
  2983. }
  2984. NetApiBufferFree( lpMachAcc );
  2985. }
  2986. return( NetStatus );
  2987. }
  2988. #define COMPUTERNAME_ROOT \
  2989. L"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
  2990. #define NEW_COMPUTERNAME_VALUE_NAME L"ComputerName"
  2991. NET_API_STATUS
  2992. NET_API_FUNCTION
  2993. NetpGetNewMachineName(
  2994. OUT PWSTR *NewMachineName
  2995. )
  2996. /*++
  2997. Routine Description:
  2998. This function reads the new Machine name parameter from the registry.
  2999. This values is what the computer name will be after the next reboot.
  3000. The returned buffer must be freed via NetApiBufferFree
  3001. Arguments:
  3002. NewMachineName -- Where the new machine name is returned
  3003. Returns:
  3004. NERR_Success -- Success
  3005. ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  3006. --*/
  3007. {
  3008. NET_API_STATUS NetStatus = NERR_Success;
  3009. HKEY ComputerNameRootKey;
  3010. ULONG Length = 0;
  3011. //
  3012. // Open the registry key
  3013. //
  3014. NetStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, COMPUTERNAME_ROOT,
  3015. 0, KEY_READ, &ComputerNameRootKey);
  3016. if ( NetStatus == ERROR_SUCCESS )
  3017. {
  3018. DWORD ValueType;
  3019. //
  3020. // Determine the size we need
  3021. //
  3022. NetStatus = RegQueryValueEx( ComputerNameRootKey,
  3023. NEW_COMPUTERNAME_VALUE_NAME,
  3024. 0, &ValueType, NULL, &Length );
  3025. if ( NetStatus == NERR_Success )
  3026. {
  3027. //
  3028. // Allocate the buffer and re-read it.
  3029. //
  3030. NetStatus = NetApiBufferAllocate( Length,
  3031. ( LPVOID * )NewMachineName );
  3032. if ( NetStatus == NERR_Success )
  3033. {
  3034. NetStatus = RegQueryValueEx( ComputerNameRootKey,
  3035. NEW_COMPUTERNAME_VALUE_NAME,
  3036. 0, &ValueType,
  3037. ( PBYTE )*NewMachineName, &Length );
  3038. }
  3039. }
  3040. RegCloseKey( ComputerNameRootKey );
  3041. }
  3042. return( NetStatus );
  3043. }
  3044. BOOL
  3045. IsNonEmptyUnicodeStr( IN UNICODE_STRING* ps )
  3046. {
  3047. return ps && ps->Length && ps->Buffer && *(ps->Buffer);
  3048. }
  3049. NET_API_STATUS
  3050. NET_API_FUNCTION
  3051. NetpValidateJoinStateAndActions(
  3052. IN NET_JOIN_STATE* pJoinState,
  3053. IN DWORD dwJoinAction
  3054. )
  3055. {
  3056. NET_API_STATUS NetStatus = NERR_Success;
  3057. GUID guidNull = { 0 };
  3058. /*
  3059. //
  3060. // validate POLICY_DNS_DOMAIN_INFO
  3061. //
  3062. if (dwJoinAction & NJA_SetPolicyDomainInfo)
  3063. {
  3064. if (!(IsNonEmptyUnicodeStr(&pJoinState->PolicyDDI.Name) &&
  3065. IsNonEmptyUnicodeStr(&pJoinState->PolicyDDI.DnsDomainName) &&
  3066. IsNonEmptyUnicodeStr(&pJoinState->PolicyDDI.DnsForestName) &&
  3067. memcmp((PVOID) &guidNull,
  3068. (PVOID) &pJoinState->PolicyDDI.DomainGuid,
  3069. sizeof(GUID)) &&
  3070. &pJoinState->PolicyDDI.Sid))
  3071. {
  3072. NetStatus = ERROR_INVALID_PARAMETER;
  3073. goto Cleanup;
  3074. }
  3075. }
  3076. */
  3077. if (dwJoinAction & NJA_SetNetlogonState)
  3078. {
  3079. if (!(((pJoinState->uiNetlogonStartType == NETSETUP_SVC_ENABLED) ||
  3080. (pJoinState->uiNetlogonStartType == NETSETUP_SVC_MANUAL)) &&
  3081. ((pJoinState->uiNetlogonState == NETSETUP_SVC_STOPPED) ||
  3082. (pJoinState->uiNetlogonState == NETSETUP_SVC_STARTED))))
  3083. {
  3084. NetStatus = ERROR_INVALID_PARAMETER;
  3085. goto Cleanup;
  3086. }
  3087. }
  3088. Cleanup:
  3089. return NetStatus;
  3090. }
  3091. NET_API_STATUS
  3092. NET_API_FUNCTION
  3093. NetpApplyJoinState(
  3094. IN NET_JOIN_STATE* pJoinState,
  3095. IN DWORD dwJoinAction,
  3096. IN LPWSTR szMachineName, OPTIONAL
  3097. IN LPWSTR szUser, OPTIONAL
  3098. IN LPWSTR szUserPassword, OPTIONAL
  3099. IN LPWSTR szPreferredDc OPTIONAL
  3100. )
  3101. {
  3102. NET_API_STATUS NetStatus = NERR_Success, NetStatus2;
  3103. NET_API_STATUS RetStatus = NERR_Success;
  3104. PWSTR szDcName = NULL;
  3105. PPOLICY_PRIMARY_DOMAIN_INFO pDcPolicyPDI = NULL, pLocalPolicyPDI = NULL;
  3106. PPOLICY_DNS_DOMAIN_INFO pDcPolicyDns = NULL, pLocalPolicyDns = NULL;
  3107. BOOL fIpcConnected = FALSE;
  3108. LSA_HANDLE hLsaLocal = NULL, hLsaDc = NULL;
  3109. WCHAR szMachinePasswordBuf[ PWLEN + 1];
  3110. ULONG ulIpcConnectFlags = NETSETUPP_CONNECT_IPC;
  3111. ULONG ulDcFlags=0, ulGetDcFlags = 0;
  3112. UNICODE_STRING sUserPassword;
  3113. UCHAR Seed;
  3114. BOOL fIsNt4Dc=FALSE;
  3115. BOOL fRandomPwdPreferred=TRUE;
  3116. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  3117. PWSTR szDnsDomainName=NULL;
  3118. NET_JOIN_STATE RollbackState = { 0 };
  3119. DWORD dwRollbackAction=0;
  3120. BOOL fIgnoreErrors=FALSE;
  3121. BOOL fSaveRollbackInfo=FALSE;
  3122. PWSTR szCurrentMachinePassword = NULL;
  3123. fIgnoreErrors = FLAG_ON ( dwJoinAction, NJA_IgnoreErrors );
  3124. fSaveRollbackInfo = FLAG_ON ( dwJoinAction, NJA_RollbackOnFailure );
  3125. NetpLog(( "NetpApplyJoinState: actions: 0x%lx\n", dwJoinAction ));
  3126. if ( szUserPassword )
  3127. {
  3128. if ( wcslen( szUserPassword ) < 1 )
  3129. {
  3130. return ERROR_INVALID_PARAMETER;
  3131. }
  3132. Seed = ( UCHAR )*szUserPassword;
  3133. RtlInitUnicodeString( &sUserPassword, szUserPassword + 1 );
  3134. }
  3135. else
  3136. {
  3137. RtlZeroMemory( &sUserPassword, sizeof( UNICODE_STRING ) );
  3138. Seed = 0;
  3139. }
  3140. NetStatus = NetpValidateJoinStateAndActions(pJoinState, dwJoinAction);
  3141. if ( NetStatus != NERR_Success )
  3142. {
  3143. return NetStatus;
  3144. }
  3145. //
  3146. // connect to the DC only if required by at least on action
  3147. //
  3148. if ( FLAG_ON( dwJoinAction, NJA_NeedDc ) )
  3149. {
  3150. ulGetDcFlags = FLAG_ON( dwJoinAction, NJA_CreateAccount ) ?
  3151. NETSETUPP_DSGETDC_FLAGS : NETSETUP_DSGETDC_FLAGS_ACCOUNT_EXISTS;
  3152. //
  3153. // Find a DC in the domain using these steps:
  3154. // - find a writable dc that has this machine account
  3155. // - if we cannot find such dc, find any writable dc
  3156. //
  3157. NetStatus = NetpDsGetDcName( szPreferredDc,
  3158. (LPWSTR) pJoinState->szDomainName,
  3159. szMachineName, ulGetDcFlags,
  3160. &ulDcFlags, &szDcName, &pDcInfo );
  3161. //
  3162. // First establish connection with the dc we found
  3163. //
  3164. if ( NetStatus == NERR_Success )
  3165. {
  3166. fIsNt4Dc = !FLAG_ON( ulDcFlags, DS_DS_FLAG);
  3167. if ( !FLAG_ON( dwJoinAction, NJA_CreateAccount ) )
  3168. {
  3169. ulIpcConnectFlags |= NETSETUPP_NULL_SESSION_IPC;
  3170. }
  3171. RtlRunDecodeUnicodeString( Seed, &sUserPassword );
  3172. NetStatus = NetpManageIPCConnect( szDcName,
  3173. szUser, sUserPassword.Buffer,
  3174. ulIpcConnectFlags );
  3175. RtlRunEncodeUnicodeString( &Seed, &sUserPassword );
  3176. if ( NetStatus == NERR_Success )
  3177. {
  3178. fIpcConnected = TRUE;
  3179. }
  3180. NetpLog(( "NetpApplyJoinState: status of connecting to dc '%ws': 0x%lx\n", szDcName, NetStatus ));
  3181. }
  3182. }
  3183. if (NetStatus != NERR_Success)
  3184. {
  3185. RetStatus = NetStatus;
  3186. }
  3187. //
  3188. // stop netlogon service if specified
  3189. //
  3190. if ( FLAG_ON ( dwJoinAction, NJA_SetNetlogonState ) &&
  3191. ( pJoinState->uiNetlogonState == NETSETUP_SVC_STOPPED ) &&
  3192. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3193. {
  3194. NetStatus = NetpControlServices( pJoinState->uiNetlogonStartType |
  3195. NETSETUP_SVC_STOPPED,
  3196. NETSETUPP_SVC_NETLOGON );
  3197. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3198. {
  3199. RollbackState.uiNetlogonState = NETSETUP_SVC_STARTED;
  3200. RollbackState.uiNetlogonStartType = NETSETUP_SVC_ENABLED;
  3201. dwRollbackAction |= NJA_SetNetlogonState;
  3202. }
  3203. NetpLog(( "NetpApplyJoinState: status of stopping and setting start type of Netlogon to %ld: 0x%lx\n", pJoinState->uiNetlogonStartType, NetStatus ));
  3204. }
  3205. if (NetStatus != NERR_Success)
  3206. {
  3207. RetStatus = NetStatus;
  3208. }
  3209. //
  3210. // config w32time service if specified
  3211. //
  3212. if ( FLAG_ON ( dwJoinAction, NJA_SetTimeSvcJoin ) &&
  3213. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3214. {
  3215. NetStatus = NetpUpdateW32timeConfig( "W32TimeVerifyJoinConfig" );
  3216. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3217. {
  3218. dwRollbackAction |= NJA_SetTimeSvcUnjoin;
  3219. }
  3220. }
  3221. if (NetStatus != NERR_Success)
  3222. {
  3223. RetStatus = NetStatus;
  3224. }
  3225. //
  3226. // Remove DNS registrations.
  3227. // Do this before changing this machine identification
  3228. // locally and in the domain because DNS deregistration
  3229. // may be secure
  3230. //
  3231. if ( FLAG_ON ( dwJoinAction, NJA_RemoveDnsRegistrations ) &&
  3232. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3233. {
  3234. NetStatus2 = NetpUpdateDnsRegistrations( FALSE );
  3235. NetpLog(( "NetpApplyJoinState: NON FATAL: status of removing DNS registrations: 0x%lx\n", NetStatus2 ));
  3236. if (fSaveRollbackInfo && (NetStatus2 == NERR_Success))
  3237. {
  3238. dwRollbackAction |= NJA_AddDnsRegistrations;
  3239. }
  3240. }
  3241. if (fIgnoreErrors || (NetStatus == NERR_Success))
  3242. {
  3243. //
  3244. // read our old primary domain info
  3245. //
  3246. NetStatus = NetpGetLsaPrimaryDomain( NULL,
  3247. &pLocalPolicyPDI,
  3248. &pLocalPolicyDns,
  3249. &hLsaLocal );
  3250. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3251. {
  3252. RollbackState.pPolicyPDI = pLocalPolicyPDI;
  3253. RollbackState.pPolicyDDI = pLocalPolicyDns;
  3254. }
  3255. }
  3256. if (NetStatus != NERR_Success)
  3257. {
  3258. RetStatus = NetStatus;
  3259. }
  3260. if ( FLAG_ON ( dwJoinAction, NJA_GetPolicyDomainInfo ) && fIpcConnected &&
  3261. (fIgnoreErrors || (NetStatus == NERR_Success)))
  3262. {
  3263. //
  3264. // get the lsa domain info on the DC
  3265. //
  3266. NetStatus = NetpGetLsaPrimaryDomain(szDcName, &pDcPolicyPDI,
  3267. &pDcPolicyDns, &hLsaDc);
  3268. if (NetStatus == NERR_Success)
  3269. {
  3270. pJoinState->pPolicyPDI = pDcPolicyPDI;
  3271. pJoinState->pPolicyDDI = pDcPolicyDns;
  3272. }
  3273. }
  3274. if (NetStatus != NERR_Success)
  3275. {
  3276. RetStatus = NetStatus;
  3277. }
  3278. if ((fIgnoreErrors || (NetStatus == NERR_Success)) &&
  3279. pJoinState->pPolicyDDI &&
  3280. pJoinState->pPolicyDDI->DnsDomainName.Buffer)
  3281. {
  3282. //
  3283. // make a copy of of DnsDomainName in the form of sz
  3284. //
  3285. NetStatus = NetpDuplicateString(
  3286. pJoinState->pPolicyDDI->DnsDomainName.Buffer,
  3287. pJoinState->pPolicyDDI->DnsDomainName.Length / sizeof(WCHAR),
  3288. &szDnsDomainName);
  3289. }
  3290. if (NetStatus != NERR_Success)
  3291. {
  3292. RetStatus = NetStatus;
  3293. }
  3294. if ( FLAG_ON ( dwJoinAction, NJA_GenMachinePassword ) &&
  3295. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3296. {
  3297. fRandomPwdPreferred = FLAG_ON ( dwJoinAction, NJA_RandomPwdPreferred );
  3298. //
  3299. // Generate the password to use on the machine account.
  3300. // This can either be the default password
  3301. // (the 1st 14 characters of the machine name, lower cased),
  3302. // or a randomly generated password.
  3303. //
  3304. NetStatus = NetpGeneratePassword( szMachineName,
  3305. fRandomPwdPreferred,
  3306. szDcName, fIsNt4Dc,
  3307. szMachinePasswordBuf );
  3308. if (NetStatus == NERR_Success)
  3309. {
  3310. pJoinState->szMachinePassword = szMachinePasswordBuf;
  3311. }
  3312. }
  3313. if (NetStatus != NERR_Success)
  3314. {
  3315. RetStatus = NetStatus;
  3316. }
  3317. if (fSaveRollbackInfo && (NetStatus == NERR_Success) &&
  3318. FLAG_ON (dwJoinAction, (NJA_SetMachinePassword |
  3319. NJA_DeleteMachinePassword)))
  3320. {
  3321. NetStatus = NetpReadCurrentSecret( &szCurrentMachinePassword,
  3322. &hLsaLocal );
  3323. if (NetStatus == NERR_Success)
  3324. {
  3325. RollbackState.szMachinePassword = szCurrentMachinePassword;
  3326. }
  3327. else if (NetStatus == ERROR_FILE_NOT_FOUND)
  3328. {
  3329. NetpLog(( "NetpApplyJoinState: machine secret not found. join state seems to be inconsistent. this case is correctly handled by the code.\n" ));
  3330. dwRollbackAction |=
  3331. NJA_GenMachinePassword | NJA_RandomPwdPreferred;
  3332. NetStatus = NERR_Success;
  3333. }
  3334. }
  3335. if (NetStatus != NERR_Success)
  3336. {
  3337. RetStatus = NetStatus;
  3338. }
  3339. //
  3340. // set the local machine secret, create if not already present
  3341. //
  3342. if ( FLAG_ON ( dwJoinAction, NJA_SetMachinePassword ) &&
  3343. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3344. {
  3345. // this also opens the local LSA policy handle
  3346. NetStatus = NetpManageMachineSecret(
  3347. szMachineName,
  3348. (LPWSTR) pJoinState->szMachinePassword,
  3349. NETSETUPP_CREATE, FALSE, &hLsaLocal );
  3350. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3351. {
  3352. dwRollbackAction |= NJA_SetMachinePassword;
  3353. }
  3354. }
  3355. if (NetStatus != NERR_Success)
  3356. {
  3357. RetStatus = NetStatus;
  3358. }
  3359. //
  3360. // delete the local machine secret
  3361. //
  3362. if ( FLAG_ON ( dwJoinAction, NJA_DeleteMachinePassword ) &&
  3363. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3364. {
  3365. // this also opens the local LSA policy handle
  3366. NetStatus = NetpManageMachineSecret(
  3367. szMachineName,
  3368. (LPWSTR) pJoinState->szMachinePassword,
  3369. NETSETUPP_DELETE, FALSE, &hLsaLocal );
  3370. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3371. {
  3372. dwRollbackAction |= NJA_SetMachinePassword;
  3373. }
  3374. }
  3375. if (NetStatus != NERR_Success)
  3376. {
  3377. RetStatus = NetStatus;
  3378. }
  3379. //
  3380. // kahrent 10-09-99 (adding comment)
  3381. //
  3382. // After this point we will be doing changes on the DC.
  3383. // However, if we are not successful at this point, fail
  3384. // over and rollback all the changes we've done locally.
  3385. //
  3386. if ((NetStatus != NERR_Success) && !fIgnoreErrors)
  3387. {
  3388. goto Cleanup;
  3389. }
  3390. //
  3391. // create the machine account on the dc if specified
  3392. //
  3393. if ( FLAG_ON ( dwJoinAction, NJA_CreateAccount ) )
  3394. {
  3395. NetStatus = NetpManageMachineAccountWithSid(
  3396. szMachineName, NULL, szDcName,
  3397. (LPWSTR) pJoinState->szMachinePassword,
  3398. pJoinState->pPolicyPDI->Sid, NETSETUPP_CREATE, 0, fIsNt4Dc );
  3399. NetpLog(( "NetpApplyJoinState: status of creating account: 0x%lx\n", NetStatus ));
  3400. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3401. {
  3402. dwRollbackAction |= NJA_DeleteAccount;
  3403. }
  3404. }
  3405. else if ( FLAG_ON ( dwJoinAction, NJA_DeleteAccount ) )
  3406. {
  3407. //
  3408. // delete the machine account on the dc if specified
  3409. //
  3410. if (fIsNt4Dc)
  3411. {
  3412. NetpLog(( "NetpApplyJoinState: account not disabled since we are talking to NT4 dc\n" ));
  3413. }
  3414. else
  3415. {
  3416. NetStatus = NetpManageMachineAccountWithSid(
  3417. szMachineName, NULL, szDcName,
  3418. (LPWSTR) pJoinState->szMachinePassword,
  3419. pLocalPolicyPDI->Sid, NETSETUPP_DELETE, 0, fIsNt4Dc );
  3420. NetpLog(( "NetpApplyJoinState: status of disabling account: 0x%lx\n", NetStatus ));
  3421. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3422. {
  3423. dwRollbackAction |= NJA_CreateAccount;
  3424. }
  3425. }
  3426. }
  3427. if (NetStatus != NERR_Success)
  3428. {
  3429. RetStatus = NetStatus;
  3430. }
  3431. if ( FLAG_ON ( dwJoinAction, NJA_ValidateMachineAccount ) && fIpcConnected &&
  3432. (fIgnoreErrors || (NetStatus == NERR_Success)))
  3433. {
  3434. NetStatus = NetpValidateMachineAccount(
  3435. szDcName, (LPWSTR) pJoinState->szDomainName,
  3436. szMachineName, (LPWSTR) pJoinState->szMachinePassword );
  3437. NetpLog(( "NetpApplyJoinState: w9x: status of validating account: 0x%lx\n", NetStatus ));
  3438. }
  3439. if (NetStatus != NERR_Success)
  3440. {
  3441. RetStatus = NetStatus;
  3442. }
  3443. if ( FLAG_ON ( dwJoinAction, NJA_SetMachinePassword ) && fIpcConnected &&
  3444. (fIgnoreErrors || (NetStatus == NERR_Success)))
  3445. {
  3446. NetStatus = NetpSetMachineAccountPassword(
  3447. szDcName,
  3448. szMachineName,
  3449. (LPWSTR) pJoinState->szMachinePassword );
  3450. NetpLog(( "NetpApplyJoinState: status of setting machine password: 0x%lx\n", NetStatus ));
  3451. }
  3452. if (NetStatus != NERR_Success)
  3453. {
  3454. RetStatus = NetStatus;
  3455. }
  3456. if ( FLAG_ON ( dwJoinAction, NJA_UpdateNetlogonCache ) && fIpcConnected &&
  3457. (fIgnoreErrors || (NetStatus == NERR_Success)))
  3458. {
  3459. NetStatus = NetpSetNetlogonDomainCache( szDcName );
  3460. NetpLog(( "NetpApplyJoinState: status of setting netlogon cache: 0x%lx\n", NetStatus ));
  3461. }
  3462. if (NetStatus != NERR_Success)
  3463. {
  3464. RetStatus = NetStatus;
  3465. }
  3466. //
  3467. // Set the primary domain info from the Dc to the client
  3468. //
  3469. if ( FLAG_ON ( dwJoinAction, NJA_SetPolicyDomainInfo ) &&
  3470. pJoinState->pPolicyPDI &&
  3471. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3472. {
  3473. NetStatus = NetpSetLsaPrimaryDomain(pJoinState->pPolicyPDI->Name.Buffer,
  3474. pJoinState->pPolicyPDI->Sid,
  3475. pJoinState->pPolicyDDI,
  3476. &hLsaLocal);
  3477. NetpLog(( "NetpApplyJoinState: status of setting LSA pri. domain: 0x%lx\n", NetStatus ));
  3478. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3479. {
  3480. dwRollbackAction |= NJA_SetPolicyDomainInfo;
  3481. }
  3482. }
  3483. //
  3484. // Set the new DNS computer name, as needed
  3485. //
  3486. if ( FLAG_ON(dwJoinAction, NJA_SetPolicyDomainInfo) &&
  3487. (fIgnoreErrors || (NetStatus == NERR_Success)) ) {
  3488. //
  3489. // If we have a new name, set it if it's different from the old one
  3490. //
  3491. if ( pJoinState->pPolicyDDI != NULL ) {
  3492. if ( pLocalPolicyDns == NULL ||
  3493. RtlCompareUnicodeString( &pLocalPolicyDns->DnsDomainName,
  3494. &pJoinState->pPolicyDDI->DnsDomainName,
  3495. TRUE ) != 0 ) {
  3496. NetStatus = NetpSetDnsComputerNameAsRequired( pJoinState->pPolicyDDI->DnsDomainName.Buffer );
  3497. NetpLog(( "NetpApplyJoinState: status of setting ComputerNamePhysicalDnsDomain to '%wZ': 0x%lx\n",
  3498. &pJoinState->pPolicyDDI->DnsDomainName,
  3499. NetStatus ));
  3500. }
  3501. //
  3502. // If we don't have a new name (must be an NT4 domain/DC),
  3503. // clear the old name, if any.
  3504. //
  3505. // Note, if this is an NT5 domain but we simply don't have
  3506. // an NT5 DC at this time, netlogon will eventually discover
  3507. // an NT5 DC and netlogon will set the new name then.
  3508. //
  3509. } else if ( pLocalPolicyDns != NULL ) {
  3510. NetStatus = NetpSetDnsComputerNameAsRequired( L"\0" );
  3511. NetpLog(( "NetpApplyJoinState: status of clearing ComputerNamePhysicalDnsDomain: 0x%lx\n",
  3512. NetStatus ));
  3513. }
  3514. }
  3515. if (NetStatus != NERR_Success)
  3516. {
  3517. RetStatus = NetStatus;
  3518. }
  3519. //
  3520. // add to local group memberships
  3521. //
  3522. if ( FLAG_ON ( dwJoinAction, NJA_AddToLocalGroups ) &&
  3523. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3524. {
  3525. NetStatus = NetpManageLocalGroups( pJoinState->pPolicyPDI->Sid, NETSETUPP_CREATE );
  3526. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3527. {
  3528. dwRollbackAction |= NJA_RemoveFromLocalGroups;
  3529. }
  3530. NetpLog(( "NetpApplyJoinState: status of adding to local groups: 0x%lx\n", NetStatus ));
  3531. }
  3532. if (NetStatus != NERR_Success)
  3533. {
  3534. RetStatus = NetStatus;
  3535. }
  3536. //
  3537. // remove from our local group memberships
  3538. //
  3539. if ( FLAG_ON ( dwJoinAction, NJA_RemoveFromLocalGroups ) &&
  3540. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3541. {
  3542. NetStatus = NetpManageLocalGroups( pLocalPolicyPDI->Sid, NETSETUPP_DELETE );
  3543. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3544. {
  3545. dwRollbackAction |= NJA_AddToLocalGroups;
  3546. }
  3547. NetpLog(( "NetpApplyJoinState: status of removing from local groups: 0x%lx\n", NetStatus ));
  3548. }
  3549. if (NetStatus != NERR_Success)
  3550. {
  3551. RetStatus = NetStatus;
  3552. }
  3553. //
  3554. // start netlogon service if specified
  3555. //
  3556. if ( FLAG_ON ( dwJoinAction, NJA_SetNetlogonState ) &&
  3557. ( pJoinState->uiNetlogonState == NETSETUP_SVC_STARTED ) &&
  3558. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3559. {
  3560. NetStatus = NetpControlServices( pJoinState->uiNetlogonStartType |
  3561. NETSETUP_SVC_STARTED,
  3562. NETSETUPP_SVC_NETLOGON );
  3563. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3564. {
  3565. RollbackState.uiNetlogonState = NETSETUP_SVC_STOPPED;
  3566. RollbackState.uiNetlogonStartType = NETSETUP_SVC_MANUAL;
  3567. dwRollbackAction |= NJA_SetNetlogonState;
  3568. }
  3569. NetpLog(( "NetpApplyJoinState: status of starting and setting start type of Netlogon to %ld: 0x%lx\n", pJoinState->uiNetlogonStartType, NetStatus ));
  3570. }
  3571. if (NetStatus != NERR_Success)
  3572. {
  3573. RetStatus = NetStatus;
  3574. }
  3575. //
  3576. // config w32time service if specified
  3577. //
  3578. if ( FLAG_ON ( dwJoinAction, NJA_SetTimeSvcUnjoin ) &&
  3579. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3580. {
  3581. NetStatus = NetpUpdateW32timeConfig( "W32TimeVerifyUnjoinConfig" );
  3582. if (fSaveRollbackInfo && (NetStatus == NERR_Success))
  3583. {
  3584. dwRollbackAction |= NJA_SetTimeSvcJoin;
  3585. }
  3586. }
  3587. //
  3588. // Config AutoEnrol service if specified.
  3589. //
  3590. // On join, do this after enabling the account in
  3591. // the DS because Autoenrol needs the account
  3592. // enabled to have the DS access. Also, do this
  3593. // after deleting the local secret to ensure we
  3594. // are running as local admin.
  3595. //
  3596. if ( FLAG_ON ( dwJoinAction, NJA_SetAutoenrolSvcJoin ) &&
  3597. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3598. {
  3599. //
  3600. // Ignore the failure since it's not critical
  3601. // but remember if we need to do anything on rollback
  3602. //
  3603. NET_API_STATUS TmpNetStatus = NetpUpdateAutoenrolConfig( FALSE );
  3604. if (fSaveRollbackInfo && (TmpNetStatus == NERR_Success))
  3605. {
  3606. dwRollbackAction |= NJA_SetAutoenrolSvcUnjoin;
  3607. }
  3608. }
  3609. if ( FLAG_ON ( dwJoinAction, NJA_SetAutoenrolSvcUnjoin ) &&
  3610. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3611. {
  3612. //
  3613. // Ignore the failure since it's not critical
  3614. // but remember if we need to do anything on rollback
  3615. //
  3616. NET_API_STATUS TmpNetStatus = NetpUpdateAutoenrolConfig( TRUE );
  3617. if (fSaveRollbackInfo && (TmpNetStatus == NERR_Success))
  3618. {
  3619. dwRollbackAction |= NJA_SetAutoenrolSvcJoin;
  3620. }
  3621. }
  3622. if (NetStatus != NERR_Success)
  3623. {
  3624. RetStatus = NetStatus;
  3625. }
  3626. //
  3627. // Save off the name of the initial domain controller we contacted
  3628. // if we successfully joined the domain
  3629. //
  3630. if ( FLAG_ON ( dwJoinAction, NJA_RecordDcInfo ) && fIpcConnected &&
  3631. (fIgnoreErrors || (NetStatus == NERR_Success)))
  3632. {
  3633. //
  3634. // A failure here is NON-FATAL, so we ignore the error code
  3635. //
  3636. NetStatus2 = NetpStoreIntialDcRecord( pDcInfo );
  3637. if ( NetStatus2 != NERR_Success )
  3638. {
  3639. NetpLog(( "NetpApplyJoinState: NON FATAL: failed to store the initial Dc record for '%ws': 0x%lx\n", szDcName, NetStatus ));
  3640. }
  3641. }
  3642. if (NetStatus != NERR_Success)
  3643. {
  3644. RetStatus = NetStatus;
  3645. }
  3646. //
  3647. // Add DNS registrations.
  3648. // Do this after the machine account is set locally
  3649. // and in teh domain because DNS upodates may be secure.
  3650. //
  3651. if ( FLAG_ON ( dwJoinAction, NJA_AddDnsRegistrations ) &&
  3652. ( fIgnoreErrors || ( NetStatus == NERR_Success ) ) )
  3653. {
  3654. NetStatus2 = NetpUpdateDnsRegistrations( TRUE );
  3655. NetpLog(( "NetpApplyJoinState: NON FATAL: status of adding DNS registrations: 0x%lx\n", NetStatus2 ));
  3656. if (fSaveRollbackInfo && (NetStatus2 == NERR_Success))
  3657. {
  3658. dwRollbackAction |= NJA_RemoveDnsRegistrations;
  3659. }
  3660. }
  3661. Cleanup:
  3662. if (fSaveRollbackInfo && (NetStatus != NERR_Success))
  3663. {
  3664. // time to rollback. ignore all errors during rollback
  3665. NetpLog(( "NetpApplyJoinState: initiating a rollback due to earlier errors\n"));
  3666. dwRollbackAction |= NJA_IgnoreErrors;
  3667. NetStatus2 = NetpApplyJoinState(&RollbackState, dwRollbackAction,
  3668. szMachineName, szUser, szUserPassword,
  3669. szDcName ? szDcName : szPreferredDc);
  3670. }
  3671. LsaFreeMemory( pDcPolicyPDI );
  3672. LsaFreeMemory( pDcPolicyDns );
  3673. LsaFreeMemory( pLocalPolicyPDI );
  3674. LsaFreeMemory( pLocalPolicyDns );
  3675. if ( hLsaLocal != NULL )
  3676. {
  3677. LsaClose( hLsaLocal );
  3678. }
  3679. if ( hLsaDc != NULL )
  3680. {
  3681. LsaClose( hLsaDc );
  3682. }
  3683. //
  3684. // Now, we'll no longer need our session to our dc
  3685. //
  3686. if ( fIpcConnected )
  3687. {
  3688. RtlRunDecodeUnicodeString( Seed, &sUserPassword );
  3689. NetStatus2 = NetpManageIPCConnect( szDcName, szUser,
  3690. sUserPassword.Buffer,
  3691. NETSETUPP_DISCONNECT_IPC );
  3692. RtlRunEncodeUnicodeString( &Seed, &sUserPassword );
  3693. NetpLog(( "NetpApplyJoinState: status of disconnecting from '%ws': 0x%lx\n", szDcName, NetStatus2));
  3694. }
  3695. // Note: NetApiBufferFree checks for NULL
  3696. NetApiBufferFree( pDcInfo );
  3697. NetApiBufferFree( szDcName );
  3698. NetApiBufferFree( szDnsDomainName );
  3699. NetApiBufferFree( szCurrentMachinePassword );
  3700. if (RetStatus != NERR_Success)
  3701. {
  3702. NetStatus = RetStatus;
  3703. }
  3704. return( NetStatus );
  3705. }
  3706. NET_API_STATUS
  3707. NET_API_FUNCTION
  3708. NetpForceMachinePasswordChange(
  3709. IN LPWSTR szDomainName
  3710. )
  3711. {
  3712. NET_API_STATUS NetStatus = NERR_Success;
  3713. LPBYTE pNetlogonInfo=NULL;
  3714. NetpLog(( "NetpForceMachinePasswordChange: on '%ws'\n",
  3715. GetStrPtr(szDomainName)));
  3716. NetStatus = I_NetLogonControl2( NULL,
  3717. NETLOGON_CONTROL_CHANGE_PASSWORD,
  3718. 1, (LPBYTE) &szDomainName,
  3719. (LPBYTE *) &pNetlogonInfo );
  3720. if (NetStatus == NERR_Success)
  3721. {
  3722. NetApiBufferFree(pNetlogonInfo);
  3723. }
  3724. NetpLog(( "NetpForceMachinePasswordChange: status: 0x%lx\n", NetStatus));
  3725. return NetStatus;
  3726. }
  3727. NET_API_STATUS
  3728. NET_API_FUNCTION
  3729. NetpUpgradePreNT5JoinInfo( VOID )
  3730. {
  3731. NET_API_STATUS NetStatus =NERR_Success;
  3732. WCHAR szMachineNameBuf[MAX_COMPUTERNAME_LENGTH + 1];
  3733. LPWSTR szMachineName=szMachineNameBuf;
  3734. LPWSTR szDomainName=NULL;
  3735. NETSETUP_JOIN_STATUS JoinStatus;
  3736. NET_JOIN_STATE JoinState = { 0 };
  3737. DWORD dwJoinAction=0;
  3738. NetSetuppOpenLog();
  3739. NetpLog(( "NetpUpgradePreNT5JoinInfo: upgrading join info\n" ));
  3740. //
  3741. // make sure we are joined to a domain
  3742. //
  3743. NetStatus = NetpGetJoinInformation(NULL, &szDomainName, &JoinStatus);
  3744. if (NetStatus == NERR_Success)
  3745. {
  3746. if (JoinStatus == NetSetupDomainName)
  3747. {
  3748. //
  3749. // get the computer name
  3750. //
  3751. NetStatus = NetpGetComputerNameAllocIfReqd(
  3752. &szMachineName, MAX_COMPUTERNAME_LENGTH+1);
  3753. NetpLog(( "NetpUpgradePreNT5JoinInfo: status of getting computer name: 0x%lx\n", NetStatus ));
  3754. }
  3755. else
  3756. {
  3757. //
  3758. // machine is not joined to a domain,
  3759. // no need to upgrade anything
  3760. //
  3761. NetStatus = NERR_SetupNotJoined;
  3762. goto Cleanup;
  3763. }
  3764. }
  3765. if (NetStatus == NERR_Success)
  3766. {
  3767. NetpLog(( "NetpUpgradePreNT5JoinInfo: upgrading join info for '%ws' in domain '%ws'\n", szMachineName, szDomainName));
  3768. dwJoinAction =
  3769. NJA_UpdateNetlogonCache |
  3770. NJA_GetPolicyDomainInfo |
  3771. NJA_SetPolicyDomainInfo |
  3772. NJA_SetNetlogonState |
  3773. NJA_RecordDcInfo |
  3774. NJA_IgnoreErrors;
  3775. JoinState.szDomainName = szDomainName;
  3776. JoinState.uiNetlogonStartType = NETSETUP_SVC_ENABLED;
  3777. JoinState.uiNetlogonState = NETSETUP_SVC_STARTED;
  3778. NetStatus = NetpApplyJoinState(&JoinState, dwJoinAction,
  3779. szMachineName, NULL, NULL, NULL);
  3780. NetpLog(( "NetpUpgradePreNT5JoinInfo: status of NetpApplyJoinState: 0x%lx\n", NetStatus ));
  3781. //
  3782. // ignore earlier error, if any, and try to reset password
  3783. //
  3784. NetStatus = NetpWaitForNetlogonSc(szDomainName);
  3785. if (NetStatus == NERR_Success)
  3786. {
  3787. NetStatus = NetpForceMachinePasswordChange( szDomainName );
  3788. }
  3789. else
  3790. {
  3791. NetpLog(( "NetpUpgradePreNT5JoinInfo: netlogon did not establish secure channel, machine password not updated. This is not a fatal error. netlogon will retry updating the password later.\n" ));
  3792. }
  3793. }
  3794. Cleanup:
  3795. NetApiBufferFree(szDomainName);
  3796. if (szMachineName != szMachineNameBuf)
  3797. {
  3798. NetApiBufferFree(szMachineName);
  3799. }
  3800. NetpLog(( "NetpUpgradePreNT5JoinInfo: status: 0x%lx\n", NetStatus ));
  3801. NetSetuppCloseLog( );
  3802. return NetStatus;
  3803. }