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.

689 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Shutdown.c
  5. Abstract:
  6. This module contains the client side wrappers for the Win32 remote
  7. shutdown APIs, that is:
  8. - InitiateSystemShutdownA
  9. - InitiateSystemShutdownW
  10. - AbortSystemShutdownA
  11. - AbortSystemShutdownW
  12. Author:
  13. Dave Chalmers (davidc) 29-Apr-1992
  14. Notes:
  15. Revision History:
  16. Dragos C. Sambotin (dragoss) 21-May-1999
  17. Added support for the new winlogon's Shutdown interface
  18. --*/
  19. #define UNICODE
  20. #include <rpc.h>
  21. #include "regrpc.h"
  22. #include "client.h"
  23. #include "shutinit.h"
  24. #include "..\regconn\regconn.h"
  25. LONG
  26. BaseBindToMachine(
  27. IN LPCWSTR lpMachineName,
  28. IN PBIND_CALLBACK BindCallback,
  29. IN PVOID Context1,
  30. IN PVOID Context2
  31. );
  32. LONG
  33. ShutdownCallback(
  34. IN RPC_BINDING_HANDLE *pbinding,
  35. IN PUNICODE_STRING Message,
  36. IN PVOID Context2
  37. );
  38. LONG
  39. ShutdownCallbackEx(
  40. IN RPC_BINDING_HANDLE *pbinding,
  41. IN PUNICODE_STRING Message,
  42. IN PVOID Context2
  43. );
  44. LONG
  45. AbortShutdownCallback(
  46. IN RPC_BINDING_HANDLE *pbinding,
  47. IN PVOID Context1,
  48. IN PVOID Context2
  49. );
  50. BOOL
  51. APIENTRY
  52. InitiateSystemShutdownW(
  53. IN LPWSTR lpMachineName OPTIONAL,
  54. IN LPWSTR lpMessage OPTIONAL,
  55. IN DWORD dwTimeout,
  56. IN BOOL bForceAppsClosed,
  57. IN BOOL bRebootAfterShutdown
  58. )
  59. /*++
  60. Routine Description:
  61. Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
  62. Arguments:
  63. lpMachineName - Name of machine to shutdown.
  64. lpMessage - Message to display during shutdown timeout period.
  65. if Message(comment) is longer than MAX_REASON_COMMENT_LEN
  66. return FALSE.(ERROR_INVALID_PARAMETER)
  67. dwTimeout - Number of seconds to delay before shutting down
  68. if dwTimeout is larger than MAX_SHUTDOWN_TIMEOUT,
  69. return FALSE. (ERROR_INVALID_PARAMETER)
  70. bForceAppsClosed - Normally applications may prevent system shutdown.
  71. If this flag is set, all applications are terminated
  72. unconditionally.
  73. bRebootAfterShutdown - TRUE if the system should reboot.
  74. FALSE if it should be left in a shutdown state.
  75. Return Value:
  76. Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
  77. Possible errors :
  78. ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
  79. the specified machine.
  80. --*/
  81. {
  82. DWORD Result;
  83. UNICODE_STRING Message;
  84. SHUTDOWN_CONTEXT ShutdownContext;
  85. BOOL TryOld = TRUE;
  86. //
  87. // Explicitly bind to the given server.
  88. //
  89. if (!ARGUMENT_PRESENT(lpMachineName)) {
  90. lpMachineName = L"";
  91. TryOld = FALSE;
  92. }
  93. ShutdownContext.dwTimeout = dwTimeout;
  94. ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
  95. ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
  96. RtlInitUnicodeString(&Message, lpMessage);
  97. if ( ( Message.Length / sizeof(WCHAR) < MAX_REASON_COMMENT_LEN ) &&
  98. ( dwTimeout < MAX_SHUTDOWN_TIMEOUT ) ){
  99. //
  100. // Call the server
  101. //
  102. //
  103. // First try to connect to the new InitShutdown interface
  104. //
  105. Result = BaseBindToMachineShutdownInterface(lpMachineName,
  106. NewShutdownCallback,
  107. &Message,
  108. &ShutdownContext);
  109. if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
  110. //
  111. // try the old one, maybe we are calling into a NT4 machine
  112. // which doesn't know about the new interface
  113. //
  114. Result = BaseBindToMachine(lpMachineName,
  115. ShutdownCallback,
  116. &Message,
  117. &ShutdownContext);
  118. }
  119. }
  120. else{
  121. Result = ERROR_INVALID_PARAMETER;
  122. }
  123. if (Result != ERROR_SUCCESS) {
  124. SetLastError(Result);
  125. }
  126. return(Result == ERROR_SUCCESS);
  127. }
  128. BOOL
  129. APIENTRY
  130. InitiateSystemShutdownExW(
  131. IN LPWSTR lpMachineName OPTIONAL,
  132. IN LPWSTR lpMessage OPTIONAL,
  133. IN DWORD dwTimeout,
  134. IN BOOL bForceAppsClosed,
  135. IN BOOL bRebootAfterShutdown,
  136. IN DWORD dwReason
  137. )
  138. /*++
  139. Routine Description:
  140. Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
  141. Arguments:
  142. lpMachineName - Name of machine to shutdown.
  143. lpMessage - Message to display during shutdown timeout period.
  144. if Message(comment) is longer than MAX_REASON_COMMENT_LEN
  145. return FALSE.(ERROR_INVALID_PARAMETER)
  146. dwTimeout - Number of seconds to delay before shutting down
  147. if dwTimeout is larger than MAX_SHUTDOWN_TIMEOUT,
  148. return FALSE. (ERROR_INVALID_PARAMETER)
  149. bForceAppsClosed - Normally applications may prevent system shutdown.
  150. If this flag is set, all applications are terminated
  151. unconditionally.
  152. bRebootAfterShutdown - TRUE if the system should reboot.
  153. FALSE if it should be left in a shutdown state.
  154. dwReason - Reason for initiating the shutdown. This reason is logged
  155. in the eventlog #6006 event.
  156. Return Value:
  157. Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
  158. Possible errors :
  159. ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
  160. the specified machine.
  161. --*/
  162. {
  163. DWORD Result;
  164. UNICODE_STRING Message;
  165. SHUTDOWN_CONTEXTEX ShutdownContext;
  166. BOOL TryOld = TRUE;
  167. //
  168. // Explicitly bind to the given server.
  169. //
  170. if (!ARGUMENT_PRESENT(lpMachineName)) {
  171. lpMachineName = L"";
  172. TryOld = FALSE;
  173. }
  174. ShutdownContext.dwTimeout = dwTimeout;
  175. ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
  176. ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
  177. ShutdownContext.dwReason = dwReason;
  178. RtlInitUnicodeString(&Message, lpMessage);
  179. if ( ( Message.Length / sizeof(WCHAR) < MAX_REASON_COMMENT_LEN ) &&
  180. ( dwTimeout < MAX_SHUTDOWN_TIMEOUT ) ) {
  181. //
  182. // Call the server
  183. //
  184. //
  185. // First try to connect to the new InitShutdown interface
  186. //
  187. Result = BaseBindToMachineShutdownInterface(lpMachineName,
  188. NewShutdownCallbackEx,
  189. &Message,
  190. &ShutdownContext);
  191. if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
  192. //
  193. // try the old one, maybe we are calling into a NT4 machine
  194. // which doesn't know about the new interface
  195. //
  196. Result = BaseBindToMachine(lpMachineName,
  197. ShutdownCallbackEx,
  198. &Message,
  199. &ShutdownContext);
  200. }
  201. }
  202. else{
  203. Result = ERROR_INVALID_PARAMETER;
  204. }
  205. if (Result != ERROR_SUCCESS) {
  206. SetLastError(Result);
  207. }
  208. return(Result == ERROR_SUCCESS);
  209. }
  210. BOOL
  211. APIENTRY
  212. InitiateSystemShutdownA(
  213. IN LPSTR lpMachineName OPTIONAL,
  214. IN LPSTR lpMessage OPTIONAL,
  215. IN DWORD dwTimeout,
  216. IN BOOL bForceAppsClosed,
  217. IN BOOL bRebootAfterShutdown
  218. )
  219. /*++
  220. Routine Description:
  221. See InitiateSystemShutdownW
  222. --*/
  223. {
  224. UNICODE_STRING MachineName;
  225. UNICODE_STRING Message;
  226. ANSI_STRING AnsiString;
  227. NTSTATUS Status;
  228. BOOL Result;
  229. //
  230. // Convert the ansi machinename to wide-character
  231. //
  232. RtlInitAnsiString( &AnsiString, lpMachineName );
  233. Status = RtlAnsiStringToUnicodeString(
  234. &MachineName,
  235. &AnsiString,
  236. TRUE
  237. );
  238. if( NT_SUCCESS( Status )) {
  239. //
  240. // Convert the ansi message to wide-character
  241. //
  242. RtlInitAnsiString( &AnsiString, lpMessage );
  243. Status = RtlAnsiStringToUnicodeString(
  244. &Message,
  245. &AnsiString,
  246. TRUE
  247. );
  248. if (NT_SUCCESS(Status)) {
  249. //
  250. // Call the wide-character api
  251. //
  252. Result = InitiateSystemShutdownW(
  253. MachineName.Buffer,
  254. Message.Buffer,
  255. dwTimeout,
  256. bForceAppsClosed,
  257. bRebootAfterShutdown
  258. );
  259. RtlFreeUnicodeString(&Message);
  260. }
  261. RtlFreeUnicodeString(&MachineName);
  262. }
  263. if (!NT_SUCCESS(Status)) {
  264. SetLastError(RtlNtStatusToDosError(Status));
  265. Result = FALSE;
  266. }
  267. return(Result);
  268. }
  269. BOOL
  270. APIENTRY
  271. InitiateSystemShutdownExA(
  272. IN LPSTR lpMachineName OPTIONAL,
  273. IN LPSTR lpMessage OPTIONAL,
  274. IN DWORD dwTimeout,
  275. IN BOOL bForceAppsClosed,
  276. IN BOOL bRebootAfterShutdown,
  277. IN DWORD dwReason
  278. )
  279. /*++
  280. Routine Description:
  281. See InitiateSystemShutdownW
  282. --*/
  283. {
  284. UNICODE_STRING MachineName;
  285. UNICODE_STRING Message;
  286. ANSI_STRING AnsiString;
  287. NTSTATUS Status;
  288. BOOL Result;
  289. //
  290. // Convert the ansi machinename to wide-character
  291. //
  292. RtlInitAnsiString( &AnsiString, lpMachineName );
  293. Status = RtlAnsiStringToUnicodeString(
  294. &MachineName,
  295. &AnsiString,
  296. TRUE
  297. );
  298. if( NT_SUCCESS( Status )) {
  299. //
  300. // Convert the ansi message to wide-character
  301. //
  302. RtlInitAnsiString( &AnsiString, lpMessage );
  303. Status = RtlAnsiStringToUnicodeString(
  304. &Message,
  305. &AnsiString,
  306. TRUE
  307. );
  308. if (NT_SUCCESS(Status)) {
  309. //
  310. // Call the wide-character api
  311. //
  312. Result = InitiateSystemShutdownExW(
  313. MachineName.Buffer,
  314. Message.Buffer,
  315. dwTimeout,
  316. bForceAppsClosed,
  317. bRebootAfterShutdown,
  318. dwReason
  319. );
  320. RtlFreeUnicodeString(&Message);
  321. }
  322. RtlFreeUnicodeString(&MachineName);
  323. }
  324. if (!NT_SUCCESS(Status)) {
  325. SetLastError(RtlNtStatusToDosError(Status));
  326. Result = FALSE;
  327. }
  328. return(Result);
  329. }
  330. BOOL
  331. APIENTRY
  332. AbortSystemShutdownW(
  333. IN LPWSTR lpMachineName OPTIONAL
  334. )
  335. /*++
  336. Routine Description:
  337. Win32 Unicode API for aborting the shutdown of a (possibly remote) machine.
  338. Arguments:
  339. lpMachineName - Name of target machine.
  340. Return Value:
  341. Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
  342. --*/
  343. {
  344. DWORD Result;
  345. RPC_BINDING_HANDLE binding;
  346. BOOL TryOld = TRUE;
  347. //
  348. // Explicitly bind to the given server.
  349. //
  350. if (!ARGUMENT_PRESENT(lpMachineName)) {
  351. lpMachineName = L"";
  352. TryOld = FALSE;
  353. }
  354. //
  355. // Call the server
  356. //
  357. //
  358. // First try to connect to the new InitShutdown interface
  359. //
  360. Result = BaseBindToMachineShutdownInterface(lpMachineName,
  361. NewAbortShutdownCallback,
  362. NULL,
  363. NULL);
  364. if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
  365. //
  366. // try the old one, maybe we are calling into a NT4 machine
  367. // which doesn't know about the new interface
  368. Result = BaseBindToMachine(lpMachineName,
  369. AbortShutdownCallback,
  370. NULL,
  371. NULL);
  372. }
  373. if (Result != ERROR_SUCCESS) {
  374. SetLastError(Result);
  375. }
  376. return(Result == ERROR_SUCCESS);
  377. }
  378. BOOL
  379. APIENTRY
  380. AbortSystemShutdownA(
  381. IN LPSTR lpMachineName OPTIONAL
  382. )
  383. /*++
  384. Routine Description:
  385. See AbortSystemShutdownW
  386. --*/
  387. {
  388. UNICODE_STRING MachineName;
  389. ANSI_STRING AnsiString;
  390. NTSTATUS Status;
  391. BOOL Result;
  392. //
  393. // Convert the ansi machinename to wide-character
  394. //
  395. RtlInitAnsiString( &AnsiString, lpMachineName );
  396. Status = RtlAnsiStringToUnicodeString(
  397. &MachineName,
  398. &AnsiString,
  399. TRUE
  400. );
  401. if( NT_SUCCESS( Status )) {
  402. //
  403. // Call the wide-character api
  404. //
  405. Result = AbortSystemShutdownW(
  406. MachineName.Buffer
  407. );
  408. RtlFreeUnicodeString(&MachineName);
  409. }
  410. if (!NT_SUCCESS(Status)) {
  411. SetLastError(RtlNtStatusToDosError(Status));
  412. Result = FALSE;
  413. }
  414. return(Result);
  415. }
  416. LONG
  417. ShutdownCallback(
  418. IN RPC_BINDING_HANDLE *pbinding,
  419. IN PUNICODE_STRING Message,
  420. IN PSHUTDOWN_CONTEXT ShutdownContext
  421. )
  422. /*++
  423. Routine Description:
  424. Callback for binding to a machine to initiate a shutdown.
  425. Arguments:
  426. pbinding - Supplies a pointer to the RPC binding context
  427. Message - Supplies message to display during shutdown timeout period.
  428. ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
  429. Return Value:
  430. ERROR_SUCCESS if no error.
  431. --*/
  432. {
  433. DWORD Result;
  434. RpcTryExcept {
  435. Result = BaseInitiateSystemShutdown((PREGISTRY_SERVER_NAME)pbinding,
  436. Message,
  437. ShutdownContext->dwTimeout,
  438. ShutdownContext->bForceAppsClosed,
  439. ShutdownContext->bRebootAfterShutdown);
  440. } RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  441. Result = RpcExceptionCode();
  442. } RpcEndExcept;
  443. if (Result != ERROR_SUCCESS) {
  444. RpcBindingFree(pbinding);
  445. }
  446. return(Result);
  447. }
  448. LONG
  449. ShutdownCallbackEx(
  450. IN RPC_BINDING_HANDLE *pbinding,
  451. IN PUNICODE_STRING Message,
  452. IN PSHUTDOWN_CONTEXTEX ShutdownContext
  453. )
  454. /*++
  455. Routine Description:
  456. Callback for binding to a machine to initiate a shutdown.
  457. Arguments:
  458. pbinding - Supplies a pointer to the RPC binding context
  459. Message - Supplies message to display during shutdown timeout period.
  460. ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
  461. Return Value:
  462. ERROR_SUCCESS if no error.
  463. --*/
  464. {
  465. DWORD Result;
  466. RpcTryExcept {
  467. Result = BaseInitiateSystemShutdownEx((PREGISTRY_SERVER_NAME)pbinding,
  468. Message,
  469. ShutdownContext->dwTimeout,
  470. ShutdownContext->bForceAppsClosed,
  471. ShutdownContext->bRebootAfterShutdown,
  472. ShutdownContext->dwReason);
  473. } RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  474. Result = RpcExceptionCode();
  475. } RpcEndExcept;
  476. if (Result != ERROR_SUCCESS) {
  477. RpcBindingFree(pbinding);
  478. }
  479. return(Result);
  480. }
  481. LONG
  482. AbortShutdownCallback(
  483. IN RPC_BINDING_HANDLE *pbinding,
  484. IN PVOID Unused1,
  485. IN PVOID Unused2
  486. )
  487. /*++
  488. Routine Description:
  489. Callback for binding to a machine to abort a shutdown.
  490. Arguments:
  491. pbinding - Supplies a pointer to the RPC binding context
  492. Return Value:
  493. ERROR_SUCCESS if no error.
  494. --*/
  495. {
  496. DWORD Result;
  497. RpcTryExcept {
  498. Result = BaseAbortSystemShutdown((PREGISTRY_SERVER_NAME)pbinding);
  499. } RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
  500. Result = RpcExceptionCode();
  501. } RpcEndExcept;
  502. if (Result != ERROR_SUCCESS) {
  503. RpcBindingFree(pbinding);
  504. }
  505. return(Result);
  506. }