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

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