Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1112 lines
38 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2001
  5. //
  6. // File: CompName.h
  7. //
  8. // Contents: Definitions for the computer name management code.
  9. //
  10. // History: 20-April-2001 EricB Created
  11. //
  12. //-----------------------------------------------------------------------------
  13. #include "pch.h"
  14. #pragma hdrstop
  15. #include "netdom.h"
  16. #include "CompName.h"
  17. //+----------------------------------------------------------------------------
  18. //
  19. // Function: NetDomComputerNames
  20. //
  21. // Synopsis: Entry point for the computer name command.
  22. //
  23. // Arguments: [rgNetDomArgs] - The command line argument array.
  24. //
  25. //-----------------------------------------------------------------------------
  26. DWORD
  27. NetDomComputerNames(ARG_RECORD * rgNetDomArgs)
  28. {
  29. DWORD Win32Err = ERROR_SUCCESS;
  30. Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
  31. eObject,
  32. eCommUserNameO,
  33. eCommPasswordO,
  34. eCommUserNameD,
  35. eCommPasswordD,
  36. eCommAdd,
  37. eCommRemove,
  38. eCompNameMakePri,
  39. eCompNameEnum,
  40. eCommVerify,
  41. eCommVerbose,
  42. eArgEnd);
  43. if (ERROR_SUCCESS != Win32Err)
  44. {
  45. DisplayHelp(ePriCompName);
  46. return Win32Err;
  47. }
  48. PWSTR pwzMachine = rgNetDomArgs[eObject].strValue;
  49. if (!pwzMachine)
  50. {
  51. DisplayHelp(ePriCompName);
  52. return ERROR_INVALID_PARAMETER;
  53. }
  54. //
  55. // Get the users and passwords if they were entered.
  56. //
  57. ND5_AUTH_INFO MachineUser = {0}, DomainUser = {0};
  58. if (CmdFlagOn(rgNetDomArgs, eCommUserNameO))
  59. {
  60. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  61. eCommUserNameO,
  62. pwzMachine,
  63. &MachineUser);
  64. if (ERROR_SUCCESS != Win32Err)
  65. {
  66. DisplayHelp(ePriCompName);
  67. return Win32Err;
  68. }
  69. }
  70. if (CmdFlagOn(rgNetDomArgs, eCommUserNameD))
  71. {
  72. Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
  73. eCommUserNameD,
  74. pwzMachine,
  75. &DomainUser);
  76. if (ERROR_SUCCESS != Win32Err)
  77. {
  78. DisplayHelp(ePriCompName);
  79. goto CompNameExit;
  80. }
  81. }
  82. //
  83. // See which name operation is specified.
  84. //
  85. bool fHaveOp = false;
  86. PWSTR pwzOp = NULL;
  87. NETDOM_ARG_ENUM eOp = eArgNull, eBadOp = eArgNull;
  88. if (CmdFlagOn(rgNetDomArgs, eCommAdd))
  89. {
  90. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  91. eCommAdd,
  92. &pwzOp);
  93. if (NO_ERROR == Win32Err)
  94. {
  95. eOp = eCommAdd;
  96. }
  97. }
  98. if (CmdFlagOn(rgNetDomArgs, eCommRemove))
  99. {
  100. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  101. eCommRemove,
  102. &pwzOp);
  103. if (NO_ERROR == Win32Err)
  104. {
  105. if (eArgNull == eOp)
  106. {
  107. eOp = eCommRemove;
  108. }
  109. else
  110. {
  111. eBadOp = eCommRemove;
  112. }
  113. }
  114. }
  115. if (CmdFlagOn(rgNetDomArgs, eCompNameMakePri))
  116. {
  117. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  118. eCompNameMakePri,
  119. &pwzOp);
  120. if (NO_ERROR == Win32Err)
  121. {
  122. if (eArgNull == eOp)
  123. {
  124. eOp = eCompNameMakePri;
  125. }
  126. else
  127. {
  128. eBadOp = eCompNameMakePri;
  129. }
  130. }
  131. }
  132. if (CmdFlagOn(rgNetDomArgs, eCompNameEnum))
  133. {
  134. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  135. eCompNameEnum,
  136. &pwzOp);
  137. if (NO_ERROR == Win32Err)
  138. {
  139. if (eArgNull == eOp)
  140. {
  141. eOp = eCompNameEnum;
  142. }
  143. else
  144. {
  145. eBadOp = eCompNameEnum;
  146. }
  147. }
  148. }
  149. if (CmdFlagOn(rgNetDomArgs, eCommVerify))
  150. {
  151. if (eArgNull == eOp)
  152. {
  153. eOp = eCommVerify;
  154. }
  155. else
  156. {
  157. eBadOp = eCommVerify;
  158. }
  159. }
  160. if (eArgNull != eBadOp)
  161. {
  162. ASSERT(rgNetDomArgs[eBadOp].strArg1);
  163. NetDompDisplayUnexpectedParameter(rgNetDomArgs[eBadOp].strArg1);
  164. DisplayHelp(ePriCompName);
  165. Win32Err = ERROR_INVALID_PARAMETER;
  166. goto CompNameExit;
  167. }
  168. if (eArgNull == eOp)
  169. {
  170. DisplayHelp(ePriCompName);
  171. Win32Err = ERROR_INVALID_PARAMETER;
  172. goto CompNameExit;
  173. }
  174. if (CmdFlagOn(rgNetDomArgs, eCommUserNameO))
  175. {
  176. LOG_VERBOSE((MSG_VERBOSE_ESTABLISH_SESSION, pwzMachine));
  177. Win32Err = NetpManageIPCConnect(pwzMachine,
  178. MachineUser.User,
  179. MachineUser.Password,
  180. NETSETUPP_CONNECT_IPC);
  181. }
  182. if (NO_ERROR != Win32Err)
  183. {
  184. goto CompNameExit;
  185. }
  186. int cchName = 0;
  187. DWORD size = CNLEN + 1;
  188. WCHAR wzNBname[CNLEN + 1] = {0};
  189. // To ensure that netdom.exe runs on Win2K, we do
  190. // dynamic loading of the following API that are available
  191. // only in later versions of netapi32.dll
  192. HMODULE hm = NULL;
  193. if ( eOp == eCommAdd ||
  194. eOp == eCommRemove ||
  195. eOp == eCompNameMakePri ||
  196. eOp == eCompNameEnum
  197. )
  198. {
  199. hm = LoadLibrary ( L"netapi32.dll" );
  200. if ( !hm )
  201. {
  202. Win32Err = GetLastError ();
  203. NetDompDisplayMessage ( MSG_NETAPI32_LOAD_FAILED );
  204. goto CompNameExit;
  205. }
  206. }
  207. //
  208. // Do the operation.
  209. //
  210. switch (eOp)
  211. {
  212. case eCommAdd:
  213. {
  214. typedef DWORD (*NetAddAltCompName) (
  215. LPCWSTR Server,
  216. LPCWSTR AlternateName,
  217. LPCWSTR DomainAccount,
  218. LPCWSTR DomainAccountPasswd,
  219. ULONG Reserved
  220. );
  221. NetAddAltCompName pNetAddAltCompName = NULL;
  222. pNetAddAltCompName = ( NetAddAltCompName ) GetProcAddress ( hm, "NetAddAlternateComputerName" );
  223. if ( !pNetAddAltCompName )
  224. {
  225. NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL );
  226. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  227. goto CompNameExit;
  228. }
  229. // NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
  230. // string's length
  231. if (!rgNetDomArgs[eCommAdd].strValue ||
  232. !wcslen(rgNetDomArgs[eCommAdd].strValue))
  233. {
  234. DisplayHelp(ePriCompName);
  235. Win32Err = ERROR_INVALID_PARAMETER;
  236. goto CompNameExit;
  237. }
  238. // The name being added should be a Fully Qualified DNS Name (FQDN)
  239. // So check if the name has dots (.) in it.
  240. if ( wcschr ( rgNetDomArgs[eCommAdd].strValue, L'.' ) == NULL )
  241. {
  242. // Create and load the Response strings
  243. WCHAR wzYes[NETDOM_STR_LEN], wzNo[NETDOM_STR_LEN];
  244. if (!LoadString(g_hInstance, IDS_YES, wzYes, NETDOM_STR_LEN) ||
  245. !LoadString(g_hInstance, IDS_NO, wzNo, NETDOM_STR_LEN))
  246. {
  247. DisplayOutput ( L"LoadString FAILED!" );
  248. Win32Err = ERROR_RESOURCE_NAME_NOT_FOUND;
  249. goto CompNameExit;
  250. }
  251. PWSTR pwszResponse = NULL;
  252. BOOL Proceed = FALSE;
  253. // Display warning that name being added is not a Full Qualified DNS name
  254. NetDompDisplayMessage ( MSG_COMPNAME_ADD_NOT_FQDN, rgNetDomArgs[eCommAdd].strValue );
  255. // Give the user 3 chances to get in a valid response
  256. int i = 0;
  257. for ( ; i < 3; i ++ )
  258. {
  259. // Prompt user to Continue ( Y or N )
  260. NetDompDisplayMessage ( MSG_PROMPT_PROCEED, NULL );
  261. if ( -1 != ReadFromIn ( &pwszResponse ) )
  262. {
  263. //Compare the first char of response with Yes and No strings
  264. if ( _wcsnicmp ( pwszResponse, wzYes, 1 ) == 0 )
  265. {
  266. Proceed = TRUE;
  267. break;
  268. }
  269. if ( _wcsnicmp ( pwszResponse, wzNo, 1 ) == 0 )
  270. {
  271. Proceed = FALSE;
  272. break;
  273. }
  274. }
  275. else
  276. {
  277. // Unable to get response from user (typically when input is too large)
  278. // Blank line
  279. DisplayOutput ( L"" );
  280. NetDompDisplayMessage ( MSG_PROMPT_FAILED );
  281. Proceed = FALSE;
  282. Win32Err = ERROR_CANCELLED;
  283. break;
  284. }
  285. if ( pwszResponse )
  286. {
  287. LocalFree ( pwszResponse );
  288. pwszResponse = NULL;
  289. }
  290. }
  291. if ( i == 3 )
  292. {
  293. // Correct response was not entered after 3 tries
  294. DisplayOutput ( L"" );
  295. NetDompDisplayMessage ( MSG_PROMPT_FAILED );
  296. Proceed = FALSE;
  297. Win32Err = ERROR_CANCELLED;
  298. }
  299. LocalFree ( pwszResponse );
  300. DisplayOutput ( L"" );
  301. if ( !Proceed )
  302. {
  303. NetDompDisplayMessage ( MSG_COMPNAME_ADD_NOT_COMPLETED );
  304. goto CompNameExit;
  305. }
  306. }
  307. // If the alternative name being added is longer than 15 chars and
  308. // if it is made the primary name, the corresponding NETBIOS will
  309. // be formed by truncating it to its first 15 chars.
  310. // Inform the user about this case
  311. // Obtain the Netbios name from the DNS name
  312. if ( !DnsHostnameToComputerName( rgNetDomArgs[eCommAdd].strValue, wzNBname, &size ) )
  313. {
  314. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCommAdd].strValue );
  315. Win32Err = GetLastError();
  316. goto CompNameExit;
  317. }
  318. if ( ( cchName = (int)wcslen( wzNBname ) ) == 0 )
  319. {
  320. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCommAdd].strValue );
  321. Win32Err = ERROR_INVALID_COMPUTERNAME;
  322. goto CompNameExit;
  323. }
  324. // If the NetBIOS name is truncated, display warning
  325. if ( cchName < (int) wcscspn( rgNetDomArgs[eCommAdd].strValue, L"." ) )
  326. {
  327. NetDompDisplayMessage( MSG_COMPNAME_ADD_NETBIOS_TRUNCATE, CNLEN, wzNBname );
  328. }
  329. Win32Err = pNetAddAltCompName ( pwzMachine,
  330. rgNetDomArgs[eCommAdd].strValue,
  331. DomainUser.User,
  332. DomainUser.Password,
  333. 0);
  334. if (NO_ERROR == Win32Err)
  335. {
  336. NetDompDisplayMessage(MSG_COMPNAME_ADD, rgNetDomArgs[eCommAdd].strValue);
  337. }
  338. else
  339. {
  340. NetDompDisplayMessage(MSG_COMPNAME_ADD_FAIL, rgNetDomArgs[eCommAdd].strValue);
  341. NetDompDisplayErrorMessage(Win32Err);
  342. if (ERROR_CAN_NOT_COMPLETE == Win32Err ||
  343. ERROR_DS_NOT_SUPPORTED == Win32Err)
  344. {
  345. NetDompDisplayMessage(MSG_COMPNAME_ADD_FAIL_VERSION);
  346. }
  347. }
  348. break;
  349. }
  350. case eCommRemove:
  351. {
  352. typedef DWORD (*NetRemoveAltCompName) (
  353. LPCWSTR Server,
  354. LPCWSTR AlternateName,
  355. LPCWSTR DomainAccount,
  356. LPCWSTR DomainAccountPasswd,
  357. ULONG Reserved
  358. );
  359. NetRemoveAltCompName pNetRemoveAltCompName = NULL;
  360. pNetRemoveAltCompName = ( NetRemoveAltCompName ) GetProcAddress ( hm, "NetRemoveAlternateComputerName" );
  361. if ( !pNetRemoveAltCompName )
  362. {
  363. NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL );
  364. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  365. goto CompNameExit;
  366. }
  367. // NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
  368. // string's length
  369. if (!rgNetDomArgs[eCommRemove].strValue ||
  370. !wcslen(rgNetDomArgs[eCommRemove].strValue))
  371. {
  372. DisplayHelp(ePriCompName);
  373. Win32Err = ERROR_INVALID_PARAMETER;
  374. goto CompNameExit;
  375. }
  376. Win32Err = pNetRemoveAltCompName( pwzMachine,
  377. rgNetDomArgs[eCommRemove].strValue,
  378. DomainUser.User,
  379. DomainUser.Password,
  380. 0);
  381. if (NO_ERROR == Win32Err)
  382. {
  383. NetDompDisplayMessage(MSG_COMPNAME_REM, rgNetDomArgs[eCommRemove].strValue);
  384. }
  385. else
  386. {
  387. NetDompDisplayMessage(MSG_COMPNAME_REM_FAIL, rgNetDomArgs[eCommRemove].strValue);
  388. NetDompDisplayErrorMessage(Win32Err);
  389. }
  390. break;
  391. }
  392. case eCompNameMakePri:
  393. {
  394. typedef DWORD (*NetMakeCompNamePri) (
  395. LPCWSTR Server,
  396. LPCWSTR AlternateName,
  397. LPCWSTR DomainAccount,
  398. LPCWSTR DomainAccountPasswd,
  399. ULONG Reserved
  400. );
  401. NetMakeCompNamePri pNetMakeCompNamePri = NULL;
  402. pNetMakeCompNamePri = ( NetMakeCompNamePri ) GetProcAddress ( hm, "NetSetPrimaryComputerName" );
  403. if ( !pNetMakeCompNamePri )
  404. {
  405. NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL );
  406. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  407. goto CompNameExit;
  408. }
  409. // NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
  410. // string's length
  411. if (!rgNetDomArgs[eCompNameMakePri].strValue ||
  412. !wcslen(rgNetDomArgs[eCompNameMakePri].strValue))
  413. {
  414. DisplayHelp(ePriCompName);
  415. Win32Err = ERROR_INVALID_PARAMETER;
  416. goto CompNameExit;
  417. }
  418. // If the name being made primary is longer than 15 chars
  419. // the corresponding NETBIOS name will
  420. // be formed by truncating it to its first 15 chars.
  421. // Inform the user about this case
  422. // Obtain the Netbios name from the DNS name
  423. if ( !DnsHostnameToComputerName( rgNetDomArgs[eCompNameMakePri].strValue, wzNBname, &size ) )
  424. {
  425. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCompNameMakePri].strValue );
  426. Win32Err = GetLastError();
  427. goto CompNameExit;
  428. }
  429. if ( ( cchName = (int)wcslen( wzNBname ) ) == 0 )
  430. {
  431. NetDompDisplayMessage( MSG_CONVERSION_TO_NETBIOS_NAME_FAILED, rgNetDomArgs[eCompNameMakePri].strValue );
  432. Win32Err = ERROR_INVALID_COMPUTERNAME;
  433. goto CompNameExit;
  434. }
  435. // If the NetBIOS name is truncated, display warning
  436. if ( cchName < (int)wcscspn( rgNetDomArgs[eCompNameMakePri].strValue, L"." ) )
  437. {
  438. NetDompDisplayMessage( MSG_COMPNAME_MAKE_PRI_NETBIOS_TRUNCATE, CNLEN, wzNBname );
  439. }
  440. Win32Err = pNetMakeCompNamePri( pwzMachine,
  441. rgNetDomArgs[eCompNameMakePri].strValue,
  442. DomainUser.User,
  443. DomainUser.Password,
  444. 0);
  445. if (NO_ERROR == Win32Err)
  446. {
  447. NetDompDisplayMessage(MSG_COMPNAME_MAKEPRI, rgNetDomArgs[eCompNameMakePri].strValue);
  448. }
  449. else
  450. {
  451. NetDompDisplayMessage(MSG_COMPNAME_MAKEPRI_FAIL, rgNetDomArgs[eCompNameMakePri].strValue);
  452. NetDompDisplayErrorMessage(Win32Err);
  453. //Special check for Account already exists error, this can happen
  454. //if there is a Computer Account or a Server Object with the same name
  455. //already present in AD
  456. if ( Win32Err == NERR_UserExists )
  457. {
  458. NetDompDisplayMessage ( MSG_COMPNAME_ACCT_EXISTS, wzNBname );
  459. }
  460. }
  461. break;
  462. }
  463. case eCompNameEnum:
  464. {
  465. typedef DWORD (*NetEnumCompName) (
  466. LPCWSTR Server,
  467. NET_COMPUTER_NAME_TYPE NameType,
  468. ULONG Reserved,
  469. PDWORD EntryCount,
  470. LPWSTR **ComputerNames
  471. );
  472. NetEnumCompName pNetEnumCompName = NULL;
  473. pNetEnumCompName = ( NetEnumCompName ) GetProcAddress ( hm, "NetEnumerateComputerNames" );
  474. if ( !pNetEnumCompName )
  475. {
  476. NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL );
  477. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  478. goto CompNameExit;
  479. }
  480. NET_COMPUTER_NAME_TYPE NameType = NetAllComputerNames;
  481. WCHAR wzBuf[MAX_PATH+1];
  482. DWORD dwMsgID = MSG_COMPNAME_ENUMALL;
  483. int stringLength = 0;
  484. // NOTICE-2002/03/04-ericb - SecurityPush: pointer is verified before checking
  485. // string's length
  486. if (rgNetDomArgs[eCompNameEnum].strValue &&
  487. wcslen(rgNetDomArgs[eCompNameEnum].strValue))
  488. {
  489. // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
  490. // string length, save it for use below after checking that it doesn't
  491. // equal MAX_PATH. (Done by shasan 4/10/2002)
  492. stringLength = LoadString(g_hInstance, IDS_ENUM_ALT, wzBuf, MAX_PATH);
  493. if ( !stringLength )
  494. {
  495. Win32Err = GetLastError();
  496. goto CompNameExit;
  497. }
  498. // Check for truncation
  499. if ( stringLength == MAX_PATH )
  500. {
  501. Win32Err = ERROR_INSUFFICIENT_BUFFER;
  502. goto CompNameExit;
  503. }
  504. // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
  505. // wzBuf from above. (Done by shasan 4/10/2002)
  506. if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength) == 0)
  507. {
  508. NameType = NetAlternateComputerNames;
  509. dwMsgID = MSG_COMPNAME_ENUMALT;
  510. }
  511. else
  512. {
  513. // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
  514. // string length, save it for use below after checking that it doesn't equal MAX_PATH. (Done by shasan 4/10/2002)
  515. stringLength = LoadString(g_hInstance, IDS_ENUM_PRI, wzBuf, MAX_PATH );
  516. if ( !stringLength )
  517. {
  518. Win32Err = GetLastError();
  519. goto CompNameExit;
  520. }
  521. // Check for truncation
  522. if ( stringLength == MAX_PATH )
  523. {
  524. Win32Err = ERROR_INSUFFICIENT_BUFFER;
  525. goto CompNameExit;
  526. }
  527. // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
  528. // wzBuf from above. (Done by shasan 4/10/2002)
  529. if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength ) == 0)
  530. {
  531. NameType = NetPrimaryComputerName;
  532. dwMsgID = MSG_COMPNAME_ENUMPRI;
  533. }
  534. else
  535. {
  536. // NOTICE-2002/03/04-ericb - SecurityPush: return from LoadString is
  537. // string length, save it for use below after checking that it doesn't equal MAX_PATH.(Done by shasan 4/10/2002)
  538. stringLength = LoadString(g_hInstance, IDS_ENUM_ALL, wzBuf, MAX_PATH);
  539. if ( !stringLength )
  540. {
  541. Win32Err = GetLastError();
  542. goto CompNameExit;
  543. }
  544. // Check for truncation
  545. if ( stringLength == MAX_PATH )
  546. {
  547. Win32Err = ERROR_INSUFFICIENT_BUFFER;
  548. goto CompNameExit;
  549. }
  550. // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp with length of
  551. // wzBuf from above. (Done by shasan 4/10/2002)
  552. if (_wcsnicmp(wzBuf, rgNetDomArgs[eCompNameEnum].strValue, stringLength) == 0)
  553. {
  554. NameType = NetAllComputerNames;
  555. dwMsgID = MSG_COMPNAME_ENUMALL;
  556. }
  557. else
  558. {
  559. NetDompDisplayUnexpectedParameter(rgNetDomArgs[eCompNameEnum].strValue);
  560. DisplayHelp(ePriCompName);
  561. Win32Err = ERROR_INVALID_PARAMETER;
  562. goto CompNameExit;
  563. }
  564. }
  565. }
  566. }
  567. DWORD dwCount = 0;
  568. PWSTR * rgpwzNames = NULL;
  569. DBG_VERBOSE(("NetEnumerateComputerNames(%ws, %d, 0, etc)\n", pwzMachine, NameType));
  570. Win32Err = pNetEnumCompName ( pwzMachine,
  571. NameType,
  572. 0,
  573. &dwCount,
  574. &rgpwzNames);
  575. if (NO_ERROR != Win32Err)
  576. {
  577. NetDompDisplayErrorMessage(Win32Err);
  578. goto CompNameExit;
  579. }
  580. NetDompDisplayMessage(dwMsgID);
  581. for (DWORD i = 0; i < dwCount; i++)
  582. {
  583. // NOTICE-2002/03/04-ericb - SecurityPush: fail if rgpwzNames[i] is not
  584. // a valid string, don't just assert. (Done by shasan 4/10/2002)
  585. if ( ! rgpwzNames[i] )
  586. {
  587. ASSERT(rgpwzNames[i]);
  588. Win32Err = ERROR_FUNCTION_FAILED;
  589. goto CompNameExit;
  590. }
  591. // NOTICE-2002/03/04-ericb - SecurityPush: Use varg.cxx output routine instead of printf. (Done by shasan 4/10/2002)
  592. DisplayOutput ( rgpwzNames[i] );
  593. }
  594. if (rgpwzNames)
  595. {
  596. NetApiBufferFree(rgpwzNames);
  597. }
  598. }
  599. break;
  600. case eCommVerify:
  601. Win32Err = VerifyComputerNameRegistrations(pwzMachine, &DomainUser);
  602. break;
  603. default:
  604. ASSERT(FALSE);
  605. Win32Err = ERROR_INVALID_PARAMETER;
  606. goto CompNameExit;
  607. }
  608. CompNameExit:
  609. if (CmdFlagOn(rgNetDomArgs, eCommUserNameO))
  610. {
  611. LOG_VERBOSE((MSG_VERBOSE_DELETE_SESSION, pwzMachine));
  612. NetpManageIPCConnect(pwzMachine,
  613. MachineUser.User,
  614. MachineUser.Password,
  615. NETSETUPP_DISCONNECT_IPC);
  616. }
  617. if ( hm )
  618. {
  619. FreeLibrary ( hm );
  620. }
  621. NetDompFreeAuthIdent(&MachineUser);
  622. NetDompFreeAuthIdent(&DomainUser);
  623. return Win32Err;
  624. }
  625. //+----------------------------------------------------------------------------
  626. //
  627. // Function: VerifyComputerNameRegistrations
  628. //
  629. // Synopsis: Check that each computer name has a DNS a record and an SPN.
  630. //
  631. //-----------------------------------------------------------------------------
  632. DWORD
  633. VerifyComputerNameRegistrations(PCWSTR pwzMachine, ND5_AUTH_INFO * pDomainUser)
  634. {
  635. DWORD Win32Err = NO_ERROR, dwCount = 0;
  636. PWSTR * rgpwzNames = NULL;
  637. HMODULE hm = NULL;
  638. HMODULE hm2 = NULL;
  639. //
  640. // See if the computer is joined to a domain.
  641. //
  642. PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
  643. PWSTR * rgwzSPNs = NULL;
  644. LOG_VERBOSE((MSG_COMPNAME_CHECKING_JOIN, pwzMachine));
  645. //
  646. // It's joined, get a DC for the domain. Specify DS_DIRECTORY_SERVICE_REQUIRED
  647. // because we only check for SPNs if the domain is uplevel (supports AD).
  648. //
  649. Win32Err = DsGetDcName(pwzMachine,
  650. NULL,
  651. NULL,
  652. NULL,
  653. DS_DIRECTORY_SERVICE_REQUIRED,
  654. &pDcInfo);
  655. if (NO_ERROR != Win32Err)
  656. {
  657. if (ERROR_NO_SUCH_DOMAIN == Win32Err)
  658. {
  659. // Its joined to a downlevel domain. There is no SPN data.
  660. //
  661. LOG_VERBOSE((MSG_COMPNAME_NOT_UPLEVEL_JOINED));
  662. }
  663. else if (RPC_S_UNKNOWN_IF == Win32Err)
  664. {
  665. LOG_VERBOSE((MSG_COMPNAME_NOT_JOINED));
  666. }
  667. else if (RPC_S_SERVER_UNAVAILABLE == Win32Err)
  668. {
  669. NetDompDisplayMessage(MSG_COMPNAME_COMPUTER_NOT_FOUND, pwzMachine);
  670. return Win32Err;
  671. }
  672. else
  673. {
  674. NetDompDisplayErrorMessage(Win32Err);
  675. return Win32Err;
  676. }
  677. }
  678. else
  679. {
  680. PWSTR pwzFilter = NULL;
  681. PLDAP pLdap = NULL;
  682. LDAPMessage * pMessage = NULL;
  683. WKSTA_INFO_100 * pInfo = NULL;
  684. do
  685. {
  686. if (!pDcInfo || !pDcInfo->DomainControllerName)
  687. {
  688. ASSERT(FALSE);
  689. return ERROR_INVALID_FUNCTION;
  690. }
  691. LOG_VERBOSE((MSG_COMPNAME_READING_SPNS, pDcInfo->DomainName));
  692. // Read the downlevel name (SAM account name) of the computer.
  693. //
  694. Win32Err = NetWkstaGetInfo(const_cast<PWSTR>(pwzMachine), 100, (PBYTE *)&pInfo);
  695. // NOTICE-2002/03/04-ericb - SecurityPush: check return data from NetWkstaGetInfo (done)
  696. if (ERROR_SUCCESS != Win32Err || !pInfo || !pInfo->wki100_computername)
  697. {
  698. // NOTICE-2002/03/04-ericb need better message
  699. // ( shasan 4/16/02 - No change in mesg needed as discussed with levone )
  700. NetDompDisplayMessageAndError(MSG_COMPNAME_NO_PRINAME,
  701. Win32Err,
  702. pwzMachine);
  703. break;
  704. }
  705. // There could be multiple computer objects with the same CN (in
  706. // different containers), but only one computer object will have this
  707. // SAM-Account-Name.
  708. //
  709. WCHAR wzFilterFormat[] = L"(&(objectCategory=computer)(sAMAccountName=%s$))";
  710. // NOTICE-2002/03/04-ericb - SecurityPush: find length of static string
  711. // using sizeof(wzFilterFormat)/sizeof(WCHAR)-1. Find length of
  712. // pInfo->wki100_computername using StringCchLength with a max length value.
  713. // (fixed by shasan 4/12/2002)
  714. size_t nameLength = 0;
  715. HRESULT hr = NULL;
  716. hr = StringCchLengthW ( pInfo->wki100_computername, MAX_COMPUTERNAME_LENGTH + 1, &nameLength );
  717. if ( ! SUCCEEDED ( hr ) )
  718. {
  719. Win32Err = HRESULT_CODE ( hr );
  720. NetDompDisplayErrorMessage ( Win32Err );
  721. NetApiBufferFree(pDcInfo);
  722. return Win32Err;
  723. }
  724. pwzFilter = (PWSTR)LocalAlloc(LPTR,
  725. ( (sizeof ( wzFilterFormat ) / sizeof ( WCHAR ) - 1) + nameLength + 1 ) * sizeof(WCHAR));
  726. if (!pwzFilter)
  727. {
  728. NetDompDisplayErrorMessage(ERROR_NOT_ENOUGH_MEMORY);
  729. NetApiBufferFree(pDcInfo);
  730. return ERROR_NOT_ENOUGH_MEMORY;
  731. }
  732. // NOTICE-2002/03/04-ericb - SecurityPush: buffer allocated large enough to
  733. // hold the combined strings.
  734. wsprintf(pwzFilter, wzFilterFormat, pInfo->wki100_computername);
  735. Win32Err = NetDompLdapBind(pDcInfo->DomainControllerName + 2,
  736. pDomainUser->pwzUsersDomain,
  737. pDomainUser->pwzUserWoDomain,
  738. pDomainUser->Password,
  739. LDAP_AUTH_NEGOTIATE,
  740. &pLdap);
  741. if (ERROR_SUCCESS != Win32Err)
  742. {
  743. if (ERROR_WRONG_PASSWORD == Win32Err)
  744. {
  745. NetDompDisplayMessage(MSG_COMPNAME_SPN_NO_ACCESS);
  746. Win32Err = NO_ERROR;
  747. }
  748. break;
  749. }
  750. PWSTR Attrib[2] = {
  751. L"servicePrincipalName",
  752. NULL
  753. };
  754. PWSTR pwzDomainDn = NULL;
  755. Win32Err = NetDompLdapReadOneAttribute(pLdap,
  756. NULL, // equivalent to L"RootDSE",
  757. L"defaultNamingContext",
  758. &pwzDomainDn);
  759. if (ERROR_SUCCESS != Win32Err)
  760. {
  761. break;
  762. }
  763. LDAPMessage * pEntry;
  764. Win32Err = LdapMapErrorToWin32(ldap_search_s(pLdap,
  765. pwzDomainDn,
  766. LDAP_SCOPE_SUBTREE,
  767. pwzFilter,
  768. Attrib,
  769. 0,
  770. &pMessage));
  771. NetApiBufferFree(pwzDomainDn);
  772. if (ERROR_SUCCESS != Win32Err)
  773. {
  774. break;
  775. }
  776. pEntry = ldap_first_entry(pLdap, pMessage);
  777. if (!pEntry)
  778. {
  779. NetDompDisplayMessage(MSG_COMPNAME_OBJECT_NOT_FOUND, pInfo->wki100_computername);
  780. NetDompDisplayMessage(MSG_COMPNAME_SPN_SEARCH_FAILED);
  781. break;
  782. }
  783. rgwzSPNs = ldap_get_values(pLdap,
  784. pEntry,
  785. Attrib[0]);
  786. if (!rgwzSPNs)
  787. {
  788. LOG_VERBOSE((MSG_COMPNAME_SPN_SEARCH_FAILED));
  789. }
  790. } while (false);
  791. if (Win32Err != ERROR_SUCCESS)
  792. {
  793. NetDompDisplayMessage(MSG_COMPNAME_SPN_SEARCH_FAILED);
  794. NetDompDisplayErrorMessage(Win32Err);
  795. }
  796. if (pwzFilter)
  797. {
  798. LocalFree(pwzFilter);
  799. }
  800. if (pInfo)
  801. {
  802. NetApiBufferFree(pInfo);
  803. }
  804. if (pMessage)
  805. {
  806. ldap_msgfree(pMessage);
  807. }
  808. if (pLdap)
  809. {
  810. NetDompLdapUnbind(pLdap);
  811. }
  812. if (pDcInfo)
  813. {
  814. NetApiBufferFree(pDcInfo);
  815. }
  816. }
  817. // To ensure that netdom.exe runs on Win2K, we do
  818. // dynamic loading of the following API that are available
  819. // only in later versions of netapi32.dll
  820. hm = LoadLibrary ( L"netapi32.dll" );
  821. if ( !hm )
  822. {
  823. Win32Err = GetLastError ();
  824. NetDompDisplayMessage ( MSG_NETAPI32_LOAD_FAILED );
  825. return Win32Err;
  826. }
  827. typedef DWORD (*NetEnumCompName) (
  828. LPCWSTR Server,
  829. NET_COMPUTER_NAME_TYPE NameType,
  830. ULONG Reserved,
  831. PDWORD EntryCount,
  832. LPWSTR **ComputerNames
  833. );
  834. NetEnumCompName pNetEnumCompName = NULL;
  835. pNetEnumCompName = ( NetEnumCompName ) GetProcAddress ( hm, "NetEnumerateComputerNames" );
  836. if ( !pNetEnumCompName )
  837. {
  838. NetDompDisplayMessage ( MSG_WRONG_NETAPI32_DLL );
  839. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  840. return Win32Err;
  841. }
  842. Win32Err = pNetEnumCompName (pwzMachine,
  843. NetAllComputerNames,
  844. 0,
  845. &dwCount,
  846. &rgpwzNames);
  847. if ( hm )
  848. {
  849. FreeLibrary ( hm );
  850. }
  851. if (NO_ERROR != Win32Err)
  852. {
  853. NetDompDisplayErrorMessage(Win32Err);
  854. return Win32Err;
  855. }
  856. const WCHAR wzHost[] = L"HOST/";
  857. // NOTICE-2002/03/04-ericb - SecurityPush: getting length of a static string, use
  858. // sizeof(wzHost)/sizeof(WCHAR) - 1 rather than wcslen(). (done)
  859. const size_t cchHost = sizeof(wzHost) / sizeof(WCHAR) - 1;
  860. bool fDnsFailed = false, fSpnFailed = false;
  861. size_t cchName = 0;
  862. HRESULT hr = NULL;
  863. for (DWORD i = 0; i < dwCount; i++)
  864. {
  865. ASSERT(rgpwzNames[i]);
  866. LOG_VERBOSE((MSG_COMPNAME_VERIFY_START, rgpwzNames[i]));
  867. //
  868. // Check the DNS registration first.
  869. //
  870. PDNS_RECORD rgARecs = NULL;
  871. Win32Err = DnsQuery_W(rgpwzNames[i],
  872. DNS_TYPE_A,
  873. DNS_QUERY_BYPASS_CACHE,
  874. NULL,
  875. &rgARecs,
  876. NULL);
  877. if (ERROR_SUCCESS != Win32Err || !rgARecs)
  878. {
  879. Win32Err = DnsQuery_W(rgpwzNames[i],
  880. DNS_TYPE_AAAA,
  881. DNS_QUERY_BYPASS_CACHE,
  882. NULL,
  883. &rgARecs,
  884. NULL);
  885. }
  886. if (ERROR_SUCCESS != Win32Err || !rgARecs)
  887. {
  888. NetDompDisplayMessageAndError(MSG_COMPNAME_DNS_FAILED,
  889. Win32Err,
  890. rgpwzNames[i]);
  891. fDnsFailed = true;
  892. }
  893. else
  894. {
  895. // To ensure that netdom.exe runs on Win2K, we do
  896. // dynamic loading of the following API that are available
  897. // only in later versions of dnsapi.dll
  898. hm2 = LoadLibrary ( L"dnsapi.dll" );
  899. if ( !hm )
  900. {
  901. Win32Err = GetLastError ();
  902. NetDompDisplayMessage ( MSG_DNSAPI_LOAD_FAILED );
  903. return Win32Err;
  904. }
  905. typedef void ( *DnsFreeType ) ( PVOID pData, DNS_FREE_TYPE FreeType );
  906. DnsFreeType pDnsFree = NULL;
  907. pDnsFree = ( DnsFreeType ) GetProcAddress ( hm2, "DnsFree" );
  908. if ( !pDnsFree )
  909. {
  910. NetDompDisplayMessage ( MSG_WRONG_DNSAPI_DLL );
  911. Win32Err = ERROR_CALL_NOT_IMPLEMENTED;
  912. return Win32Err;
  913. }
  914. pDnsFree ( rgARecs, DnsFreeRecordListDeep );
  915. if ( hm2 )
  916. {
  917. FreeLibrary ( hm2 );
  918. }
  919. }
  920. //
  921. // Check the SPN registration. Only checking the Host SPN.
  922. //
  923. bool fFound = false;
  924. size_t cchSPN = 0;
  925. if (rgwzSPNs)
  926. {
  927. for (int j = 0; rgwzSPNs[j]; j++)
  928. {
  929. // NOTICE-2002/03/04-ericb - SecurityPush: use StringCchLength here. (fixed shasan 4/15/02)
  930. hr = StringCchLength ( rgwzSPNs[j], DNS_MAX_NAME_LENGTH + cchHost + 1, &cchSPN );
  931. if ( !SUCCEEDED (hr) )
  932. {
  933. NetDompDisplayErrorMessage ( HRESULT_CODE ( hr ) );
  934. break;
  935. }
  936. if ( cchSPN < cchHost)
  937. {
  938. continue;
  939. }
  940. // NOTICE-2002/03/04-ericb - SecurityPush: length already checked..
  941. if (_wcsnicmp(wzHost, rgwzSPNs[j], cchHost) != 0)
  942. {
  943. continue;
  944. }
  945. PWSTR pwz = rgwzSPNs[j] + cchHost;
  946. // NOTICE-2002/03/04-ericb - SecurityPush: use _wcsnicmp here after calling
  947. // StringCchLength on pwz. (fixed shasan 4/15/02)
  948. hr = StringCchLengthW ( pwz, DNS_MAX_NAME_LENGTH + 1, &cchName );
  949. if ( !SUCCEEDED (hr) )
  950. {
  951. NetDompDisplayErrorMessage ( HRESULT_CODE ( hr ) );
  952. break;
  953. }
  954. if (_wcsicmp(rgpwzNames[i], pwz) == 0)
  955. {
  956. fFound = true;
  957. break;
  958. }
  959. }
  960. if (!fFound)
  961. {
  962. NetDompDisplayMessage(MSG_COMPNAME_SPN_NOT_FOUND, rgpwzNames[i]);
  963. fSpnFailed = true;
  964. }
  965. }
  966. else
  967. {
  968. fSpnFailed = true;
  969. }
  970. }
  971. if (!fDnsFailed)
  972. {
  973. NetDompDisplayMessage(MSG_COMPNAME_VERIFY_DNS_OK);
  974. }
  975. if (!fSpnFailed)
  976. {
  977. NetDompDisplayMessage(MSG_COMPNAME_VERIFY_SPN_OK);
  978. }
  979. if (rgpwzNames)
  980. {
  981. NetApiBufferFree(rgpwzNames);
  982. }
  983. if (rgwzSPNs)
  984. {
  985. ldap_value_free(rgwzSPNs);
  986. }
  987. return NO_ERROR;
  988. }