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.

1367 lines
36 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1998 - 2001
  4. Module Name:
  5. ndutil.cxx
  6. Abstract:
  7. Common functions to be shared between the netdom features
  8. --*/
  9. #include "pch.h"
  10. #pragma hdrstop
  11. #include <netdom.h>
  12. bool
  13. CmdFlagOn(ARG_RECORD * rgNetDomArgs, NETDOM_ARG_ENUM eArgIndex)
  14. {
  15. if (!rgNetDomArgs || eArgIndex >= eArgEnd)
  16. {
  17. ASSERT(FALSE);
  18. return false;
  19. }
  20. return rgNetDomArgs[eArgIndex].bDefined == TRUE;
  21. }
  22. BOOL
  23. NetDompGetUserConfirmation(
  24. IN DWORD PromptResId,
  25. IN PWSTR pwzName
  26. )
  27. /*++
  28. Routine Description:
  29. Prompt the user to press the y or n button.
  30. Arguments:
  31. PrompteResId - Resource ID of the prompt to be displayed
  32. pwzName - Optional name to put in the prompt string
  33. Return Value:
  34. TRUE if the user pressed y or Y, FALSE otherwise.
  35. --*/
  36. {
  37. if (!PromptResId)
  38. {
  39. ASSERT(FALSE);
  40. return IDNO;
  41. }
  42. WCHAR wzBuf[MAX_PATH+1], wzTitle[31];
  43. PWSTR pwzMsg = NULL;
  44. int nRet = 0, cchPrompt = 0;
  45. cchPrompt = LoadString(g_hInstance, PromptResId, wzBuf, MAX_PATH);
  46. if (!cchPrompt)
  47. {
  48. printf("LoadString FAILED!\n");
  49. return FALSE;
  50. }
  51. if (!LoadString(g_hInstance, IDS_PROMPT_TITLE, wzTitle, 30))
  52. {
  53. printf("LoadString FAILED!\n");
  54. return FALSE;
  55. }
  56. if (pwzName)
  57. {
  58. size_t cchBuf = cchPrompt + wcslen(pwzName) + 1;
  59. if (NetApiBufferAllocate(cchBuf * sizeof(WCHAR),
  60. (PVOID*)&pwzMsg) != ERROR_SUCCESS)
  61. {
  62. printf("Memory allocation FAILED!\n");
  63. return FALSE;
  64. }
  65. HRESULT hr = StringCchPrintf(pwzMsg, cchBuf, wzBuf, pwzName);
  66. if (FAILED(hr))
  67. {
  68. ASSERT(FALSE);
  69. printf("NetDompGetUserConfirmation assertion failed!\n");
  70. return FALSE;
  71. }
  72. }
  73. else
  74. {
  75. pwzMsg = wzBuf;
  76. }
  77. nRet = MessageBox(GetFocus(),
  78. pwzMsg,
  79. wzTitle,
  80. MB_YESNO |
  81. MB_ICONEXCLAMATION |
  82. MB_DEFAULT_DESKTOP_ONLY |
  83. MB_SETFOREGROUND |
  84. MB_DEFBUTTON2);
  85. if (pwzName)
  86. {
  87. NetApiBufferFree(pwzMsg);
  88. }
  89. return (nRet == IDYES);
  90. }
  91. DWORD
  92. NetDompGetPasswordString(
  93. DWORD PromptResId,
  94. PWSTR Buffer,
  95. ULONG BufferLength
  96. )
  97. /*++
  98. Routine Description:
  99. This function will get the password string for an account object. It reads it from
  100. the user input
  101. Arguments:
  102. PromptResId - Resource ID of the prompt to be displayed
  103. Buffer - The buffer in which to return the password
  104. BufferLength - Length of the buffer (in characters)
  105. Return Value:
  106. ERROR_SUCCESS - The call succeeded
  107. NERR_BufTooSmall - The password entered was larger than would fit in the buffer
  108. --*/
  109. {
  110. ULONG Win32Err = ERROR_SUCCESS;
  111. DWORD CurrentMode, Read = 0;
  112. HANDLE InputHandle = GetStdHandle( STD_INPUT_HANDLE );
  113. PWSTR TempBuf = NULL;
  114. // Display the password prompt, if specified
  115. if ( PromptResId != 0 )
  116. {
  117. NetDompDisplayMessage( PromptResId );
  118. }
  119. BufferLength -= 1; /* make space for null terminator */
  120. // If input is from console, turn off echo
  121. if ( FileIsConsole ( InputHandle ) )
  122. {
  123. if (!GetConsoleMode( InputHandle, &CurrentMode ) )
  124. {
  125. return GetLastError();
  126. }
  127. SetConsoleMode( InputHandle, ~( ENABLE_ECHO_INPUT ) & CurrentMode );
  128. }
  129. // Read the password and copy to Buffer
  130. Read = ReadFromIn ( &TempBuf );
  131. if ( (Read == -1) || ( (Read + 1) > BufferLength ) )
  132. {
  133. Win32Err = NERR_BufTooSmall;
  134. }
  135. else
  136. {
  137. HRESULT hr = StringCchCopy ( Buffer, Read + 1, TempBuf );
  138. if ( FAILED (hr) )
  139. {
  140. Win32Err = NERR_BufTooSmall;
  141. }
  142. }
  143. if ( TempBuf )
  144. {
  145. LocalFree ( TempBuf );
  146. }
  147. // Restore console echo setting
  148. if ( FileIsConsole ( InputHandle ) )
  149. {
  150. SetConsoleMode( InputHandle, CurrentMode );
  151. }
  152. // Clear the line for the next prompt
  153. if ( PromptResId ) {
  154. printf( "\n" );
  155. }
  156. return( Win32Err );
  157. }
  158. DWORD
  159. NetDompGetDomainForOperation(ARG_RECORD * rgNetDomArgs,
  160. PWSTR Server OPTIONAL,
  161. BOOL CanDefaultToCurrent,
  162. PWSTR *DomainName)
  163. /*++
  164. Routine Description:
  165. This function will get name of the domain for the current operation. It does this
  166. by parsing the command line parameters. If no argument is found, it uses the default
  167. domain for that machine
  168. Arguments:
  169. Args - List of arguments, can be NULL if CanDefaultToCurrent is true
  170. Server - Optional name of servre for which we wish to have the default domain
  171. CanDefaultToCurrent - if TRUE and the domain name not specified on the command line,
  172. use the current domain for the specified machine
  173. DomainName - Where the domain name is returned. Freed via NetApiBufferFree().
  174. Return Value:
  175. ERROR_SUCCESS - The call succeeded
  176. ERROR_INVALID_PARAMETER - The domain name was not specified and it was requried
  177. --*/
  178. {
  179. if (!DomainName)
  180. {
  181. ASSERT(DomainName);
  182. return ERROR_INVALID_PARAMETER;
  183. }
  184. DWORD Win32Err = ERROR_SUCCESS;
  185. ULONG i;
  186. NETSETUP_JOIN_STATUS JoinStatus;
  187. *DomainName = NULL;
  188. //
  189. // See the name is specifed
  190. //
  191. if (rgNetDomArgs && CmdFlagOn(rgNetDomArgs, eCommDomain)) {
  192. Win32Err = NetDompGetArgumentString(rgNetDomArgs,
  193. eCommDomain,
  194. DomainName);
  195. }
  196. //
  197. // If so, convert it
  198. //
  199. if ( Win32Err == ERROR_SUCCESS || CanDefaultToCurrent) {
  200. if ( *DomainName == NULL ) {
  201. if ( CanDefaultToCurrent ) {
  202. //
  203. // See if we can use the current domain
  204. //
  205. Win32Err = NetGetJoinInformation( Server,
  206. DomainName,
  207. &JoinStatus );
  208. if ( Win32Err == ERROR_SUCCESS ) {
  209. if ( JoinStatus != NetSetupDomainName ) {
  210. NetApiBufferFree( *DomainName );
  211. NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
  212. Win32Err = ERROR_INVALID_PARAMETER;
  213. }
  214. }
  215. else if (RPC_S_PROCNUM_OUT_OF_RANGE == Win32Err)
  216. {
  217. // Must be an NT4 or earlier machine.
  218. //
  219. WKSTA_INFO_100 * pWkstaInfo = NULL;
  220. Win32Err = NetWkstaGetInfo(Server, 100, (LPBYTE*)&pWkstaInfo);
  221. if (NERR_Success == Win32Err)
  222. {
  223. if (!pWkstaInfo->wki100_langroup)
  224. {
  225. return ERROR_INVALID_PARAMETER;
  226. }
  227. Win32Err = NetApiBufferAllocate(
  228. (wcslen(pWkstaInfo->wki100_langroup) + 1) * sizeof(WCHAR),
  229. (PVOID*)DomainName);
  230. if (ERROR_SUCCESS == Win32Err)
  231. {
  232. // NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
  233. wcscpy(*DomainName, pWkstaInfo->wki100_langroup);
  234. }
  235. NetApiBufferFree(pWkstaInfo);
  236. }
  237. }
  238. } else {
  239. NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
  240. Win32Err = ERROR_INVALID_PARAMETER;
  241. }
  242. }
  243. } else {
  244. //
  245. // Hmm, guess we don't have what we need
  246. //
  247. NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
  248. Win32Err = ERROR_INVALID_PARAMETER;
  249. }
  250. return( Win32Err );
  251. }
  252. typedef struct _ND5_USER_FLAG_MAP {
  253. NETDOM_ARG_ENUM UserFlag;
  254. NETDOM_ARG_ENUM PasswordFlag;
  255. ULONG PasswordPromptId;
  256. } ND5_USER_FLAG_MAP, *PND5_USER_FLAG_MAP;
  257. DWORD
  258. NetDompGetUserAndPasswordForOperation(ARG_RECORD * rgNetDomArgs,
  259. NETDOM_ARG_ENUM eUserType,
  260. PWSTR DefaultDomain,
  261. PND5_AUTH_INFO AuthIdent)
  262. /*++
  263. Routine Description:
  264. This function will get the user name and password from the command line, as required. If
  265. necessary, the function will cause a prompt for the password to be displayed and processed
  266. Arguments:
  267. eUserType - Whether to prompt for object or domain user
  268. DefaultDomain - Default domain for the operation, in case a relative name was supplied
  269. AuthIdent - Structure to initialize with the user name and password
  270. Return Value:
  271. ERROR_SUCCESS - The call succeeded
  272. ERROR_INVALID_PARAMETER - The domain name was not specified and it was requried
  273. --*/
  274. {
  275. DWORD Win32Err = ERROR_SUCCESS;
  276. PWSTR SpecifiedUser = NULL, SpecifiedPassword = NULL;
  277. PWSTR pwzUserWoDomain = NULL, pwzUsersDomain = NULL;
  278. size_t cchDomain = 0;
  279. ND5_USER_FLAG_MAP FlagMap[] = {
  280. { eCommUserNameD, eCommPasswordD, MSG_NETDOM5_USERD_PWD },
  281. { eCommUserNameO, eCommPasswordO, MSG_NETDOM5_USERO_PWD },
  282. { eMoveUserNameF, eMovePasswordF, MSG_NETDOM5_USERF_PWD },
  283. };
  284. if (!rgNetDomArgs || !AuthIdent)
  285. {
  286. ASSERT(rgNetDomArgs);
  287. ASSERT(AuthIdent);
  288. return ERROR_INVALID_PARAMETER;
  289. }
  290. //
  291. // Return success if the name wasn't supplied
  292. //
  293. if (!CmdFlagOn(rgNetDomArgs, eUserType))
  294. {
  295. return(ERROR_SUCCESS);
  296. }
  297. // NOTICE-2002/02/27-ericb - SecurityPush: zeroing the structure pointed to by AuthIdent.
  298. RtlZeroMemory( AuthIdent, sizeof( ND5_AUTH_INFO ) );
  299. //
  300. // See if the name is specifed
  301. //
  302. SpecifiedUser = rgNetDomArgs[eUserType].strValue;
  303. //
  304. // If so, use it
  305. //
  306. if ( SpecifiedUser ) {
  307. size_t cchUser = 0;
  308. HRESULT hr = StringCchLength(SpecifiedUser, MAXSTR, &cchUser);
  309. if (FAILED(hr))
  310. {
  311. ASSERT(FALSE);
  312. return HRESULT_CODE(hr);
  313. }
  314. if ( wcschr( SpecifiedUser, L'\\' ) || wcschr( SpecifiedUser, L'@' ) ) {
  315. Win32Err = NetApiBufferAllocate((cchUser + 1) * sizeof(WCHAR),
  316. (PVOID*)&(AuthIdent->User));
  317. if ( Win32Err == ERROR_SUCCESS && AuthIdent->User) {
  318. // NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
  319. wcscpy(AuthIdent->User, SpecifiedUser);
  320. }
  321. else
  322. {
  323. return ERROR_NOT_ENOUGH_MEMORY;
  324. }
  325. } else {
  326. if (cchUser < 1) {
  327. Win32Err = NetApiBufferAllocate(sizeof(WCHAR), (PVOID*)&(AuthIdent->User));
  328. if (ERROR_SUCCESS == Win32Err && AuthIdent->User) {
  329. *(AuthIdent->User) = L'\0';
  330. }
  331. else
  332. {
  333. return ERROR_NOT_ENOUGH_MEMORY;
  334. }
  335. } else {
  336. if ( !DefaultDomain ) {
  337. return ERROR_INVALID_PARAMETER;
  338. } else {
  339. hr = StringCchLength(DefaultDomain, MAXSTR, &cchDomain);
  340. if (FAILED(hr))
  341. {
  342. ASSERT(FALSE);
  343. return HRESULT_CODE(hr);
  344. }
  345. size_t cchLength = cchDomain + 1 + cchUser + 1;
  346. Win32Err = NetApiBufferAllocate((cchLength + 1) * sizeof(WCHAR),
  347. (PVOID*)&(AuthIdent->User));
  348. if ( Win32Err == ERROR_SUCCESS ) {
  349. // NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
  350. wcscpy( AuthIdent->User, DefaultDomain );
  351. wcscat( AuthIdent->User, L"\\" );
  352. wcscat( AuthIdent->User, SpecifiedUser);
  353. }
  354. }
  355. }
  356. }
  357. if (pwzUserWoDomain = wcschr(AuthIdent->User, L'\\')) {
  358. cchDomain = pwzUserWoDomain - AuthIdent->User;
  359. Win32Err = NetApiBufferAllocate((cchDomain + 1) * sizeof(WCHAR),
  360. (PVOID*)&(AuthIdent->pwzUsersDomain));
  361. if ( Win32Err == ERROR_SUCCESS ) {
  362. wcsncpy(AuthIdent->pwzUsersDomain, AuthIdent->User, cchDomain);
  363. AuthIdent->pwzUsersDomain[cchDomain] = L'\0';
  364. pwzUserWoDomain++;
  365. if (pwzUserWoDomain) {
  366. Win32Err = NetApiBufferAllocate((wcslen(pwzUserWoDomain) + 1) * sizeof(WCHAR),
  367. (PVOID*)&(AuthIdent->pwzUserWoDomain));
  368. if ( Win32Err == ERROR_SUCCESS ) {
  369. // NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
  370. wcscpy(AuthIdent->pwzUserWoDomain, pwzUserWoDomain);
  371. }
  372. }
  373. }
  374. }
  375. } else {
  376. Win32Err = ERROR_INVALID_PARAMETER;
  377. }
  378. //
  379. // Now, the password if it exists
  380. //
  381. if ( Win32Err == ERROR_SUCCESS ) {
  382. NETDOM_ARG_ENUM ePasswordArg;
  383. ULONG PasswordPrompt = 0;
  384. for (ULONG i = 0; i < sizeof( FlagMap ) / sizeof( ND5_USER_FLAG_MAP ); i++ ) {
  385. if ( eUserType == FlagMap[ i ].UserFlag ) {
  386. ePasswordArg = FlagMap[ i ].PasswordFlag;
  387. PasswordPrompt = FlagMap[ i ].PasswordPromptId;
  388. break;
  389. }
  390. }
  391. ASSERT( ePasswordArg != eArgBegin );
  392. //
  393. // Now, get the password
  394. //
  395. SpecifiedPassword = rgNetDomArgs[ePasswordArg].strValue;
  396. if (SpecifiedPassword)
  397. {
  398. size_t cchPw = 0;
  399. HRESULT hr = StringCchLength(SpecifiedPassword, MAXSTR, &cchPw);
  400. if (FAILED(hr))
  401. {
  402. ASSERT(FALSE);
  403. return HRESULT_CODE(hr);
  404. }
  405. if (1 == cchPw && L'*' == *SpecifiedPassword) {
  406. //
  407. // Prompt for it...
  408. //
  409. Win32Err = NetApiBufferAllocate( ( PWLEN + 1 ) * sizeof( WCHAR ),
  410. (PVOID*)&( AuthIdent->Password ) );
  411. if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
  412. Win32Err = NetDompGetPasswordString( PasswordPrompt,
  413. AuthIdent->Password,
  414. PWLEN );
  415. }
  416. else
  417. {
  418. return ERROR_NOT_ENOUGH_MEMORY;
  419. }
  420. } else {
  421. //
  422. // It's a password, so go with it..
  423. //
  424. Win32Err = NetApiBufferAllocate((cchPw + 1) * sizeof(WCHAR),
  425. (PVOID*)&(AuthIdent->Password));
  426. if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
  427. // NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
  428. wcscpy(AuthIdent->Password, SpecifiedPassword);
  429. }
  430. else
  431. {
  432. return ERROR_NOT_ENOUGH_MEMORY;
  433. }
  434. }
  435. }
  436. // Password not specified, create an empty one.
  437. //
  438. if( AuthIdent->Password == NULL )
  439. {
  440. Win32Err = NetApiBufferAllocate(sizeof(WCHAR), (PVOID*)&(AuthIdent->Password));
  441. if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
  442. *AuthIdent->Password = L'\0';
  443. }
  444. else
  445. {
  446. return ERROR_NOT_ENOUGH_MEMORY;
  447. }
  448. }
  449. }
  450. if ( Win32Err != ERROR_SUCCESS ) {
  451. NetDompFreeAuthIdent( AuthIdent );
  452. }
  453. return( Win32Err );
  454. }
  455. DWORD
  456. NetDompGetArgumentString(ARG_RECORD * rgNetDomArgs,
  457. NETDOM_ARG_ENUM eArgToGet,
  458. PWSTR *ArgString)
  459. /*++
  460. Routine Description:
  461. This function will get the string associated with a command line parameter, if it exists.
  462. Arguments:
  463. Args - List of arguments
  464. ArgToGet - Argument to get the string for
  465. ArgString - Where the arg string is returned if found. Freed via NetApiBufferFree
  466. Return Value:
  467. ERROR_SUCCESS - The call succeeded
  468. --*/
  469. {
  470. if (!rgNetDomArgs || !ArgString)
  471. {
  472. ASSERT(rgNetDomArgs);
  473. ASSERT(ArgString);
  474. return ERROR_INVALID_PARAMETER;
  475. }
  476. DWORD Win32Err = ERROR_SUCCESS;
  477. *ArgString = NULL;
  478. if (eArgToGet >= eArgEnd)
  479. {
  480. return ERROR_INVALID_PARAMETER;
  481. }
  482. if (!rgNetDomArgs[eArgToGet].strValue)
  483. {
  484. // Allow null strings.
  485. //
  486. return ERROR_SUCCESS;
  487. }
  488. // NOTICE-2002/02/27-ericb - SecurityPush: rgNetDomArgs strValue tested for
  489. // non-null above. If non-null, the string is assigned by ParseCmd.
  490. Win32Err = NetApiBufferAllocate((wcslen(rgNetDomArgs[eArgToGet].strValue) + 1) *
  491. sizeof(WCHAR),
  492. (PVOID*)ArgString);
  493. if ( Win32Err == ERROR_SUCCESS ) {
  494. wcscpy(*ArgString, rgNetDomArgs[eArgToGet].strValue);
  495. }
  496. return( Win32Err );
  497. }
  498. BOOL
  499. NetDompGetArgumentBoolean(ARG_RECORD * rgNetDomArgs,
  500. NETDOM_ARG_ENUM eArgToGet)
  501. /*++
  502. Routine Description:
  503. This function will determine whether the given command line argument was present on the
  504. command line or not.
  505. Arguments:
  506. Args - List of arguments
  507. ArgToGet - Argument to get the string for
  508. Return Value:
  509. TRUE - The argument was found
  510. FALSE - The argument wasn't found
  511. --*/
  512. {
  513. if (!rgNetDomArgs)
  514. {
  515. ASSERT(FALSE);
  516. return FALSE;
  517. }
  518. if (eArgToGet >= eArgEnd)
  519. {
  520. ASSERT(FALSE);
  521. return FALSE;
  522. }
  523. return rgNetDomArgs[eArgToGet].bDefined;
  524. }
  525. DWORD
  526. NetDompControlService(
  527. IN PWSTR Server,
  528. IN PWSTR Service,
  529. IN DWORD ServiceOptions
  530. )
  531. /*++
  532. Routine Description:
  533. This function will control the given service on the given machine.
  534. Arguments:
  535. Server - Machine on which to control the service
  536. Service - Service to control
  537. ServiceOptions - What do with the service. Uses standard SvcCtrl bits
  538. Return Value:
  539. ERROR_SUCCESS - The operation succeeded
  540. --*/
  541. {
  542. DWORD Win32Err = ERROR_SUCCESS;
  543. SC_HANDLE ScMgr, Svc;
  544. DWORD OpenMode;
  545. //
  546. // Open the service control manager
  547. //
  548. ScMgr = OpenSCManager( Server,
  549. SERVICES_ACTIVE_DATABASE,
  550. GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE );
  551. if ( ScMgr == NULL ) {
  552. Win32Err = GetLastError();
  553. } else {
  554. //
  555. // Set the open mode
  556. //
  557. if( FLAG_ON( ServiceOptions, SERVICE_STOP ) ) {
  558. LOG_VERBOSE(( MSG_VERBOSE_SVC_STOP, Service ));
  559. OpenMode = SERVICE_STOP |
  560. SERVICE_ENUMERATE_DEPENDENTS |
  561. SERVICE_QUERY_STATUS |
  562. SERVICE_CHANGE_CONFIG;
  563. } else if( FLAG_ON( ServiceOptions, SERVICE_START ) ) {
  564. LOG_VERBOSE(( MSG_VERBOSE_SVC_START, Service ));
  565. OpenMode = SERVICE_START;
  566. } else {
  567. LOG_VERBOSE(( MSG_VERBOSE_SVC_CONFIG, Service ));
  568. OpenMode = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG;
  569. }
  570. if ( FLAG_ON( ServiceOptions, SERVICE_STOP ) ) {
  571. Win32Err = NetpStopService( Service,
  572. ScMgr );
  573. }
  574. if ( Win32Err == ERROR_SUCCESS ) {
  575. //
  576. // Open the service
  577. //
  578. Svc = OpenService( ScMgr,
  579. Service,
  580. OpenMode );
  581. if ( Svc == NULL ) {
  582. Win32Err = GetLastError();
  583. } else {
  584. if ( FLAG_ON( ServiceOptions, SERVICE_START ) ) {
  585. //
  586. // See about changing its state
  587. //
  588. if ( StartService( Svc, 0, NULL ) == FALSE ) {
  589. Win32Err = GetLastError();
  590. if ( Win32Err == ERROR_SERVICE_ALREADY_RUNNING ) {
  591. Win32Err = ERROR_SUCCESS;
  592. }
  593. }
  594. } else {
  595. if ( ChangeServiceConfig( Svc,
  596. SERVICE_NO_CHANGE,
  597. ServiceOptions,
  598. SERVICE_NO_CHANGE,
  599. NULL, NULL, 0, NULL, NULL, NULL,
  600. NULL ) == FALSE ) {
  601. Win32Err = GetLastError();
  602. }
  603. }
  604. CloseServiceHandle( Svc );
  605. }
  606. }
  607. CloseServiceHandle( ScMgr );
  608. }
  609. return( Win32Err );
  610. }
  611. DWORD
  612. EnablePrivilege( PCWSTR PrivilegeName )
  613. {
  614. HANDLE hToken; // handle to process token
  615. TOKEN_PRIVILEGES tkp; // pointer to token structure
  616. // Get the current process token handle so we can get the specified
  617. // privilege.
  618. if (!OpenProcessToken( GetCurrentProcess(),
  619. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  620. &hToken))
  621. return GetLastError();
  622. // Get the LUID for the specified privilege.
  623. if (!LookupPrivilegeValue(NULL, PrivilegeName,
  624. &tkp.Privileges[0].Luid))
  625. return GetLastError();
  626. tkp.PrivilegeCount = 1; // one privilege to set
  627. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  628. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
  629. (PTOKEN_PRIVILEGES) NULL, 0);
  630. // Cannot test the return value of AdjustTokenPrivileges.
  631. CloseHandle(hToken);
  632. if ( GetLastError() != ERROR_SUCCESS )
  633. return GetLastError();
  634. return ERROR_SUCCESS;
  635. }
  636. DWORD
  637. NetDompRestartAsRequired(ARG_RECORD * rgNetDomArgs,
  638. PWSTR Machine,
  639. PWSTR User,
  640. DWORD PreliminaryStatus,
  641. DWORD MsgID)
  642. /*++
  643. Routine Description:
  644. This function will (remotely) shutdown a machine if the command line arguments indicate
  645. that it should
  646. Arguments:
  647. Args - List of arguments
  648. ArgCount - Number of arguments in the list
  649. Machine - Machine which should be restarted
  650. User - The user who connected to the machine, doing whatever operation needed a reboot.
  651. If NULL is specified, the current user is used.
  652. PreliminaryStatus - Status from the operation. If it's not SUCCESS, the restart isn't
  653. attempted
  654. MsgID - Message ID of string to display on system being shut down.
  655. Return Value:
  656. ERROR_SUCCESS - The operation succeeded
  657. --*/
  658. {
  659. if (!rgNetDomArgs || !Machine || !MsgID)
  660. {
  661. ASSERT(rgNetDomArgs);
  662. ASSERT(Machine);
  663. ASSERT(MsgID);
  664. return ERROR_INVALID_PARAMETER;
  665. }
  666. DWORD Win32Err = PreliminaryStatus;
  667. BOOL Restart = FALSE;
  668. PWSTR UserName = NULL, DisplayString = NULL, Delay, End;
  669. ULONG Length = 0, RestartDelay = 30;
  670. if ( PreliminaryStatus != ERROR_SUCCESS ) {
  671. return( PreliminaryStatus );
  672. }
  673. //
  674. // See if the argument is specified
  675. //
  676. Restart = NetDompGetArgumentBoolean(rgNetDomArgs,
  677. eCommRestart);
  678. if ( Restart ) {
  679. //
  680. // Get the delay time
  681. //
  682. RestartDelay = rgNetDomArgs[eCommRestart].nValue;
  683. //
  684. // Get the user display name
  685. //
  686. if ( User ) {
  687. UserName = User;
  688. } else {
  689. // NOTICE-2002/02/27-ericb - SecurityPush: The first call to GetUserName returns
  690. // the length required which is used to allocate the buffer.
  691. Length = 0;
  692. GetUserName( UserName, &Length );
  693. Win32Err = NetApiBufferAllocate( Length * sizeof( WCHAR ),
  694. (PVOID*)&UserName );
  695. if ( Win32Err == ERROR_SUCCESS ) {
  696. if ( !GetUserName( UserName, &Length ) ) {
  697. Win32Err = GetLastError();
  698. }
  699. }
  700. }
  701. //
  702. // Build the message to display, and schedule the shutdown
  703. //
  704. if ( Win32Err == ERROR_SUCCESS ) {
  705. // NOTICE-2002/02/27-ericb - SecurityPush: checked parameters at beginning
  706. // of the function.
  707. Length = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE |
  708. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  709. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  710. NULL,
  711. MsgID,
  712. 0,
  713. ( PWSTR )&DisplayString,
  714. 0,
  715. ( va_list * )&UserName );
  716. if ( Length == 0 ) {
  717. Win32Err = GetLastError();
  718. } else {
  719. LOG_VERBOSE(( MSG_VERBOSE_REBOOTING, Machine ));
  720. // NTRAID#NTBUG9-620218-2002/05/13-ericb
  721. DWORD dwReason = SHTDN_REASON_FLAG_PLANNED |
  722. SHTDN_REASON_MINOR_RECONFIG |
  723. SHTDN_REASON_MAJOR_OPERATINGSYSTEM;
  724. //If Machine is localMachine, Enable SE_SHUTDOWN_NAME privilege
  725. if( IsLocalMachine( Machine ) ){
  726. if( ( Win32Err = EnablePrivilege(SE_SHUTDOWN_NAME) ) == ERROR_SUCCESS ){
  727. if ( InitiateSystemShutdownEx(Machine,
  728. DisplayString,
  729. RestartDelay,
  730. TRUE,
  731. TRUE,
  732. dwReason) == FALSE ) {
  733. Win32Err = GetLastError();
  734. }
  735. }
  736. }
  737. else
  738. {
  739. if (InitiateSystemShutdownEx(Machine,
  740. DisplayString,
  741. RestartDelay,
  742. TRUE,
  743. TRUE,
  744. dwReason) == FALSE)
  745. {
  746. Win32Err = GetLastError();
  747. }
  748. if (RPC_S_PROCNUM_OUT_OF_RANGE == Win32Err)
  749. {
  750. // Machine must be running a pre-Win2k OS.
  751. //
  752. if (InitiateSystemShutdown(Machine,
  753. DisplayString,
  754. RestartDelay,
  755. TRUE,
  756. TRUE) == FALSE)
  757. {
  758. Win32Err = GetLastError();
  759. }
  760. else
  761. {
  762. Win32Err = NO_ERROR;
  763. }
  764. }
  765. }
  766. }
  767. }
  768. }
  769. if ( Win32Err != ERROR_SUCCESS ) {
  770. NetDompDisplayMessage( MSG_NO_RESTART );
  771. NetDompDisplayErrorMessage( Win32Err );
  772. }
  773. LocalFree( DisplayString );
  774. if ( UserName != User ) {
  775. NetApiBufferFree( UserName );
  776. }
  777. return( Win32Err );
  778. }
  779. DWORD
  780. NetDompCheckDomainMembership(
  781. IN PWSTR Server,
  782. IN PND5_AUTH_INFO AuthInfo,
  783. IN BOOL EstablishSessionIfRequried,
  784. IN OUT BOOL * DomainMember
  785. )
  786. /*++
  787. Routine Description:
  788. This function will determine whether the specified machine is a member of a domain or not
  789. Arguments:
  790. Server - Machine in question
  791. AuthInfo - User name and password used to connect to the machine if necessary
  792. EstablishSessionIfRequired - Establish an authenticated session to the machine if necessary
  793. DomainMember - Gets set to TRUE if the machine is a domain member. Otherwise, it's FALSE.
  794. Return Value:
  795. ERROR_SUCCESS - The operation succeeded
  796. --*/
  797. {
  798. DWORD Win32Err = ERROR_SUCCESS;
  799. NTSTATUS Status;
  800. LSA_HANDLE LsaHandle = NULL;
  801. PPOLICY_PRIMARY_DOMAIN_INFO PolicyPDI = NULL;
  802. OBJECT_ATTRIBUTES OA;
  803. UNICODE_STRING ServerU;
  804. *DomainMember = FALSE;
  805. //
  806. // Establish a session, if necessary
  807. //
  808. if ( Server && EstablishSessionIfRequried ) {
  809. LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Server ));
  810. Win32Err = NetpManageIPCConnect( Server,
  811. AuthInfo->User,
  812. AuthInfo->Password,
  813. NETSETUPP_CONNECT_IPC );
  814. }
  815. //
  816. // See if it's a domain member. Use the LSA apis, since this might be an
  817. // NT4 box.
  818. //
  819. if ( Win32Err == ERROR_SUCCESS ) {
  820. if ( Server ) {
  821. RtlInitUnicodeString( &ServerU, Server );
  822. }
  823. InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
  824. Status = LsaOpenPolicy( Server ? &ServerU : NULL,
  825. &OA,
  826. MAXIMUM_ALLOWED,
  827. &LsaHandle );
  828. if ( NT_SUCCESS( Status ) ) {
  829. Status = LsaQueryInformationPolicy( LsaHandle,
  830. PolicyPrimaryDomainInformation,
  831. ( PVOID * )&PolicyPDI );
  832. if ( NT_SUCCESS( Status ) ) {
  833. if ( PolicyPDI->Sid ) {
  834. *DomainMember = TRUE;
  835. }
  836. LsaFreeMemory( PolicyPDI );
  837. }
  838. LsaClose( LsaHandle );
  839. }
  840. Win32Err = RtlNtStatusToDosError( Status );
  841. }
  842. //
  843. // Tear down the session
  844. //
  845. if ( Server && EstablishSessionIfRequried ) {
  846. LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Server ));
  847. NetpManageIPCConnect( Server,
  848. AuthInfo->User,
  849. AuthInfo->Password,
  850. NETSETUPP_DISCONNECT_IPC );
  851. }
  852. return( Win32Err );
  853. }
  854. DWORD
  855. NetDompValidateSecondaryArguments(ARG_RECORD * rgNetDomArgs,
  856. NETDOM_ARG_ENUM eFirstValidParam, ...)
  857. //PND5_ARG Args,
  858. /*++
  859. Routine Description:
  860. This function will determine whether the supplied command line options are
  861. valid for this operation or not
  862. Return Value:
  863. ERROR_SUCCESS - The operation succeeded
  864. ERROR_INVALID_PARAMETER - A bad parameter was specified
  865. --*/
  866. {
  867. if (!rgNetDomArgs)
  868. {
  869. ASSERT(FALSE);
  870. return ERROR_INVALID_PARAMETER;
  871. }
  872. DWORD Win32Err = ERROR_SUCCESS;
  873. va_list ArgList;
  874. for (int i = eArgBegin; i < eArgEnd; i++)
  875. {
  876. if (rgNetDomArgs[i].bDefined)
  877. {
  878. int j = eFirstValidParam;
  879. bool fFound = false;
  880. va_start(ArgList, eFirstValidParam);
  881. while (j != eArgEnd)
  882. {
  883. if (i == j)
  884. {
  885. fFound = true;
  886. break;
  887. }
  888. j = va_arg(ArgList, int);
  889. }
  890. if (!fFound)
  891. {
  892. NetDompDisplayUnexpectedParameter(rgNetDomArgs[i].strArg1);
  893. return ERROR_INVALID_PARAMETER;
  894. }
  895. }
  896. }
  897. va_end(ArgList);
  898. return(Win32Err);
  899. }
  900. DWORD
  901. NetDompGenerateRandomPassword(
  902. IN PWSTR Buffer,
  903. IN ULONG Length
  904. )
  905. /*++
  906. Routine Description:
  907. This function will generate a random password of the specified length
  908. Arguments:
  909. Buffer - Place to put the randomly generated password
  910. Length - Length of the password (in characters) to generate
  911. Return Value:
  912. ERROR_SUCCESS - The operation succeeded
  913. --*/
  914. {
  915. DWORD Win32Err = ERROR_SUCCESS;
  916. HCRYPTPROV CryptProvider = 0;
  917. LARGE_INTEGER Time;
  918. ULONG Seed, i;
  919. UCHAR Filler;
  920. NtQuerySystemTime( &Time );
  921. Seed = ( ( PLONG )( &Time ) )[ 0 ] ^ ( ( PLONG )( &Time ) )[ 1 ];
  922. Filler = ( UCHAR )( RtlRandom( &Seed ) % ( 254 ) + 1 ); // Generate a fill character to use
  923. //
  924. // Generate a random password.
  925. //
  926. if ( CryptAcquireContext( &CryptProvider,
  927. NULL,
  928. NULL,
  929. PROV_RSA_FULL,
  930. CRYPT_VERIFYCONTEXT ) ) {
  931. if ( CryptGenRandom( CryptProvider,
  932. Length * sizeof( WCHAR ),
  933. ( LPBYTE )Buffer ) ) {
  934. Buffer[ Length ] = UNICODE_NULL;
  935. //
  936. // Make sure there are no NULL's in the middle of the list
  937. //
  938. for ( i = 0; i < Length; i++ ) {
  939. if ( Buffer[ i ] == UNICODE_NULL ) {
  940. Buffer[ i ] = Filler;
  941. }
  942. }
  943. } else {
  944. Win32Err = GetLastError();
  945. }
  946. CryptReleaseContext( CryptProvider, 0 );
  947. } else {
  948. Win32Err = GetLastError();
  949. }
  950. return( Win32Err );
  951. }
  952. VOID
  953. NetDompFreeAuthIdent(
  954. IN PND5_AUTH_INFO pAuthIdent
  955. )
  956. {
  957. if (pAuthIdent->User)
  958. NetApiBufferFree(pAuthIdent->User);
  959. if (pAuthIdent->Password)
  960. NetApiBufferFree(pAuthIdent->Password);
  961. if (pAuthIdent->pwzUserWoDomain)
  962. NetApiBufferFree(pAuthIdent->pwzUserWoDomain);
  963. if (pAuthIdent->pwzUsersDomain)
  964. NetApiBufferFree(pAuthIdent->pwzUsersDomain);
  965. }
  966. //+----------------------------------------------------------------------------
  967. //
  968. // Function: IsLocalMachine
  969. //
  970. // Synopsis: Checks if pwzMachine is the local machine.
  971. //
  972. // NOTICE-2002/08/01-shasan - Added code so that function can be used
  973. // even if the machine name passed in has \\ before it.
  974. //
  975. //-----------------------------------------------------------------------------
  976. BOOL
  977. IsLocalMachine(PCWSTR pwzMachine)
  978. {
  979. if (!pwzMachine)
  980. {
  981. ASSERT(false);
  982. return FALSE;
  983. }
  984. // Skip the initial \\ if present
  985. if ( wcslen (pwzMachine) >= 2 )
  986. {
  987. if ( *pwzMachine == L'\\' && * (pwzMachine + 1) == L'\\' )
  988. pwzMachine += 2;
  989. }
  990. // NOTICE-2002/02/27-ericb - SecurityPush: the SDK docs say the buffer
  991. // should be large enough for MAX_COMPUTERNAME_LENGTH + 1 characters but
  992. // don't explicitly say if the null is included in that count. So add one
  993. // more to make sure there is room for the null.
  994. WCHAR szLocalComputer[MAX_COMPUTERNAME_LENGTH + 2];
  995. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1 ;
  996. WCHAR szLocalComputerDns[DNS_MAX_NAME_LENGTH + 2];
  997. DWORD nDnsSize = DNS_MAX_NAME_LENGTH + 1;
  998. if (!GetComputerName(szLocalComputer, &nSize))
  999. return FALSE;
  1000. if (_wcsnicmp(pwzMachine, szLocalComputer, nSize) == 0)
  1001. return TRUE;
  1002. // The netBIOS name hasnt matched, check if the DNS name matches
  1003. if ( !GetComputerNameEx ( ComputerNamePhysicalDnsFullyQualified, szLocalComputerDns, &nDnsSize ) )
  1004. return FALSE;
  1005. if ( _wcsnicmp ( pwzMachine, szLocalComputerDns, nDnsSize ) == 0)
  1006. return TRUE;
  1007. else
  1008. return FALSE;
  1009. }