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.

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