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.

649 lines
17 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1998 - 2001
  4. Module Name:
  5. rename.c
  6. Abstract:
  7. Handles the various functions for renaming computers/domains
  8. --*/
  9. #include "pch.h"
  10. #pragma hdrstop
  11. #include <netdom.h>
  12. DWORD
  13. NetDompHandleRename(ARG_RECORD * rgNetDomArgs)
  14. /*++
  15. Routine Description:
  16. This function will rename the domain a BDC is in
  17. Arguments:
  18. Args - List of command line arguments
  19. Return Value:
  20. ERROR_INVALID_PARAMETER - No object name was supplied
  21. --*/
  22. {
  23. DWORD Win32Err = ERROR_SUCCESS;
  24. PWSTR Domain = NULL;
  25. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  26. LSA_HANDLE PdcHandle = NULL, BdcHandle = NULL;
  27. NTSTATUS Status;
  28. UNICODE_STRING Server;
  29. OBJECT_ATTRIBUTES OA;
  30. PPOLICY_PRIMARY_DOMAIN_INFO PdcPolicyPDI = NULL, BdcPolicyPDI = NULL;
  31. PPOLICY_ACCOUNT_DOMAIN_INFO PdcPolicyADI = NULL;
  32. PWSTR Object = rgNetDomArgs[eObject].strValue;
  33. if ( !Object ) {
  34. DisplayHelp(ePriRename);
  35. return( ERROR_INVALID_PARAMETER );
  36. }
  37. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  38. eObject,
  39. eCommDomain,
  40. eCommRestart,
  41. eCommVerbose,
  42. eArgEnd);
  43. if ( Win32Err != ERROR_SUCCESS )
  44. {
  45. DisplayHelp(ePriRename);
  46. return Win32Err;
  47. }
  48. //
  49. // Ok, make sure that we have a specified domain...
  50. //
  51. Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
  52. Object,
  53. TRUE,
  54. &Domain);
  55. if ( Win32Err != ERROR_SUCCESS ) {
  56. goto HandleRenameExit;
  57. }
  58. //
  59. // Get the name of a domain controller
  60. //
  61. Win32Err = DsGetDcName( NULL,
  62. Domain,
  63. NULL,
  64. NULL,
  65. DS_PDC_REQUIRED,
  66. &DcInfo );
  67. if ( Win32Err != ERROR_SUCCESS ) {
  68. goto HandleRenameExit;
  69. }
  70. InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
  71. RtlInitUnicodeString( &Server, DcInfo->DomainControllerName );
  72. Status = LsaOpenPolicy( &Server,
  73. &OA,
  74. POLICY_VIEW_LOCAL_INFORMATION,
  75. &PdcHandle );
  76. if ( NT_SUCCESS( Status ) ) {
  77. Status = LsaQueryInformationPolicy( PdcHandle,
  78. PolicyPrimaryDomainInformation,
  79. ( PVOID * )&PdcPolicyPDI );
  80. if ( NT_SUCCESS( Status ) ) {
  81. Status = LsaQueryInformationPolicy( PdcHandle,
  82. PolicyAccountDomainInformation,
  83. ( PVOID * )&PdcPolicyADI );
  84. if ( NT_SUCCESS( Status ) ) {
  85. RtlInitUnicodeString( &Server, Object );
  86. Status = LsaOpenPolicy( &Server,
  87. &OA,
  88. POLICY_VIEW_LOCAL_INFORMATION,
  89. &BdcHandle );
  90. if ( NT_SUCCESS( Status ) ) {
  91. Status = LsaQueryInformationPolicy( BdcHandle,
  92. PolicyPrimaryDomainInformation,
  93. ( PVOID * )&BdcPolicyPDI );
  94. }
  95. }
  96. }
  97. }
  98. if ( !NT_SUCCESS( Status ) ) {
  99. Win32Err = RtlNtStatusToDosError( Status );
  100. goto HandleRenameExit;
  101. }
  102. //
  103. // See if they are the same domain
  104. //
  105. if ( !PdcPolicyPDI->Sid || !BdcPolicyPDI->Sid ||
  106. !RtlEqualSid( BdcPolicyPDI->Sid, PdcPolicyPDI->Sid ) ) {
  107. Win32Err = ERROR_INVALID_DOMAIN_STATE;
  108. goto HandleRenameExit;
  109. }
  110. //
  111. // If they have the same name, do nothing...
  112. //
  113. if ( RtlCompareUnicodeString( &PdcPolicyPDI->Name, &BdcPolicyPDI->Name, TRUE ) ) {
  114. goto HandleRenameExit;
  115. }
  116. //
  117. // Otherwise, set it..
  118. //
  119. Status = LsaSetInformationPolicy( BdcHandle,
  120. PolicyPrimaryDomainInformation,
  121. ( PVOID )PdcPolicyPDI );
  122. if ( NT_SUCCESS( Status ) ) {
  123. Status = LsaSetInformationPolicy( BdcHandle,
  124. PolicyAccountDomainInformation,
  125. ( PVOID )PdcPolicyADI );
  126. //
  127. // Restore the original, if possible
  128. //
  129. if ( !NT_SUCCESS( Status ) ) {
  130. NTSTATUS Status2 = LsaSetInformationPolicy( BdcHandle,
  131. PolicyPrimaryDomainInformation,
  132. ( PVOID )BdcPolicyPDI );
  133. if ( !NT_SUCCESS( Status2 ) ) {
  134. NetDompDisplayMessage( MSG_FAIL_RENAME_RESTORE, Object );
  135. NetDompDisplayErrorMessage( RtlNtStatusToDosError( Status2 ) );
  136. }
  137. }
  138. }
  139. if ( !NT_SUCCESS( Status ) ) {
  140. Win32Err = RtlNtStatusToDosError( Status );
  141. goto HandleRenameExit;
  142. }
  143. //
  144. // Finally, reboot if necessary
  145. //
  146. NetDompRestartAsRequired(rgNetDomArgs,
  147. Object,
  148. NULL,
  149. Win32Err,
  150. MSG_DOMAIN_CHANGE_RESTART_MSG);
  151. HandleRenameExit:
  152. NetApiBufferFree( Domain );
  153. NetApiBufferFree( DcInfo );
  154. if ( PdcHandle ) {
  155. LsaClose( PdcHandle );
  156. }
  157. if ( BdcHandle ) {
  158. LsaClose( BdcHandle );
  159. }
  160. LsaFreeMemory( PdcPolicyPDI );
  161. LsaFreeMemory( PdcPolicyADI );
  162. LsaFreeMemory( BdcPolicyPDI );
  163. if (NO_ERROR != Win32Err)
  164. {
  165. NetDompDisplayErrorMessage(Win32Err);
  166. }
  167. return( Win32Err );
  168. }
  169. //+----------------------------------------------------------------------------
  170. //
  171. // Function: CheckNewName
  172. //
  173. // Synopsis: Validate the new computer name performing the same checks as
  174. // NetID
  175. //
  176. //-----------------------------------------------------------------------------
  177. DWORD CheckNewName(PWSTR pwzNewName)
  178. {
  179. DWORD dwErr = ERROR_SUCCESS;
  180. int cchName, i;
  181. DWORD size = CNLEN + 1;
  182. WCHAR wzNBname[CNLEN + 1] = {0};
  183. WORD rgwCharType[CNLEN + 1] = {0};
  184. BOOL fNumber = TRUE;
  185. //
  186. // Validate the computer name (logic same as NetID).
  187. //
  188. cchName = (int)wcslen( pwzNewName ); // cheap test first
  189. if ( DNS_MAX_LABEL_LENGTH < cchName )
  190. {
  191. NetDompDisplayMessage( MSG_DNS_LABEL_TOO_LONG, pwzNewName, DNS_MAX_LABEL_LENGTH );
  192. dwErr = ERROR_INVALID_PARAMETER;
  193. return dwErr;
  194. }
  195. cchName = WideCharToMultiByte( CP_UTF8,
  196. 0,
  197. pwzNewName,
  198. cchName,
  199. 0,
  200. 0,
  201. 0,
  202. 0 );
  203. if ( DNS_MAX_LABEL_LENGTH < cchName )
  204. {
  205. NetDompDisplayMessage( MSG_DNS_LABEL_TOO_LONG, pwzNewName, DNS_MAX_LABEL_LENGTH );
  206. dwErr = ERROR_INVALID_PARAMETER;
  207. return dwErr;
  208. }
  209. dwErr = DnsValidateName( pwzNewName, DnsNameHostnameLabel );
  210. switch ( dwErr )
  211. {
  212. case ERROR_INVALID_NAME:
  213. case DNS_ERROR_INVALID_NAME_CHAR:
  214. case DNS_ERROR_NUMERIC_NAME:
  215. NetDompDisplayMessage( MSG_DNS_LABEL_SYNTAX, pwzNewName );
  216. return dwErr;
  217. case DNS_ERROR_NON_RFC_NAME:
  218. //
  219. // Not an error, print warning message.
  220. //
  221. NetDompDisplayMessage( MSG_DNS_LABEL_WARN_RFC, pwzNewName );
  222. dwErr = NO_ERROR;
  223. break;
  224. case ERROR_SUCCESS:
  225. break;
  226. }
  227. if ( !DnsHostnameToComputerName( pwzNewName, wzNBname, &size ) )
  228. {
  229. dwErr = GetLastError();
  230. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, pwzNewName );
  231. return dwErr;
  232. }
  233. if ( ( cchName = (int)wcslen( wzNBname ) ) == 0 )
  234. {
  235. dwErr = ERROR_INVALID_COMPUTERNAME;
  236. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, pwzNewName );
  237. return dwErr;
  238. }
  239. if ( !GetStringTypeEx( LOCALE_USER_DEFAULT,
  240. CT_CTYPE1,
  241. wzNBname,
  242. cchName,
  243. rgwCharType ) )
  244. {
  245. dwErr = GetLastError();
  246. return dwErr;
  247. }
  248. for ( i = 0; i < cchName; i++ )
  249. {
  250. if ( !( rgwCharType[i] & C1_DIGIT ) )
  251. {
  252. fNumber = FALSE;
  253. break;
  254. }
  255. }
  256. if ( fNumber )
  257. {
  258. dwErr = ERROR_INVALID_COMPUTERNAME;
  259. NetDompDisplayMessage( MSG_NETBIOS_NAME_NUMERIC, wzNBname, CNLEN );
  260. return dwErr;
  261. }
  262. // The NetID code does further NetBIOS name validation which is repeated here.
  263. // This test is probably not necessary since the DNS name syntax is actually
  264. // more restrictive than NetBIOS and errors would be caught above by DnsValidateName.
  265. //
  266. if ( I_NetNameValidate( 0, wzNBname, NAMETYPE_COMPUTER, LM2X_COMPATIBLE ) != NERR_Success )
  267. {
  268. dwErr = ERROR_INVALID_COMPUTERNAME;
  269. NetDompDisplayMessage( MSG_BAD_NETBIOS_CHARACTERS );
  270. return dwErr;
  271. }
  272. if ( cchName < (int)wcslen( pwzNewName ) )
  273. {
  274. NetDompDisplayMessage( MSG_NAME_TRUNCATED, CNLEN, wzNBname );
  275. }
  276. return dwErr;
  277. }
  278. //+----------------------------------------------------------------------------
  279. //
  280. // Function: OkToRename
  281. //
  282. // Synopsis: Return failure code if the machine is a CA server or if in the
  283. // middle of DCPromo or a role change.
  284. //
  285. //-----------------------------------------------------------------------------
  286. DWORD OkToRename( PWSTR pwzComputer )
  287. {
  288. PDSROLE_OPERATION_STATE_INFO pRoleState;
  289. PDSROLE_UPGRADE_STATUS_INFO pRoleUpgrade;
  290. DWORD dwErr;
  291. SC_HANDLE hSc, hCA;
  292. // Is the machine a DC in the middle of an upgrade?
  293. dwErr = DsRoleGetPrimaryDomainInformation( pwzComputer,
  294. DsRoleUpgradeStatus,
  295. (PBYTE *) &pRoleUpgrade );
  296. if ( ERROR_SUCCESS != dwErr )
  297. {
  298. NetDompDisplayMessage( MSG_ROLE_READ_FAILED, pwzComputer, dwErr );
  299. return dwErr;
  300. }
  301. if ( pRoleUpgrade->OperationState & DSROLE_UPGRADE_IN_PROGRESS )
  302. {
  303. DsRoleFreeMemory( pRoleUpgrade );
  304. NetDompDisplayMessage( MSG_MUST_COMPLETE_DCPROMO );
  305. return ERROR_DS_UNWILLING_TO_PERFORM;
  306. }
  307. DsRoleFreeMemory( pRoleUpgrade );
  308. // Is the machine in the midst of changing its role?
  309. dwErr = DsRoleGetPrimaryDomainInformation( pwzComputer,
  310. DsRoleOperationState,
  311. (PBYTE *) &pRoleState );
  312. if ( ERROR_SUCCESS != dwErr )
  313. {
  314. NetDompDisplayMessage( MSG_ROLE_READ_FAILED, pwzComputer, dwErr );
  315. return dwErr;
  316. }
  317. if ( DsRoleOperationIdle != pRoleState->OperationState )
  318. {
  319. NetDompDisplayMessage( (DsRoleOperationActive == pRoleState->OperationState) ?
  320. MSG_ROLE_CHANGE_IN_PROGRESS : MSG_ROLE_CHANGE_NEEDS_REBOOT );
  321. DsRoleFreeMemory( pRoleState );
  322. return ERROR_DS_UNWILLING_TO_PERFORM;
  323. }
  324. DsRoleFreeMemory( pRoleState );
  325. // Is CertSvc installed?
  326. hSc = OpenSCManager( pwzComputer, SERVICES_ACTIVE_DATABASE, GENERIC_READ );
  327. if ( NULL == hSc )
  328. {
  329. dwErr = GetLastError();
  330. NetDompDisplayMessage( MSG_SC_OPEN_FAILED, pwzComputer, dwErr );
  331. return dwErr;
  332. }
  333. hCA = OpenService( hSc, L"SertSvc", SERVICE_QUERY_STATUS );
  334. CloseServiceHandle( hSc );
  335. if ( hCA )
  336. {
  337. NetDompDisplayMessage( MSG_CANT_RENAME_CERT_SVC );
  338. CloseServiceHandle( hCA );
  339. return ERROR_DS_UNWILLING_TO_PERFORM;
  340. }
  341. return ERROR_SUCCESS;
  342. }
  343. DWORD
  344. NetDompHandleRenameComputer(ARG_RECORD * rgNetDomArgs)
  345. /*++
  346. Routine Description:
  347. This function will rename a computer
  348. Arguments:
  349. Args - List of command line arguments
  350. Return Value:
  351. ERROR_INVALID_PARAMETER - No object name was supplied
  352. --*/
  353. {
  354. DWORD dwErr = ERROR_SUCCESS;
  355. ND5_AUTH_INFO ComputerUser, DomainUser;
  356. PWSTR pwzNewName = NULL;
  357. WKSTA_INFO_100 * pInfo = NULL;
  358. int cchName;
  359. BOOL fForce = CmdFlagOn(rgNetDomArgs, eCommForce );
  360. RtlZeroMemory( &ComputerUser, sizeof( ND5_AUTH_INFO ) );
  361. RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
  362. PWSTR pwzComputer = rgNetDomArgs[eObject].strValue;
  363. if ( !pwzComputer )
  364. {
  365. DisplayHelp(ePriRenameComputer);
  366. return( ERROR_INVALID_PARAMETER );
  367. }
  368. dwErr = NetDompValidateSecondaryArguments(rgNetDomArgs,
  369. eObject,
  370. eRenCompNewName,
  371. eCommUserNameD,
  372. eCommPasswordD,
  373. eCommUserNameO,
  374. eCommPasswordO,
  375. eCommForce,
  376. eCommRestart,
  377. eCommVerbose,
  378. eArgEnd);
  379. if ( ERROR_SUCCESS != dwErr )
  380. {
  381. DisplayHelp(ePriRenameComputer);
  382. return dwErr;
  383. }
  384. dwErr = NetDompGetArgumentString(rgNetDomArgs,
  385. eRenCompNewName,
  386. &pwzNewName);
  387. if ( ERROR_SUCCESS != dwErr )
  388. {
  389. NetDompDisplayErrorMessage(dwErr);
  390. return dwErr;
  391. }
  392. if ( !pwzNewName || !_wcsicmp( pwzComputer, pwzNewName ) )
  393. {
  394. DisplayHelp(ePriRenameComputer);
  395. return( ERROR_INVALID_PARAMETER );
  396. }
  397. //
  398. // Validate the computer name (logic same as NetID).
  399. //
  400. if ( ( dwErr = CheckNewName(pwzNewName) ) != ERROR_SUCCESS )
  401. {
  402. goto RenameComputerExit;
  403. }
  404. //
  405. // Get the computer user and password
  406. //
  407. dwErr = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  408. eCommUserNameO,
  409. pwzComputer,
  410. &ComputerUser);
  411. if ( ERROR_SUCCESS != dwErr )
  412. {
  413. goto RenameComputerExit;
  414. }
  415. if ( ComputerUser.User )
  416. {
  417. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, pwzComputer ));
  418. dwErr = NetpManageIPCConnect( pwzComputer,
  419. ComputerUser.User,
  420. ComputerUser.Password,
  421. NETSETUPP_CONNECT_IPC );
  422. if ( ERROR_SUCCESS != dwErr )
  423. {
  424. LOG_VERBOSE(( MSG_VERBOSE_SESSION_FAILED, pwzComputer ));
  425. ERROR_VERBOSE( dwErr );
  426. goto RenameComputerExit;
  427. }
  428. }
  429. //
  430. // Get the domain user and password
  431. //
  432. dwErr = NetWkstaGetInfo( pwzComputer, 100, (PBYTE *)&pInfo );
  433. if ( ERROR_SUCCESS != dwErr )
  434. {
  435. NetDompDisplayMessage( MSG_COMPUTER_NOT_FOUND, pwzComputer, dwErr );
  436. goto RenameComputerExit;
  437. }
  438. // DBG_VERBOSE(( "%ws domain: %ws\n", pwzComputer, pInfo->wki100_langroup ));
  439. dwErr = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  440. eCommUserNameD,
  441. pInfo->wki100_langroup,
  442. &DomainUser );
  443. if ( ERROR_SUCCESS != dwErr )
  444. {
  445. goto RenameComputerExit;
  446. }
  447. //
  448. // Check for conditions that should prevent a computer rename. This is done
  449. // after the IPC$ connection is made to the computer.
  450. //
  451. if ( (dwErr = OkToRename( pwzComputer ) ) != ERROR_SUCCESS )
  452. {
  453. goto RenameComputerExit;
  454. }
  455. //
  456. // Get confirmation if necessary.
  457. //
  458. if ( fForce )
  459. {
  460. LOG_VERBOSE(( MSG_ATTEMPT_RENAME_COMPUTER, pwzComputer, pwzNewName ));
  461. }
  462. else
  463. {
  464. NetDompDisplayMessage( MSG_ATTEMPT_RENAME_COMPUTER, pwzComputer, pwzNewName );
  465. NetDompDisplayMessage( MSG_RENAME_COMPUTER_WARNING, pwzComputer );
  466. if ( !NetDompGetUserConfirmation( IDS_PROMPT_PROCEED, NULL ) )
  467. {
  468. goto RenameComputerExit;
  469. }
  470. }
  471. //
  472. // Do the rename.
  473. //
  474. dwErr = NetRenameMachineInDomain( pwzComputer,
  475. pwzNewName,
  476. DomainUser.User,
  477. DomainUser.Password,
  478. NETSETUP_ACCT_CREATE );
  479. if ( ERROR_SUCCESS != dwErr )
  480. {
  481. LOG_VERBOSE(( MSG_VERBOSE_RENAME_COMPUTER_FAILED, dwErr ));
  482. }
  483. //
  484. // Reboot if necessary
  485. //
  486. NetDompRestartAsRequired(rgNetDomArgs,
  487. pwzComputer,
  488. NULL,
  489. dwErr,
  490. MSG_COMPUTER_RENAME_RESTART_MSG);
  491. if ( ComputerUser.User )
  492. {
  493. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, pwzComputer ));
  494. NetpManageIPCConnect( pwzComputer,
  495. ComputerUser.User,
  496. ComputerUser.Password,
  497. NETSETUPP_DISCONNECT_IPC );
  498. }
  499. RenameComputerExit:
  500. NetApiBufferFree( pwzNewName );
  501. if ( pInfo )
  502. {
  503. NetApiBufferFree( pInfo );
  504. }
  505. NetDompFreeAuthIdent( &ComputerUser );
  506. NetDompFreeAuthIdent( &DomainUser );
  507. if (NO_ERROR != dwErr)
  508. {
  509. NetDompDisplayErrorMessage(dwErr);
  510. }
  511. return dwErr;
  512. }