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.

486 lines
11 KiB

  1. //Copyright (c) 1998 - 1999 Microsoft Corporation
  2. /*************************************************************************
  3. *
  4. * TSSHUTDN.C
  5. * This module is the TSSHUTDN utility code.
  6. *
  7. *
  8. *************************************************************************/
  9. #include <nt.h>
  10. #include <ntrtl.h>
  11. #include <nturtl.h>
  12. #include <ntlsa.h>
  13. #include <stdio.h>
  14. #include <wchar.h>
  15. #include <windows.h>
  16. #include <ntddkbd.h>
  17. #include <ntddmou.h>
  18. #include <winstaw.h>
  19. #include <stdlib.h>
  20. #include <utilsub.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. #include <locale.h>
  24. #include "tsshutdn.h"
  25. #include "printfoa.h"
  26. #define DEFAULT_WAIT_TIME 60
  27. #define DEFAULT_LOGOFF_DELAY 30
  28. #define MAX_MESSAGE_LENGTH 256
  29. WCHAR WSTime[MAX_IDS_LEN+2];
  30. WCHAR WDTime[MAX_IDS_LEN+2];
  31. USHORT help_flag = FALSE;
  32. USHORT v_flag = FALSE;
  33. USHORT RebootFlag = FALSE;
  34. USHORT PowerDownFlag = FALSE;
  35. USHORT FastFlag = FALSE;
  36. #if 0
  37. USHORT DumpFlag = FALSE;
  38. #endif
  39. HANDLE hServerName = SERVERNAME_CURRENT;
  40. WCHAR ServerName[MAX_IDS_LEN+1];
  41. TOKMAP ptm[] =
  42. {
  43. {TOKEN_TIME, TMFLAG_OPTIONAL, TMFORM_S_STRING, MAX_IDS_LEN, WSTime},
  44. {TOKEN_SERVER, TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN, ServerName},
  45. {TOKEN_DELAY, TMFLAG_OPTIONAL, TMFORM_STRING, MAX_IDS_LEN, WDTime},
  46. {TOKEN_HELP, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &help_flag},
  47. {TOKEN_VERBOSE, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &v_flag},
  48. {TOKEN_REBOOT, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &RebootFlag},
  49. {TOKEN_POWERDOWN,TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &PowerDownFlag},
  50. {TOKEN_FAST, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &FastFlag},
  51. #if 0
  52. {TOKEN_DUMP, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &DumpFlag},
  53. #endif
  54. {0, 0, 0, 0, 0}
  55. };
  56. /*
  57. * Local function prototypes.
  58. */
  59. void Usage( BOOLEAN bError );
  60. void NotifyUsers( ULONG WaitTime );
  61. void NotifyWinStations( PLOGONIDW, ULONG, ULONG );
  62. BOOLEAN CheckShutdownPrivilege();
  63. /*************************************************************************
  64. *
  65. * main
  66. * Main function and entry point of the TSSHUTDN utility.
  67. *
  68. * ENTRY:
  69. * argc - count of the command line arguments.
  70. * argv - vector of strings containing the command line arguments.
  71. *
  72. * EXIT
  73. * Nothing.
  74. *
  75. *************************************************************************/
  76. int __cdecl
  77. main(INT argc, CHAR **argv)
  78. {
  79. int rc, i;
  80. ULONG Error;
  81. WCHAR *CmdLine;
  82. WCHAR **argvW, *endptr;
  83. ULONG ShutdownFlags = WSD_SHUTDOWN | WSD_LOGOFF;
  84. ULONG WaitTime = DEFAULT_WAIT_TIME;
  85. ULONG LogoffDelay = DEFAULT_LOGOFF_DELAY;
  86. setlocale(LC_ALL, ".OCP");
  87. /*
  88. * Massage the command line.
  89. */
  90. argvW = MassageCommandLine((DWORD)argc);
  91. if (argvW == NULL) {
  92. ErrorPrintf(IDS_ERROR_MALLOC);
  93. return(FAILURE);
  94. }
  95. /*
  96. * parse the cmd line without parsing the program name (argc-1, argv+1)
  97. */
  98. WSTime[0] = L'\0';
  99. rc = ParseCommandLine(argc-1, argvW+1, ptm, 0);
  100. /*
  101. * Check for error from ParseCommandLine
  102. */
  103. if ( help_flag || (rc && !(rc & PARSE_FLAG_NO_PARMS)) ) {
  104. if ( !help_flag ) {
  105. Usage(TRUE);
  106. return(FAILURE);
  107. } else {
  108. Usage(FALSE);
  109. return(SUCCESS);
  110. }
  111. }
  112. // If no remote server was specified, then check if we are running under Terminal Server
  113. if ((!IsTokenPresent(ptm, TOKEN_SERVER) ) && (!AreWeRunningTerminalServices()))
  114. {
  115. ErrorPrintf(IDS_ERROR_NOT_TS);
  116. return(FAILURE);
  117. }
  118. /*
  119. * Open the specified server
  120. */
  121. if( ServerName[0] ) {
  122. hServerName = WinStationOpenServer( ServerName );
  123. if( hServerName == NULL ) {
  124. StringErrorPrintf(IDS_ERROR_SERVER,ServerName);
  125. PutStdErr( GetLastError(), 0 );
  126. return(FAILURE);
  127. }
  128. }
  129. // Make sure the user has the proper privilege
  130. // SM should really do the check
  131. /*
  132. if( !CheckShutdownPrivilege() ) {
  133. ErrorPrintf(IDS_ERROR_NO_RIGHTS);
  134. return(FAILURE);
  135. }
  136. */
  137. // Make sure its a number
  138. if ( WSTime[0] ) {
  139. if( !iswdigit(WSTime[0]) ) {
  140. StringErrorPrintf(IDS_ERROR_INVALID_TIME, WSTime);
  141. return(FAILURE);
  142. }
  143. WaitTime = wcstoul(WSTime, &endptr, 10);
  144. if ( *endptr ) {
  145. StringErrorPrintf(IDS_ERROR_INVALID_TIME, WSTime);
  146. return(FAILURE);
  147. }
  148. }
  149. // Make sure its a number
  150. if ( WDTime[0] ) {
  151. if( !iswdigit(WDTime[0]) ) {
  152. StringErrorPrintf(IDS_ERROR_INVALID_DELAY, WDTime);
  153. return(FAILURE);
  154. }
  155. LogoffDelay = wcstoul(WDTime, &endptr, 10);
  156. if ( *endptr ) {
  157. StringErrorPrintf(IDS_ERROR_INVALID_DELAY, WDTime);
  158. return(FAILURE);
  159. }
  160. }
  161. #if 0
  162. /*
  163. * If /dump option was specified, call NT function directly
  164. */
  165. if ( DumpFlag ) {
  166. NtShutdownSystem( ShutdownDump ); // will not return
  167. }
  168. #endif
  169. if( RebootFlag ) {
  170. ShutdownFlags |= WSD_REBOOT;
  171. }
  172. if( PowerDownFlag )
  173. ShutdownFlags |= WSD_POWEROFF;
  174. if( FastFlag ) {
  175. ShutdownFlags |= WSD_FASTREBOOT;
  176. ShutdownFlags &= ~WSD_LOGOFF;
  177. WaitTime = 0;
  178. }
  179. if( WaitTime ) {
  180. NotifyUsers( WaitTime );
  181. }
  182. /*
  183. * If necessary, force all WinStations to logoff
  184. */
  185. if ( ShutdownFlags & WSD_LOGOFF ) {
  186. Message( IDS_SHUTTING_DOWN, 0 );
  187. if ( !WinStationShutdownSystem( hServerName, WSD_LOGOFF ) ) {
  188. Error = GetLastError();
  189. ErrorPrintf( IDS_ERROR_SHUTDOWN_FAILED, Error );
  190. PutStdErr( Error, 0 );
  191. return( FAILURE );
  192. }
  193. Message( IDS_LOGOFF_USERS, 0);
  194. if (LogoffDelay) {
  195. NotifyUsers( LogoffDelay );
  196. }
  197. Message( IDS_SHUTDOWN_DONE, 0 );
  198. }
  199. /*
  200. * Inform user of impending reboot/poweroff
  201. */
  202. if ( ShutdownFlags & WSD_REBOOT ) {
  203. Message( IDS_SHUTDOWN_REBOOT, 0 );
  204. Sleep( 4000 );
  205. } else if ( ShutdownFlags & WSD_POWEROFF ) {
  206. Message( IDS_SHUTDOWN_POWERDOWN, 0 );
  207. Sleep( 4000 );
  208. }
  209. /*
  210. * Perform system shutdown, reboot, or poweroff, depending on flags
  211. */
  212. if( WinStationShutdownSystem( hServerName, ShutdownFlags & ~WSD_LOGOFF ) != ERROR_SUCCESS )
  213. {
  214. PutStdErr( GetLastError(), 0 );
  215. }
  216. // WinStationShutdownSystem is done asynchronously.
  217. // No way to know when the shudown is completed.
  218. //if ( !(ShutdownFlags & WSD_REBOOT) && !( ShutdownFlags & WSD_POWEROFF ) ) {
  219. // /*
  220. // * If we get here, shutdown is complete, all disks are write protected.
  221. // */
  222. // Message(IDS_SHUTDOWN_WRITEPROT, 0);
  223. //}
  224. return(SUCCESS);
  225. } /* main() */
  226. /*******************************************************************************
  227. *
  228. * Usage
  229. *
  230. * Output the usage message for this utility.
  231. *
  232. * ENTRY:
  233. * bError (input)
  234. * TRUE if the 'invalid parameter(s)' message should preceed the usage
  235. * message and the output go to stderr; FALSE for no such error
  236. * string and output goes to stdout.
  237. *
  238. * EXIT:
  239. *
  240. *
  241. ******************************************************************************/
  242. void
  243. Usage( BOOLEAN bError )
  244. {
  245. WCHAR sz1[1024];
  246. LoadString( NULL, IDS_USAGE, sz1, 1024 );
  247. if ( bError ) {
  248. ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS);
  249. fwprintf(stderr, sz1);
  250. } else {
  251. fwprintf(stdout,sz1);
  252. }
  253. } /* Usage() */
  254. /*****************************************************************************
  255. *
  256. * NotifyUsers
  257. *
  258. * Notify Users that the system is being shutdown
  259. *
  260. * ENTRY:
  261. * WaitTime (input)
  262. * Amount of time to give them to log off.
  263. *
  264. * EXIT:
  265. *
  266. ****************************************************************************/
  267. void
  268. NotifyUsers( ULONG WaitTime )
  269. {
  270. BOOLEAN Result;
  271. ULONG Entries;
  272. ULONG Error;
  273. PLOGONIDW ptr;
  274. //
  275. // Get all of the WinStations call the function to notify them.
  276. //
  277. if ( WinStationEnumerateW( hServerName, &ptr, &Entries ) ) {
  278. NotifyWinStations( ptr, Entries, WaitTime );
  279. WinStationFreeMemory(ptr);
  280. } else {
  281. Error = GetLastError();
  282. #if DBG
  283. printf("TSSHUTDN: Error emumerating Sessions %d\n",Error);
  284. #endif
  285. return;
  286. }
  287. Message(IDS_NOTIFYING_USERS);
  288. // Now wait the wait time
  289. SleepEx( WaitTime*1000, FALSE );
  290. return;
  291. }
  292. /*****************************************************************************
  293. *
  294. * NotifyWinStations
  295. *
  296. * Notify the group of WinStations about the impending system shutdown
  297. *
  298. * ENTRY:
  299. * pId (input)
  300. * Array of LOGONIDW's
  301. *
  302. * Entries (input)
  303. * Number of entries in array
  304. *
  305. * WaitTime (input)
  306. * Amount of time to wait in seconds
  307. *
  308. * EXIT:
  309. * STATUS_SUCCESS - no error
  310. *
  311. ****************************************************************************/
  312. void
  313. NotifyWinStations(
  314. PLOGONIDW pId,
  315. ULONG Entries,
  316. ULONG WaitTime
  317. )
  318. {
  319. ULONG Index;
  320. PLOGONIDW p;
  321. ULONG Response;
  322. BOOLEAN Result;
  323. WCHAR mBuf[MAX_MESSAGE_LENGTH+2];
  324. // PWCHAR pTitle = L"SYSTEM SHUTDOWN";
  325. PWCHAR pTitle;
  326. WCHAR sz1[256], sz2[512];
  327. LoadString( NULL, IDS_SHUTDOWN_TITLE, sz1, 256 );
  328. pTitle = &(sz1[0]);
  329. // Create the message
  330. LoadString( NULL, IDS_SHUTDOWN_MESSAGE, sz2, 512 );
  331. _snwprintf( mBuf, MAX_MESSAGE_LENGTH, sz2, WaitTime);
  332. for( Index=0; Index < Entries; Index++ ) {
  333. p = &pId[Index];
  334. if( p->State != State_Active ) continue;
  335. // Notify this WinStation
  336. if( v_flag ) {
  337. StringMessage(IDS_SENDING_WINSTATION, p->WinStationName);
  338. }
  339. #if DBG
  340. if( v_flag ) {
  341. printf("Open, Now really sending message to Session %ws\n", p->WinStationName);
  342. }
  343. #endif
  344. Result = WinStationSendMessage(
  345. hServerName,
  346. p->LogonId,
  347. pTitle,
  348. (wcslen(pTitle)+1)*sizeof(WCHAR),
  349. mBuf,
  350. (wcslen(mBuf)+1)*sizeof(WCHAR),
  351. MB_OK,
  352. WaitTime,
  353. &Response,
  354. TRUE
  355. );
  356. if( !Result ) {
  357. StringErrorPrintf(IDS_ERROR_SENDING_WINSTATION, p->WinStationName);
  358. }
  359. }
  360. }
  361. /*****************************************************************************
  362. *
  363. * CheckShutdownPrivilege
  364. *
  365. * Check whether the current process has shutdown permission.
  366. *
  367. * ENTRY:
  368. *
  369. * EXIT:
  370. *
  371. *
  372. ****************************************************************************/
  373. BOOLEAN
  374. CheckShutdownPrivilege()
  375. {
  376. NTSTATUS Status;
  377. BOOLEAN WasEnabled;
  378. //
  379. // Try the thread token first
  380. //
  381. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
  382. TRUE,
  383. TRUE,
  384. &WasEnabled);
  385. if (Status == STATUS_NO_TOKEN) {
  386. //
  387. // No thread token, use the process token
  388. //
  389. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
  390. TRUE,
  391. FALSE,
  392. &WasEnabled);
  393. }
  394. if (!NT_SUCCESS(Status)) {
  395. return(FALSE);
  396. }
  397. return(TRUE);
  398. }