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.

548 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. idletskc.c
  5. Abstract:
  6. This module implements the idle task client APIs.
  7. Author:
  8. Dave Fields (davidfie) 26-July-1998
  9. Cenk Ergan (cenke) 14-June-2000
  10. Revision History:
  11. --*/
  12. //
  13. // Define this to note that we are being built as a part of advapi32 and the
  14. // routines we'll call from advapi32 should not be marked as "dll imports".
  15. //
  16. #define _ADVAPI32_
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include "idletskc.h"
  22. //
  23. // Implementation of client side exposed functions.
  24. //
  25. DWORD
  26. RegisterIdleTask (
  27. IN IT_IDLE_TASK_ID IdleTaskId,
  28. OUT HANDLE *ItHandle,
  29. OUT HANDLE *StartEvent,
  30. OUT HANDLE *StopEvent
  31. )
  32. /*++
  33. Routine Description:
  34. This function is a stub to ItCliRegisterIdleTask. Please see that
  35. function for comments.
  36. Arguments:
  37. See ItCliRegisterIdleTask.
  38. Return Value:
  39. See ItCliRegisterIdleTask.
  40. --*/
  41. {
  42. // FUTURE-2002/03/26-ScottMa -- The extra layer of calls can be safely
  43. // removed to reduce clutter and improve clarity.
  44. return ItCliRegisterIdleTask(IdleTaskId,
  45. ItHandle,
  46. StartEvent,
  47. StopEvent);
  48. }
  49. DWORD
  50. ItCliRegisterIdleTask (
  51. IN IT_IDLE_TASK_ID IdleTaskId,
  52. OUT HANDLE *ItHandle,
  53. OUT HANDLE *StartEvent,
  54. OUT HANDLE *StopEvent
  55. )
  56. /*++
  57. Routine Description:
  58. Registers an idle task in the current process with the server and
  59. returns handles to two events that will be used by the server to
  60. signal the idle task to start/stop running.
  61. When the task gets to run and is completed, or not needed anymore,
  62. UnregisterIdleTask should be called with the same Id and returned
  63. event handles.
  64. The caller should not set and reset the events. It should just
  65. wait on them.
  66. An idle task should not run indefinitely as this may prevent the
  67. system from signaling other idle tasks. There is no guarantee that
  68. the StartEvent will be signaled, as the system could be always
  69. active/in use. If your task really has to run at least once every
  70. so often you can also queue a timer-queue timer.
  71. Arguments:
  72. IdleTaskId - Which idle task this is. There can be only a single
  73. task registered from a process with this id.
  74. ItHandle - Handle to registered idle task is returned here.
  75. StartEvent - Handle to a manual reset event that is set when the
  76. task should start running is returned here.
  77. StopEvent - Handle to a manual reset event that is set when the
  78. task should stop running is returned here.
  79. Return Value:
  80. Win32 error code.
  81. --*/
  82. {
  83. DWORD ErrorCode;
  84. BOOLEAN CreatedStartEvent;
  85. BOOLEAN CreatedStopEvent;
  86. IT_IDLE_TASK_PROPERTIES IdleTask;
  87. DWORD ProcessId;
  88. //
  89. // Initialize locals.
  90. //
  91. CreatedStartEvent = FALSE;
  92. CreatedStopEvent = FALSE;
  93. ProcessId = GetCurrentProcessId();
  94. DBGPR((ITID,ITTRC,"IDLE: CliRegisterIdleTask(%d,%d)\n",IdleTaskId,ProcessId));
  95. //
  96. // Setup IdleTask fields.
  97. //
  98. IdleTask.Size = sizeof(IdleTask);
  99. IdleTask.IdleTaskId = IdleTaskId;
  100. IdleTask.ProcessId = ProcessId;
  101. //
  102. // Create events for start/stop. Start event is initially
  103. // nonsignalled.
  104. //
  105. (*StartEvent) = CreateEvent(NULL, TRUE, FALSE, NULL);
  106. if (!(*StartEvent)) {
  107. ErrorCode = GetLastError();
  108. goto cleanup;
  109. }
  110. IdleTask.StartEventHandle = (ULONG_PTR) (*StartEvent);
  111. CreatedStartEvent = TRUE;
  112. //
  113. // Stop event is initially signaled.
  114. //
  115. (*StopEvent) = CreateEvent(NULL, TRUE, TRUE, NULL);
  116. if (!(*StopEvent)) {
  117. ErrorCode = GetLastError();
  118. goto cleanup;
  119. }
  120. IdleTask.StopEventHandle = (ULONG_PTR) (*StopEvent);
  121. CreatedStopEvent = TRUE;
  122. //
  123. // Call the server.
  124. //
  125. RpcTryExcept {
  126. ErrorCode = ItSrvRegisterIdleTask(NULL, (IT_HANDLE *) ItHandle, &IdleTask);
  127. }
  128. RpcExcept(IT_RPC_EXCEPTION_HANDLER()) {
  129. ErrorCode = RpcExceptionCode();
  130. }
  131. RpcEndExcept
  132. cleanup:
  133. if (ErrorCode != ERROR_SUCCESS)
  134. {
  135. // FUTURE-2002/03/26-ScottMa -- For safety, the event parameters
  136. // should be set to NULL after closing the handles on failure.
  137. // Also, the ItHandle parameter should be cleared.
  138. if (CreatedStartEvent)
  139. {
  140. CloseHandle(*StartEvent);
  141. *StartEvent = NULL;
  142. }
  143. if (CreatedStopEvent)
  144. {
  145. CloseHandle(*StopEvent);
  146. *StopEvent = NULL;
  147. }
  148. }
  149. DBGPR((ITID,ITTRC,"IDLE: CliRegisterIdleTask(%d,%d,%p)=%x\n",IdleTaskId,ProcessId,*ItHandle,ErrorCode));
  150. return ErrorCode;
  151. }
  152. DWORD
  153. UnregisterIdleTask (
  154. IN HANDLE ItHandle,
  155. IN HANDLE StartEvent,
  156. IN HANDLE StopEvent
  157. )
  158. /*++
  159. Routine Description:
  160. This function is a stub to ItCliUnregisterIdleTask. Please see
  161. that function for comments.
  162. Arguments:
  163. See ItCliUnregisterIdleTask.
  164. Return Value:
  165. Win32 error code.
  166. --*/
  167. {
  168. // FUTURE-2002/03/26-ScottMa -- The extra layer of calls can be safely
  169. // removed to reduce clutter and improve clarity. Also, the underlying
  170. // function probably *should* have returned its error code instead of
  171. // having this layer always declare success.
  172. ItCliUnregisterIdleTask(ItHandle,
  173. StartEvent,
  174. StopEvent);
  175. return ERROR_SUCCESS;
  176. }
  177. VOID
  178. ItCliUnregisterIdleTask (
  179. IN HANDLE ItHandle,
  180. IN HANDLE StartEvent,
  181. IN HANDLE StopEvent
  182. )
  183. /*++
  184. Routine Description:
  185. Unregisters an idle task in the current process with the server
  186. and cleans up any allocated resources. This function should be
  187. called when the idle task is completed, or not needed anymore
  188. (e.g. the process is exiting).
  189. Arguments:
  190. ItHandle - Registration RPC context handle.
  191. StartEvent - Handle returned from RegisterIdleTask.
  192. StopEvent - Handle returned from RegisterIdleTask.
  193. Return Value:
  194. Win32 error code.
  195. --*/
  196. {
  197. DWORD ErrorCode;
  198. //
  199. // Initialize locals.
  200. //
  201. DBGPR((ITID,ITTRC,"IDLE: CliUnregisterIdleTask(%p)\n", ItHandle));
  202. //
  203. // Call server to unregister the idle task.
  204. //
  205. RpcTryExcept {
  206. ItSrvUnregisterIdleTask(NULL, (IT_HANDLE *)&ItHandle);
  207. ErrorCode = ERROR_SUCCESS;
  208. }
  209. RpcExcept(IT_RPC_EXCEPTION_HANDLER()) {
  210. ErrorCode = RpcExceptionCode();
  211. }
  212. RpcEndExcept
  213. //
  214. // Close handles to the start/stop events.
  215. //
  216. // NOTICE-2002/03/26-ScottMa -- It is assumed that the two event params
  217. // are the same ones that were returned during registration.
  218. if (StartEvent)
  219. CloseHandle(StartEvent);
  220. if (StopEvent)
  221. CloseHandle(StopEvent);
  222. DBGPR((ITID,ITTRC,"IDLE: CliUnregisterIdleTask(%p)=0\n",ItHandle));
  223. return;
  224. }
  225. DWORD
  226. ProcessIdleTasks (
  227. VOID
  228. )
  229. /*++
  230. Routine Description:
  231. This routine forces all queued tasks (if there are any) to be processed
  232. right away.
  233. Arguments:
  234. None.
  235. Return Value:
  236. Win32 error code.
  237. --*/
  238. {
  239. DWORD ErrorCode;
  240. DBGPR((ITID,ITTRC,"IDLE: ProcessIdleTasks()\n"));
  241. //
  242. // Call the server.
  243. //
  244. RpcTryExcept {
  245. ErrorCode = ItSrvProcessIdleTasks(NULL);
  246. }
  247. RpcExcept(IT_RPC_EXCEPTION_HANDLER()) {
  248. ErrorCode = RpcExceptionCode();
  249. }
  250. RpcEndExcept
  251. DBGPR((ITID,ITTRC,"IDLE: ProcessIdleTasks()=%x\n",ErrorCode));
  252. return ErrorCode;
  253. }
  254. //
  255. // These are the custom binding functions that are called by RPC stubs
  256. // when we call interface functions:
  257. //
  258. handle_t
  259. __RPC_USER
  260. ITRPC_HANDLE_bind(
  261. ITRPC_HANDLE Reserved
  262. )
  263. /*++
  264. Routine Description:
  265. Typical RPC custom binding routine. It is called to get a binding
  266. for the RPC interface functions that require explicit_binding.
  267. Arguments:
  268. Reserved - Ignored.
  269. Return Value:
  270. RPC binding handle or NULL if there was an error.
  271. --*/
  272. {
  273. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  274. RPC_BINDING_HANDLE BindingHandle;
  275. RPC_SECURITY_QOS SecurityQOS;
  276. PSID LocalSystemSid;
  277. WCHAR *StringBinding;
  278. SID_NAME_USE AccountType;
  279. WCHAR AccountName[128];
  280. DWORD AccountNameSize = sizeof(AccountName) / sizeof(AccountName[0]);
  281. WCHAR DomainName[128];
  282. DWORD DomainNameSize = sizeof(DomainName) / sizeof(DomainName[0]);
  283. DWORD ErrorCode;
  284. //
  285. // Initialize locals.
  286. //
  287. LocalSystemSid = NULL;
  288. BindingHandle = NULL;
  289. StringBinding = NULL;
  290. ErrorCode = RpcStringBindingCompose(NULL,
  291. IT_RPC_PROTSEQ,
  292. NULL,
  293. NULL,
  294. NULL,
  295. &StringBinding);
  296. if (ErrorCode != RPC_S_OK) {
  297. goto cleanup;
  298. }
  299. ErrorCode = RpcBindingFromStringBinding(StringBinding,
  300. &BindingHandle);
  301. if (ErrorCode != RPC_S_OK) {
  302. IT_ASSERT(BindingHandle == NULL);
  303. goto cleanup;
  304. }
  305. //
  306. // Set security information.
  307. //
  308. SecurityQOS.Version = RPC_C_SECURITY_QOS_VERSION;
  309. SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  310. SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  311. SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  312. //
  313. // Get the security principal name for LocalSystem: we'll only allow an
  314. // RPC server running as LocalSystem to impersonate us.
  315. //
  316. if (!AllocateAndInitializeSid(&NtAuthority,
  317. 1,
  318. SECURITY_LOCAL_SYSTEM_RID,
  319. 0, 0, 0, 0, 0, 0, 0,
  320. &LocalSystemSid)) {
  321. ErrorCode = GetLastError();
  322. goto cleanup;
  323. }
  324. if (LookupAccountSid(NULL,
  325. LocalSystemSid,
  326. AccountName,
  327. &AccountNameSize,
  328. DomainName,
  329. &DomainNameSize,
  330. &AccountType) == 0) {
  331. ErrorCode = GetLastError();
  332. goto cleanup;
  333. }
  334. //
  335. // Set mutual authentication requirements on the binding handle.
  336. //
  337. ErrorCode = RpcBindingSetAuthInfoEx(BindingHandle,
  338. AccountName,
  339. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  340. RPC_C_AUTHN_WINNT,
  341. NULL,
  342. 0,
  343. &SecurityQOS);
  344. if (ErrorCode!= RPC_S_OK) {
  345. goto cleanup;
  346. }
  347. ErrorCode = ERROR_SUCCESS;
  348. cleanup:
  349. if (StringBinding) {
  350. RpcStringFree(&StringBinding);
  351. }
  352. if (LocalSystemSid) {
  353. FreeSid(LocalSystemSid);
  354. }
  355. return BindingHandle;
  356. }
  357. VOID
  358. __RPC_USER
  359. ITRPC_HANDLE_unbind(
  360. ITRPC_HANDLE Reserved,
  361. RPC_BINDING_HANDLE BindingHandle
  362. )
  363. /*++
  364. Routine Description:
  365. Typical RPC custom unbinding routine. It is called to close a
  366. binding established for an RPC interface function that required
  367. explicit_binding.
  368. Arguments:
  369. Reserved - Ignored.
  370. BindingHandle - Primitive binding handle.
  371. Return Value:
  372. None.
  373. --*/
  374. {
  375. RPC_STATUS Status;
  376. Status = RpcBindingFree(&BindingHandle);
  377. IT_ASSERT(Status == RPC_S_OK);
  378. IT_ASSERT(BindingHandle == NULL);
  379. return;
  380. }