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.

2511 lines
73 KiB

  1. /*++
  2. Copyright (c) 1992-1999 Microsoft Corporation
  3. Module Name:
  4. GenJob.c
  5. Abstract:
  6. Resource DLL for Generic Job Objects (based on genapp)
  7. Author:
  8. Charlie Wickham (charlwi) 4-14-99
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "clusrtl.h"
  14. #include "jobmsg.h"
  15. // move to clusres.h
  16. #define LOG_MODULE_GENJOB 0x80F
  17. #define LOG_CURRENT_MODULE LOG_MODULE_GENJOB
  18. #define DBG_PRINT printf
  19. // move to clusudef.h
  20. #define CLUS_RESTYPE_NAME_GENJOB L"Generic Job Object"
  21. #define CLUSREG_NAME_GENJOB_COMMAND_LINE L"CommandLine"
  22. #define CLUSREG_NAME_GENJOB_CURRENT_DIRECTORY L"CurrentDirectory"
  23. #define CLUSREG_NAME_GENJOB_INTERACT_WITH_DESKTOP L"InteractWithDesktop"
  24. #define CLUSREG_NAME_GENJOB_USE_NETWORK_NAME L"UseNetworkName"
  25. // delete these when moving to clusres
  26. PSET_RESOURCE_STATUS_ROUTINE ClusResSetResourceStatus = NULL;
  27. PLOG_EVENT_ROUTINE ClusResLogEvent = NULL;
  28. //
  29. // Private properties structure.
  30. //
  31. typedef struct _GENJOB_PROPS
  32. {
  33. PWSTR CommandLine; // first process in job
  34. PWSTR CurrentDirectory; // directory to associated with process
  35. DWORD InteractWithDesktop; // true sets desktop to "winsta0\default"
  36. DWORD UseNetworkName; // true if associated netname should be replaced in environment
  37. BOOL UseDefaults; // true if all job obj defaults are used
  38. BOOL ProcsCanBreakaway; // true sets JOB_OBJECT_LIMIT_BREAKAWAY_OK
  39. BOOL ProcsCanSilentlyBreakaway; // true sets JOB_OBJECT_LIMIT_SILENT_BREAKAWAY
  40. BOOL SetActiveProcessLimit; // true sets JOB_OBJECT_LIMIT_ACTIVE_PROCESS
  41. DWORD ActiveProcessLimit; // sets BasicLimitInformation.ActiveProcessLimit
  42. BOOL SetAffinity; // true sets JOB_OBJECT_LIMIT_AFFINITY
  43. DWORD Affinity; // sets BasicLimitInformation.Affinity
  44. BOOL SetJobUserTimeLimit; // true sets JOB_OBJECT_LIMIT_JOB_TIME
  45. DWORD PerJobUserTimeLimit; // sets BasicLimitInformation.PerJobUserTimeLimit
  46. BOOL SetPriorityClass; // true sets JOB_OBJECT_LIMIT_PRIORITY_CLASS
  47. DWORD PriorityClass; // sets BasicLimitInformation.PriorityClass
  48. BOOL SetProcessUserTimeLimit; // true sets JOB_OBJECT_LIMIT_PROCESS_TIME
  49. DWORD PerProcessUserTimeLimit; // sets BasicLimitInformation.PerProcessUserTimeLimit
  50. BOOL SetSchedulingClass; // true sets JOB_OBJECT_LIMIT_SCHEDULING_CLASS
  51. DWORD SchedulingClass; // sets BasicLimitInformation.SchedulingClass
  52. BOOL SetWorkingSetSize; // true sets JOB_OBJECT_LIMIT_WORKINGSET
  53. DWORD MaximumWorkingSetSize; // sets BasicLimitInformation.MaximumWorkingSetSize
  54. DWORD MinimumWorkingSetSize; // sets BasicLimitInformation.MinimumWorkingSetSize
  55. BOOL ManipulateDesktops; // false sets JOB_OBJECT_UILIMIT_DESKTOP
  56. BOOL ChangeDisplaySettings; // false sets JOB_OBJECT_UILIMIT_DISPLAYSETTINGS
  57. BOOL AllowSystemShutdown; // false sets JOB_OBJECT_UILIMIT_EXITWINDOWS
  58. BOOL AccessGlobalAtoms; // false sets JOB_OBJECT_UILIMIT_GLOBALATOMS
  59. BOOL AllowOtherProcessUSERHandles; // false sets JOB_OBJECT_UILIMIT_HANDLES
  60. BOOL ReadFromClipboard; // false sets JOB_OBJECT_UILIMIT_READCLIPBOARD
  61. BOOL ChangeSystemParameters; // false sets JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS
  62. BOOL WriteToClipboard; // false sets JOB_OBJECT_UILIMIT_WRITECLIPBOARD
  63. BOOL TerminateOnTimeLimit; // false sets JOB_OBJECT_POST_AT_END_OF_JOB
  64. BOOL SetJobMemoryLimit; // true sets JOB_OBJECT_LIMIT_JOB_MEMORY in Basic.LimitFlags
  65. DWORD JobMemoryLimit; // sets ExtendedLimits.JobMemoryLimit
  66. BOOL SetProcessMemoryLimit; // true sets JOB_OBJECT_LIMIT_PROCESS_MEMORY
  67. DWORD ProcessMemoryLimit; // sets ExtendedLimits.ProcessMemoryLimit
  68. BOOL AllowLocalAdminTokens; // false sets JOB_OBJECT_SECURITY_NO_ADMIN
  69. BOOL AllowUseOfRestrictedTokens; // false sets JOB_OBJECT_SECURITY_RESTRICTED_TOKEN
  70. } GENJOB_PROPS, * PGENJOB_PROPS;
  71. //
  72. // top level per-resource instance structure
  73. //
  74. typedef struct _GENJOB_RESOURCE {
  75. GENJOB_PROPS OperationalProps; // props associated with online resource
  76. GENJOB_PROPS StoredProps; // props to be used next time resource is online
  77. HRESOURCE hResource; // cluster handle to this resource
  78. DWORD ProcessId; // PID of initial process
  79. HKEY ResourceKey; // handle to this resource's key
  80. HKEY ParametersKey; // handle to this resource's params key
  81. HANDLE JobHandle; // backing job object handle
  82. HANDLE OfflineEvent; // signalled when resource goes offline
  83. RESOURCE_HANDLE ResourceHandle; // resmon pointer to its structure
  84. CLUS_WORKER OnlineThread; // background online processing thread
  85. BOOL Online; // true if online
  86. } GENJOB_RESOURCE, *PGENJOB_RESOURCE;
  87. //
  88. // property definitions
  89. //
  90. #define PROP_NAME__COMMANDLINE CLUSREG_NAME_GENJOB_COMMAND_LINE
  91. #define PROP_NAME__CURRENTDIRECTORY CLUSREG_NAME_GENJOB_CURRENT_DIRECTORY
  92. #define PROP_NAME__INTERACTWITHDESKTOP CLUSREG_NAME_GENJOB_INTERACT_WITH_DESKTOP
  93. #define PROP_NAME__USENETWORKNAME CLUSREG_NAME_GENJOB_USE_NETWORK_NAME
  94. #define PROP_NAME__USEDEFAULTS L"UseDefaults"
  95. #define PROP_NAME__PROCSCANBREAKAWAY L"ProcsCanBreakaway"
  96. #define PROP_NAME__PROCSCANSILENTLYBREAKAWAY L"ProcsCanSilentlyBreakaway"
  97. #define PROP_NAME__SETACTIVEPROCESSLIMIT L"SetActiveProcessLimit"
  98. #define PROP_NAME__ACTIVEPROCESSLIMIT L"ActiveProcessLimit"
  99. #define PROP_NAME__SETAFFINITY L"SetAffinity"
  100. #define PROP_NAME__AFFINITY L"Affinity"
  101. #define PROP_NAME__SETJOBUSERTIMELIMIT L"SetJobUserTimeLimit"
  102. #define PROP_NAME__PERJOBUSERTIMELIMIT L"PerJobUserTimeLimit"
  103. #define PROP_NAME__SETPRIORITYCLASS L"SetPriorityClass"
  104. #define PROP_NAME__PRIORITYCLASS L"PriorityClass"
  105. #define PROP_NAME__SETPROCESSUSERTIMELIMIT L"SetProcessUserTimeLimit"
  106. #define PROP_NAME__PERPROCESSUSERTIMELIMIT L"PerProcessUserTimelimit"
  107. #define PROP_NAME__SETSCHEDULINGCLASS L"SetSchedulingClass"
  108. #define PROP_NAME__SCHEDULINGCLASS L"SchedulingClass"
  109. #define PROP_NAME__SETWORKINGSETSIZE L"SetWorkingSetSize"
  110. #define PROP_NAME__MAXIMUMWORKINGSETSIZE L"MaximumWorkingSetSize"
  111. #define PROP_NAME__MINIMUMWORKINGSETSIZE L"MinimumWorkingSetSize"
  112. #define PROP_NAME__MANIPULATEDESKTOPS L"ManipulateDesktops"
  113. #define PROP_NAME__CHANGEDISPLAYSETTINGS L"ChangeDisplaySettings"
  114. #define PROP_NAME__ALLOWSYSTEMSHUTDOWN L"Allowsystemshutdown"
  115. #define PROP_NAME__ACCESSGLOBALATOMS L"AccessGlobalAtoms"
  116. #define PROP_NAME__ALLOWOTHERPROCESSUSERHANDLES L"AllowOtherProcessUSERHandles"
  117. #define PROP_NAME__READFROMCLIPBOARD L"ReadFromClipboard"
  118. #define PROP_NAME__CHANGESYSTEMPARAMETERS L"ChangeSystemParameters"
  119. #define PROP_NAME__WRITETOCLIPBOARD L"WriteToClipboard"
  120. #define PROP_NAME__TERMINATEONTIMELIMIT L"TerminateOnTimeLimit"
  121. #define PROP_NAME__SETJOBMEMORYLIMIT L"SetJobMemoryLimit"
  122. #define PROP_NAME__JOBMEMORYLIMIT L"JobMemoryLimit"
  123. #define PROP_NAME__SETPROCESSMEMORYLIMIT L"SetProcessMemoryLimit"
  124. #define PROP_NAME__PROCESSMEMORYLIMIT L"ProcessMemoryLimit"
  125. #define PROP_NAME__ALLOWLOCALADMINTOKENS L"AllowLocalAdminTokens"
  126. #define PROP_NAME__ALLOWUSEOFRESTRICTEDTOKENS L"AllowUseOfRestrictedTokens"
  127. //
  128. // min, max, defaults for each non-string property
  129. //
  130. #define PROP_MIN__INTERACTWITHDESKTOP 0
  131. #define PROP_MAX__INTERACTWITHDESKTOP 1
  132. #define PROP_DEFAULT__INTERACTWITHDESKTOP 0
  133. #define PROP_MIN__USENETWORKNAME 0
  134. #define PROP_MAX__USENETWORKNAME 1
  135. #define PROP_DEFAULT__USENETWORKNAME 0
  136. #define PROP_MIN__USEDEFAULTS 0
  137. #define PROP_MAX__USEDEFAULTS 1
  138. #define PROP_DEFAULT__USEDEFAULTS 1
  139. #define PROP_MIN__PROCSCANBREAKAWAY (0)
  140. #define PROP_MAX__PROCSCANBREAKAWAY (1)
  141. #define PROP_DEFAULT__PROCSCANBREAKAWAY (0)
  142. #define PROP_MIN__PROCSCANSILENTLYBREAKAWAY (0)
  143. #define PROP_MAX__PROCSCANSILENTLYBREAKAWAY (1)
  144. #define PROP_DEFAULT__PROCSCANSILENTLYBREAKAWAY (0)
  145. #define PROP_MIN__SETACTIVEPROCESSLIMIT (0)
  146. #define PROP_MAX__SETACTIVEPROCESSLIMIT (1)
  147. #define PROP_DEFAULT__SETACTIVEPROCESSLIMIT (0)
  148. #define PROP_MIN__ACTIVEPROCESSLIMIT (1)
  149. #define PROP_MAX__ACTIVEPROCESSLIMIT (4294967295)
  150. #define PROP_DEFAULT__ACTIVEPROCESSLIMIT (1)
  151. #define PROP_MIN__SETAFFINITY (0)
  152. #define PROP_MAX__SETAFFINITY (1)
  153. #define PROP_DEFAULT__SETAFFINITY (0)
  154. #define PROP_MIN__AFFINITY (1)
  155. #define PROP_MAX__AFFINITY (4294967295)
  156. #define PROP_DEFAULT__AFFINITY (1)
  157. #define PROP_MIN__SETJOBUSERTIMELIMIT (0)
  158. #define PROP_MAX__SETJOBUSERTIMELIMIT (1)
  159. #define PROP_DEFAULT__SETJOBUSERTIMELIMIT (0)
  160. #define PROP_MIN__PERJOBUSERTIMELIMIT (1)
  161. #define PROP_MAX__PERJOBUSERTIMELIMIT (4294967295)
  162. #define PROP_DEFAULT__PERJOBUSERTIMELIMIT (1)
  163. #define PROP_MIN__SETPRIORITYCLASS (0)
  164. #define PROP_MAX__SETPRIORITYCLASS (1)
  165. #define PROP_DEFAULT__SETPRIORITYCLASS (0)
  166. #define PROP_MIN__PRIORITYCLASS (0)
  167. #define PROP_MAX__PRIORITYCLASS (31)
  168. #define PROP_DEFAULT__PRIORITYCLASS (0)
  169. #define PROP_MIN__SETPROCESSUSERTIMELIMIT (0)
  170. #define PROP_MAX__SETPROCESSUSERTIMELIMIT (1)
  171. #define PROP_DEFAULT__SETPROCESSUSERTIMELIMIT (0)
  172. #define PROP_MIN__PERPROCESSUSERTIMELIMIT (1)
  173. #define PROP_MAX__PERPROCESSUSERTIMELIMIT (4294967295)
  174. #define PROP_DEFAULT__PERPROCESSUSERTIMELIMIT (1)
  175. #define PROP_MIN__SETSCHEDULINGCLASS (0)
  176. #define PROP_MAX__SETSCHEDULINGCLASS (1)
  177. #define PROP_DEFAULT__SETSCHEDULINGCLASS (0)
  178. #define PROP_MIN__SCHEDULINGCLASS (0)
  179. #define PROP_MAX__SCHEDULINGCLASS (9)
  180. #define PROP_DEFAULT__SCHEDULINGCLASS (5)
  181. #define PROP_MIN__SETWORKINGSETSIZE (0)
  182. #define PROP_MAX__SETWORKINGSETSIZE (1)
  183. #define PROP_DEFAULT__SETWORKINGSETSIZE (0)
  184. #define PROP_MIN__MAXIMUMWORKINGSETSIZE (0)
  185. #define PROP_MAX__MAXIMUMWORKINGSETSIZE (4294967295)
  186. #define PROP_DEFAULT__MAXIMUMWORKINGSETSIZE (0)
  187. #define PROP_MIN__MINIMUMWORKINGSETSIZE (0)
  188. #define PROP_MAX__MINIMUMWORKINGSETSIZE (4294967295)
  189. #define PROP_DEFAULT__MINIMUMWORKINGSETSIZE (0)
  190. #define PROP_MIN__MANIPULATEDESKTOPS (0)
  191. #define PROP_MAX__MANIPULATEDESKTOPS (1)
  192. #define PROP_DEFAULT__MANIPULATEDESKTOPS (1)
  193. #define PROP_MIN__CHANGEDISPLAYSETTINGS (0)
  194. #define PROP_MAX__CHANGEDISPLAYSETTINGS (1)
  195. #define PROP_DEFAULT__CHANGEDISPLAYSETTINGS (1)
  196. #define PROP_MIN__ALLOWSYSTEMSHUTDOWN (0)
  197. #define PROP_MAX__ALLOWSYSTEMSHUTDOWN (1)
  198. #define PROP_DEFAULT__ALLOWSYSTEMSHUTDOWN (1)
  199. #define PROP_MIN__ACCESSGLOBALATOMS (0)
  200. #define PROP_MAX__ACCESSGLOBALATOMS (1)
  201. #define PROP_DEFAULT__ACCESSGLOBALATOMS (1)
  202. #define PROP_MIN__ALLOWOTHERPROCESSUSERHANDLES (0)
  203. #define PROP_MAX__ALLOWOTHERPROCESSUSERHANDLES (1)
  204. #define PROP_DEFAULT__ALLOWOTHERPROCESSUSERHANDLES (1)
  205. #define PROP_MIN__READFROMCLIPBOARD (0)
  206. #define PROP_MAX__READFROMCLIPBOARD (1)
  207. #define PROP_DEFAULT__READFROMCLIPBOARD (1)
  208. #define PROP_MIN__CHANGESYSTEMPARAMETERS (0)
  209. #define PROP_MAX__CHANGESYSTEMPARAMETERS (1)
  210. #define PROP_DEFAULT__CHANGESYSTEMPARAMETERS (1)
  211. #define PROP_MIN__WRITETOCLIPBOARD (0)
  212. #define PROP_MAX__WRITETOCLIPBOARD (1)
  213. #define PROP_DEFAULT__WRITETOCLIPBOARD (1)
  214. #define PROP_MIN__TERMINATEONTIMELIMIT (0)
  215. #define PROP_MAX__TERMINATEONTIMELIMIT (1)
  216. #define PROP_DEFAULT__TERMINATEONTIMELIMIT (1)
  217. #define PROP_MIN__SETJOBMEMORYLIMIT (0)
  218. #define PROP_MAX__SETJOBMEMORYLIMIT (1)
  219. #define PROP_DEFAULT__SETJOBMEMORYLIMIT (0)
  220. #define PROP_MIN__JOBMEMORYLIMIT (0)
  221. #define PROP_MAX__JOBMEMORYLIMIT (4294967295)
  222. #define PROP_DEFAULT__JOBMEMORYLIMIT (0)
  223. #define PROP_MIN__SETPROCESSMEMORYLIMIT (0)
  224. #define PROP_MAX__SETPROCESSMEMORYLIMIT (1)
  225. #define PROP_DEFAULT__SETPROCESSMEMORYLIMIT (0)
  226. #define PROP_MIN__PROCESSMEMORYLIMIT (0)
  227. #define PROP_MAX__PROCESSMEMORYLIMIT (4294967295)
  228. #define PROP_DEFAULT__PROCESSMEMORYLIMIT (0)
  229. #define PROP_MIN__ALLOWLOCALADMINTOKENS (0)
  230. #define PROP_MAX__ALLOWLOCALADMINTOKENS (1)
  231. #define PROP_DEFAULT__ALLOWLOCALADMINTOKENS (1)
  232. #define PROP_MIN__ALLOWUSEOFRESTRICTEDTOKENS (0)
  233. #define PROP_MAX__ALLOWUSEOFRESTRICTEDTOKENS (1)
  234. #define PROP_DEFAULT__ALLOWUSEOFRESTRICTEDTOKENS (1)
  235. //
  236. // genjob resource read-write private properties.
  237. //
  238. RESUTIL_PROPERTY_ITEM
  239. GenJobResourcePrivateProperties[] = {
  240. { PROP_NAME__COMMANDLINE,
  241. NULL,
  242. CLUSPROP_FORMAT_SZ,
  243. 0, 0, 0,
  244. RESUTIL_PROPITEM_REQUIRED,
  245. FIELD_OFFSET(GENJOB_PROPS, CommandLine)
  246. },
  247. { PROP_NAME__CURRENTDIRECTORY,
  248. NULL,
  249. CLUSPROP_FORMAT_SZ,
  250. 0, 0, 0,
  251. RESUTIL_PROPITEM_REQUIRED,
  252. FIELD_OFFSET(GENJOB_PROPS, CurrentDirectory)
  253. },
  254. { PROP_NAME__INTERACTWITHDESKTOP,
  255. NULL,
  256. CLUSPROP_FORMAT_DWORD,
  257. PROP_DEFAULT__INTERACTWITHDESKTOP,
  258. PROP_MIN__INTERACTWITHDESKTOP,
  259. PROP_MAX__INTERACTWITHDESKTOP,
  260. 0,
  261. FIELD_OFFSET(GENJOB_PROPS, InteractWithDesktop)
  262. },
  263. { PROP_NAME__USENETWORKNAME,
  264. NULL,
  265. CLUSPROP_FORMAT_DWORD,
  266. PROP_DEFAULT__USENETWORKNAME,
  267. PROP_MIN__USENETWORKNAME,
  268. PROP_MAX__USENETWORKNAME,
  269. 0,
  270. FIELD_OFFSET(GENJOB_PROPS, UseNetworkName)
  271. },
  272. { PROP_NAME__USEDEFAULTS,
  273. NULL,
  274. CLUSPROP_FORMAT_DWORD,
  275. PROP_DEFAULT__USEDEFAULTS,
  276. PROP_MIN__USEDEFAULTS,
  277. PROP_MAX__USEDEFAULTS,
  278. 0,
  279. FIELD_OFFSET(GENJOB_PROPS, UseDefaults)
  280. },
  281. { PROP_NAME__PROCSCANBREAKAWAY,
  282. NULL,
  283. CLUSPROP_FORMAT_DWORD,
  284. PROP_DEFAULT__PROCSCANBREAKAWAY,
  285. PROP_MIN__PROCSCANBREAKAWAY,
  286. PROP_MAX__PROCSCANBREAKAWAY,
  287. RESUTIL_PROPITEM_SIGNED,
  288. FIELD_OFFSET( GENJOB_PROPS, ProcsCanBreakaway )
  289. },
  290. { PROP_NAME__PROCSCANSILENTLYBREAKAWAY,
  291. NULL,
  292. CLUSPROP_FORMAT_DWORD,
  293. PROP_DEFAULT__PROCSCANSILENTLYBREAKAWAY,
  294. PROP_MIN__PROCSCANSILENTLYBREAKAWAY,
  295. PROP_MAX__PROCSCANSILENTLYBREAKAWAY,
  296. RESUTIL_PROPITEM_SIGNED,
  297. FIELD_OFFSET( GENJOB_PROPS, ProcsCanSilentlyBreakaway )
  298. },
  299. { PROP_NAME__SETACTIVEPROCESSLIMIT,
  300. NULL,
  301. CLUSPROP_FORMAT_DWORD,
  302. PROP_DEFAULT__SETACTIVEPROCESSLIMIT,
  303. PROP_MIN__SETACTIVEPROCESSLIMIT,
  304. PROP_MAX__SETACTIVEPROCESSLIMIT,
  305. 0,
  306. FIELD_OFFSET( GENJOB_PROPS, SetActiveProcessLimit )
  307. },
  308. { PROP_NAME__ACTIVEPROCESSLIMIT,
  309. NULL,
  310. CLUSPROP_FORMAT_DWORD,
  311. PROP_DEFAULT__ACTIVEPROCESSLIMIT,
  312. PROP_MIN__ACTIVEPROCESSLIMIT,
  313. PROP_MAX__ACTIVEPROCESSLIMIT,
  314. 0,
  315. FIELD_OFFSET( GENJOB_PROPS, ActiveProcessLimit )
  316. },
  317. #if AFFINITY_SUPPORT
  318. { PROP_NAME__SETAFFINITY,
  319. NULL,
  320. CLUSPROP_FORMAT_DWORD,
  321. PROP_DEFAULT__SETAFFINITY,
  322. PROP_MIN__SETAFFINITY,
  323. PROP_MAX__SETAFFINITY,
  324. 0,
  325. FIELD_OFFSET( GENJOB_PROPS, SetAffinity )
  326. },
  327. { PROP_NAME__AFFINITY,
  328. NULL,
  329. CLUSPROP_FORMAT_DWORD,
  330. PROP_DEFAULT__AFFINITY,
  331. PROP_MIN__AFFINITY,
  332. PROP_MAX__AFFINITY,
  333. 0,
  334. FIELD_OFFSET( GENJOB_PROPS, Affinity )
  335. },
  336. #endif
  337. { PROP_NAME__SETJOBUSERTIMELIMIT,
  338. NULL,
  339. CLUSPROP_FORMAT_DWORD,
  340. PROP_DEFAULT__SETJOBUSERTIMELIMIT,
  341. PROP_MIN__SETJOBUSERTIMELIMIT,
  342. PROP_MAX__SETJOBUSERTIMELIMIT,
  343. 0,
  344. FIELD_OFFSET( GENJOB_PROPS, SetJobUserTimeLimit )
  345. },
  346. { PROP_NAME__PERJOBUSERTIMELIMIT,
  347. NULL,
  348. CLUSPROP_FORMAT_DWORD,
  349. PROP_DEFAULT__PERJOBUSERTIMELIMIT,
  350. PROP_MIN__PERJOBUSERTIMELIMIT,
  351. PROP_MAX__PERJOBUSERTIMELIMIT,
  352. 0,
  353. FIELD_OFFSET( GENJOB_PROPS, PerJobUserTimeLimit )
  354. },
  355. { PROP_NAME__SETPRIORITYCLASS,
  356. NULL,
  357. CLUSPROP_FORMAT_DWORD,
  358. PROP_DEFAULT__SETPRIORITYCLASS,
  359. PROP_MIN__SETPRIORITYCLASS,
  360. PROP_MAX__SETPRIORITYCLASS,
  361. 0,
  362. FIELD_OFFSET( GENJOB_PROPS, SetPriorityClass )
  363. },
  364. { PROP_NAME__PRIORITYCLASS,
  365. NULL,
  366. CLUSPROP_FORMAT_DWORD,
  367. PROP_DEFAULT__PRIORITYCLASS,
  368. PROP_MIN__PRIORITYCLASS,
  369. PROP_MAX__PRIORITYCLASS,
  370. 0,
  371. FIELD_OFFSET( GENJOB_PROPS, PriorityClass )
  372. },
  373. { PROP_NAME__SETPROCESSUSERTIMELIMIT,
  374. NULL,
  375. CLUSPROP_FORMAT_DWORD,
  376. PROP_DEFAULT__SETPROCESSUSERTIMELIMIT,
  377. PROP_MIN__SETPROCESSUSERTIMELIMIT,
  378. PROP_MAX__SETPROCESSUSERTIMELIMIT,
  379. 0,
  380. FIELD_OFFSET( GENJOB_PROPS, SetProcessUserTimeLimit )
  381. },
  382. { PROP_NAME__PERPROCESSUSERTIMELIMIT,
  383. NULL,
  384. CLUSPROP_FORMAT_DWORD,
  385. PROP_DEFAULT__PERPROCESSUSERTIMELIMIT,
  386. PROP_MIN__PERPROCESSUSERTIMELIMIT,
  387. PROP_MAX__PERPROCESSUSERTIMELIMIT,
  388. 0,
  389. FIELD_OFFSET( GENJOB_PROPS, PerProcessUserTimeLimit )
  390. },
  391. { PROP_NAME__SETSCHEDULINGCLASS,
  392. NULL,
  393. CLUSPROP_FORMAT_DWORD,
  394. PROP_DEFAULT__SETSCHEDULINGCLASS,
  395. PROP_MIN__SETSCHEDULINGCLASS,
  396. PROP_MAX__SETSCHEDULINGCLASS,
  397. 0,
  398. FIELD_OFFSET( GENJOB_PROPS, SetSchedulingClass )
  399. },
  400. { PROP_NAME__SCHEDULINGCLASS,
  401. NULL,
  402. CLUSPROP_FORMAT_DWORD,
  403. PROP_DEFAULT__SCHEDULINGCLASS,
  404. PROP_MIN__SCHEDULINGCLASS,
  405. PROP_MAX__SCHEDULINGCLASS,
  406. 0,
  407. FIELD_OFFSET( GENJOB_PROPS, SchedulingClass )
  408. },
  409. { PROP_NAME__SETWORKINGSETSIZE,
  410. NULL,
  411. CLUSPROP_FORMAT_DWORD,
  412. PROP_DEFAULT__SETWORKINGSETSIZE,
  413. PROP_MIN__SETWORKINGSETSIZE,
  414. PROP_MAX__SETWORKINGSETSIZE,
  415. 0,
  416. FIELD_OFFSET( GENJOB_PROPS, SetWorkingSetSize )
  417. },
  418. { PROP_NAME__MAXIMUMWORKINGSETSIZE,
  419. NULL,
  420. CLUSPROP_FORMAT_DWORD,
  421. PROP_DEFAULT__MAXIMUMWORKINGSETSIZE,
  422. PROP_MIN__MAXIMUMWORKINGSETSIZE,
  423. PROP_MAX__MAXIMUMWORKINGSETSIZE,
  424. 0,
  425. FIELD_OFFSET( GENJOB_PROPS, MaximumWorkingSetSize )
  426. },
  427. { PROP_NAME__MINIMUMWORKINGSETSIZE,
  428. NULL,
  429. CLUSPROP_FORMAT_DWORD,
  430. PROP_DEFAULT__MINIMUMWORKINGSETSIZE,
  431. PROP_MIN__MINIMUMWORKINGSETSIZE,
  432. PROP_MAX__MINIMUMWORKINGSETSIZE,
  433. 0,
  434. FIELD_OFFSET( GENJOB_PROPS, MinimumWorkingSetSize )
  435. },
  436. { PROP_NAME__MANIPULATEDESKTOPS,
  437. NULL,
  438. CLUSPROP_FORMAT_DWORD,
  439. PROP_DEFAULT__MANIPULATEDESKTOPS,
  440. PROP_MIN__MANIPULATEDESKTOPS,
  441. PROP_MAX__MANIPULATEDESKTOPS,
  442. RESUTIL_PROPITEM_SIGNED,
  443. FIELD_OFFSET( GENJOB_PROPS, ManipulateDesktops )
  444. },
  445. { PROP_NAME__CHANGEDISPLAYSETTINGS,
  446. NULL,
  447. CLUSPROP_FORMAT_DWORD,
  448. PROP_DEFAULT__CHANGEDISPLAYSETTINGS,
  449. PROP_MIN__CHANGEDISPLAYSETTINGS,
  450. PROP_MAX__CHANGEDISPLAYSETTINGS,
  451. RESUTIL_PROPITEM_SIGNED,
  452. FIELD_OFFSET( GENJOB_PROPS, ChangeDisplaySettings )
  453. },
  454. { PROP_NAME__ALLOWSYSTEMSHUTDOWN,
  455. NULL,
  456. CLUSPROP_FORMAT_DWORD,
  457. PROP_DEFAULT__ALLOWSYSTEMSHUTDOWN,
  458. PROP_MIN__ALLOWSYSTEMSHUTDOWN,
  459. PROP_MAX__ALLOWSYSTEMSHUTDOWN,
  460. RESUTIL_PROPITEM_SIGNED,
  461. FIELD_OFFSET( GENJOB_PROPS, AllowSystemShutdown )
  462. },
  463. { PROP_NAME__ACCESSGLOBALATOMS,
  464. NULL,
  465. CLUSPROP_FORMAT_DWORD,
  466. PROP_DEFAULT__ACCESSGLOBALATOMS,
  467. PROP_MIN__ACCESSGLOBALATOMS,
  468. PROP_MAX__ACCESSGLOBALATOMS,
  469. RESUTIL_PROPITEM_SIGNED,
  470. FIELD_OFFSET( GENJOB_PROPS, AccessGlobalAtoms )
  471. },
  472. { PROP_NAME__ALLOWOTHERPROCESSUSERHANDLES,
  473. NULL,
  474. CLUSPROP_FORMAT_DWORD,
  475. PROP_DEFAULT__ALLOWOTHERPROCESSUSERHANDLES,
  476. PROP_MIN__ALLOWOTHERPROCESSUSERHANDLES,
  477. PROP_MAX__ALLOWOTHERPROCESSUSERHANDLES,
  478. RESUTIL_PROPITEM_SIGNED,
  479. FIELD_OFFSET( GENJOB_PROPS, AllowOtherProcessUSERHandles )
  480. },
  481. { PROP_NAME__READFROMCLIPBOARD,
  482. NULL,
  483. CLUSPROP_FORMAT_DWORD,
  484. PROP_DEFAULT__READFROMCLIPBOARD,
  485. PROP_MIN__READFROMCLIPBOARD,
  486. PROP_MAX__READFROMCLIPBOARD,
  487. RESUTIL_PROPITEM_SIGNED,
  488. FIELD_OFFSET( GENJOB_PROPS, ReadFromClipboard )
  489. },
  490. { PROP_NAME__CHANGESYSTEMPARAMETERS,
  491. NULL,
  492. CLUSPROP_FORMAT_DWORD,
  493. PROP_DEFAULT__CHANGESYSTEMPARAMETERS,
  494. PROP_MIN__CHANGESYSTEMPARAMETERS,
  495. PROP_MAX__CHANGESYSTEMPARAMETERS,
  496. RESUTIL_PROPITEM_SIGNED,
  497. FIELD_OFFSET( GENJOB_PROPS, ChangeSystemParameters )
  498. },
  499. { PROP_NAME__WRITETOCLIPBOARD,
  500. NULL,
  501. CLUSPROP_FORMAT_DWORD,
  502. PROP_DEFAULT__WRITETOCLIPBOARD,
  503. PROP_MIN__WRITETOCLIPBOARD,
  504. PROP_MAX__WRITETOCLIPBOARD,
  505. RESUTIL_PROPITEM_SIGNED,
  506. FIELD_OFFSET( GENJOB_PROPS, WriteToClipboard )
  507. },
  508. { PROP_NAME__TERMINATEONTIMELIMIT,
  509. NULL,
  510. CLUSPROP_FORMAT_DWORD,
  511. PROP_DEFAULT__TERMINATEONTIMELIMIT,
  512. PROP_MIN__TERMINATEONTIMELIMIT,
  513. PROP_MAX__TERMINATEONTIMELIMIT,
  514. RESUTIL_PROPITEM_SIGNED,
  515. FIELD_OFFSET( GENJOB_PROPS, TerminateOnTimeLimit )
  516. },
  517. { PROP_NAME__SETJOBMEMORYLIMIT,
  518. NULL,
  519. CLUSPROP_FORMAT_DWORD,
  520. PROP_DEFAULT__SETJOBMEMORYLIMIT,
  521. PROP_MIN__SETJOBMEMORYLIMIT,
  522. PROP_MAX__SETJOBMEMORYLIMIT,
  523. 0,
  524. FIELD_OFFSET( GENJOB_PROPS, SetJobMemoryLimit )
  525. },
  526. { PROP_NAME__JOBMEMORYLIMIT,
  527. NULL,
  528. CLUSPROP_FORMAT_DWORD,
  529. PROP_DEFAULT__JOBMEMORYLIMIT,
  530. PROP_MIN__JOBMEMORYLIMIT,
  531. PROP_MAX__JOBMEMORYLIMIT,
  532. 0,
  533. FIELD_OFFSET( GENJOB_PROPS, JobMemoryLimit )
  534. },
  535. { PROP_NAME__SETPROCESSMEMORYLIMIT,
  536. NULL,
  537. CLUSPROP_FORMAT_DWORD,
  538. PROP_DEFAULT__SETPROCESSMEMORYLIMIT,
  539. PROP_MIN__SETPROCESSMEMORYLIMIT,
  540. PROP_MAX__SETPROCESSMEMORYLIMIT,
  541. 0,
  542. FIELD_OFFSET( GENJOB_PROPS, SetProcessMemoryLimit )
  543. },
  544. { PROP_NAME__PROCESSMEMORYLIMIT,
  545. NULL,
  546. CLUSPROP_FORMAT_DWORD,
  547. PROP_DEFAULT__PROCESSMEMORYLIMIT,
  548. PROP_MIN__PROCESSMEMORYLIMIT,
  549. PROP_MAX__PROCESSMEMORYLIMIT,
  550. 0,
  551. FIELD_OFFSET( GENJOB_PROPS, ProcessMemoryLimit )
  552. },
  553. { PROP_NAME__ALLOWLOCALADMINTOKENS,
  554. NULL,
  555. CLUSPROP_FORMAT_DWORD,
  556. PROP_DEFAULT__ALLOWLOCALADMINTOKENS,
  557. PROP_MIN__ALLOWLOCALADMINTOKENS,
  558. PROP_MAX__ALLOWLOCALADMINTOKENS,
  559. RESUTIL_PROPITEM_SIGNED,
  560. FIELD_OFFSET( GENJOB_PROPS, AllowLocalAdminTokens )
  561. },
  562. { PROP_NAME__ALLOWUSEOFRESTRICTEDTOKENS,
  563. NULL,
  564. CLUSPROP_FORMAT_DWORD,
  565. PROP_DEFAULT__ALLOWUSEOFRESTRICTEDTOKENS,
  566. PROP_MIN__ALLOWUSEOFRESTRICTEDTOKENS,
  567. PROP_MAX__ALLOWUSEOFRESTRICTEDTOKENS,
  568. RESUTIL_PROPITEM_SIGNED,
  569. FIELD_OFFSET( GENJOB_PROPS, AllowUseOfRestrictedTokens )
  570. },
  571. { 0 }
  572. };
  573. //
  574. // completion port vars. A separate thread is spun up when the first resource
  575. // goes online. This thread waits for activity on the completion port
  576. // handle. When the last resource goes offline, the port is closed and the
  577. // thread exits. Each time a resource comes online, it is associated with the
  578. // port.
  579. //
  580. CRITICAL_SECTION GenJobPortLock;
  581. HANDLE GenJobPort;
  582. LONG GenJobOnlineResources = 0;
  583. HANDLE GenJobPortThread = NULL;
  584. // Event Logging routine
  585. #define g_LogEvent ClusResLogEvent
  586. #define g_SetResourceStatus ClusResSetResourceStatus
  587. // Forward reference to our RESAPI function table.
  588. extern CLRES_FUNCTION_TABLE GenJobFunctionTable;
  589. //
  590. // Forward routines
  591. //
  592. BOOLEAN
  593. VerifyApp(
  594. IN RESID ResourceId,
  595. IN BOOLEAN IsAliveFlag
  596. );
  597. DWORD
  598. GenJobGetPrivateResProperties(
  599. IN OUT PGENJOB_RESOURCE ResourceEntry,
  600. OUT PVOID OutBuffer,
  601. IN DWORD OutBufferSize,
  602. OUT LPDWORD BytesReturned
  603. );
  604. DWORD
  605. GenJobValidatePrivateResProperties(
  606. IN OUT PGENJOB_RESOURCE ResourceEntry,
  607. IN PVOID InBuffer,
  608. IN DWORD InBufferSize,
  609. OUT PGENJOB_PROPS Params
  610. );
  611. DWORD
  612. GenJobSetPrivateResProperties(
  613. IN OUT PGENJOB_RESOURCE ResourceEntry,
  614. IN PVOID InBuffer,
  615. IN DWORD InBufferSize
  616. );
  617. #if LOADBAL_SUPPORT
  618. DWORD
  619. GenJobGetPids(
  620. IN OUT PGENJOB_RESOURCE ResourceEntry,
  621. OUT PVOID OutBuffer,
  622. IN DWORD OutBufferSize,
  623. OUT LPDWORD BytesReturned
  624. );
  625. #endif
  626. VOID
  627. GenJobTearDownCompletionPort(
  628. VOID
  629. );
  630. BOOLEAN
  631. GenJobInit(
  632. VOID
  633. )
  634. {
  635. return(TRUE);
  636. }
  637. BOOLEAN
  638. WINAPI
  639. GenJobDllEntryPoint(
  640. IN HINSTANCE DllHandle,
  641. IN DWORD Reason,
  642. IN LPVOID Reserved
  643. )
  644. {
  645. switch( Reason ) {
  646. case DLL_PROCESS_ATTACH:
  647. if ( !GenJobInit() ) {
  648. return(FALSE);
  649. }
  650. InitializeCriticalSection( &GenJobPortLock );
  651. break;
  652. case DLL_PROCESS_DETACH:
  653. break;
  654. default:
  655. break;
  656. }
  657. return(TRUE);
  658. } // GenJobDllEntryPoint
  659. RESID
  660. WINAPI
  661. GenJobOpen(
  662. IN LPCWSTR ResourceName,
  663. IN HKEY ResourceKey,
  664. IN RESOURCE_HANDLE ResourceHandle
  665. )
  666. /*++
  667. Routine Description:
  668. Open routine for generic job object resource.
  669. Arguments:
  670. ResourceName - supplies the resource name
  671. ResourceKey - supplies a handle to the resource's cluster registry key
  672. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  673. is called.
  674. Return Value:
  675. RESID of created resource
  676. Zero on failure
  677. --*/
  678. {
  679. RESID appResid = 0;
  680. DWORD status;
  681. HKEY parametersKey = NULL;
  682. HKEY resKey = NULL;
  683. PGENJOB_RESOURCE resourceEntry = NULL;
  684. DWORD paramNameMaxSize = 0;
  685. HCLUSTER hCluster;
  686. //
  687. // Get registry parameters for this resource.
  688. //
  689. status = ClusterRegOpenKey(ResourceKey,
  690. CLUSREG_KEYNAME_PARAMETERS,
  691. KEY_READ,
  692. &parametersKey );
  693. if ( status != NO_ERROR ) {
  694. (g_LogEvent)(ResourceHandle,
  695. LOG_ERROR,
  696. L"Unable to open parameters key. Error: %1!u!.\n",
  697. status );
  698. goto error_exit;
  699. }
  700. //
  701. // Get a handle to our resource key so that we can get our name later
  702. // if we need to log an event.
  703. //
  704. status = ClusterRegOpenKey(ResourceKey,
  705. L"",
  706. KEY_READ,
  707. &resKey);
  708. if (status != ERROR_SUCCESS) {
  709. (g_LogEvent)(ResourceHandle,
  710. LOG_ERROR,
  711. L"Unable to open resource key. Error: %1!u!.\n",
  712. status );
  713. goto error_exit;
  714. }
  715. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(GENJOB_RESOURCE) );
  716. if ( resourceEntry == NULL ) {
  717. (g_LogEvent)(
  718. ResourceHandle,
  719. LOG_ERROR,
  720. L"Failed to allocate a process info structure.\n" );
  721. status = ERROR_NOT_ENOUGH_MEMORY;
  722. goto error_exit;
  723. }
  724. ZeroMemory( resourceEntry, sizeof(GENJOB_RESOURCE) );
  725. resourceEntry->ResourceHandle = ResourceHandle;
  726. resourceEntry->ResourceKey = resKey;
  727. resourceEntry->ParametersKey = parametersKey;
  728. resourceEntry->OfflineEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  729. if ( resourceEntry->OfflineEvent == NULL ) {
  730. status = GetLastError();
  731. (g_LogEvent)(ResourceHandle,
  732. LOG_ERROR,
  733. L"Failed to create offline event, error %1!u!.\n",
  734. status);
  735. goto error_exit;
  736. }
  737. hCluster = OpenCluster(NULL);
  738. if (hCluster == NULL) {
  739. status = GetLastError();
  740. (g_LogEvent)(ResourceHandle,
  741. LOG_ERROR,
  742. L"Failed to open cluster, error %1!u!.\n",
  743. status);
  744. goto error_exit;
  745. }
  746. //
  747. // get a cluster resource handle to this resource
  748. //
  749. resourceEntry->hResource = OpenClusterResource( hCluster, ResourceName );
  750. status = GetLastError();
  751. CloseCluster(hCluster);
  752. if (resourceEntry->hResource == NULL) {
  753. (g_LogEvent)(
  754. ResourceHandle,
  755. LOG_ERROR,
  756. L"Failed to open resource, error %1!u!.\n",
  757. status
  758. );
  759. goto error_exit;
  760. }
  761. appResid = (RESID)resourceEntry;
  762. error_exit:
  763. if ( appResid == NULL) {
  764. if (parametersKey != NULL) {
  765. ClusterRegCloseKey( parametersKey );
  766. }
  767. if (resKey != NULL) {
  768. ClusterRegCloseKey( resKey );
  769. }
  770. }
  771. if ( (appResid == 0) && (resourceEntry != NULL) ) {
  772. LocalFree( resourceEntry );
  773. }
  774. if ( status != ERROR_SUCCESS ) {
  775. SetLastError( status );
  776. }
  777. return(appResid);
  778. } // GenJobOpen
  779. DWORD
  780. WINAPI
  781. GenJobPortRoutine(
  782. LPVOID Parameter
  783. )
  784. /*++
  785. Routine Description:
  786. Monitors IO on completion port. Exits if terminate event is signalled
  787. Arguments:
  788. Parameter - not used
  789. Return Value:
  790. None
  791. --*/
  792. {
  793. PGENJOB_RESOURCE resource;
  794. DWORD msgId;
  795. DWORD msgValue;
  796. LPWSTR logMessage;
  797. do {
  798. if ( GetQueuedCompletionStatus(GenJobPort,
  799. &msgId,
  800. (PULONG_PTR)&resource,
  801. (LPOVERLAPPED *)&msgValue,
  802. INFINITE))
  803. {
  804. if ( resource == NULL ) {
  805. break;
  806. }
  807. switch ( msgId ) {
  808. case JOB_OBJECT_MSG_END_OF_JOB_TIME:
  809. logMessage = L"End of job time limit has been reached.\n";
  810. break;
  811. case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
  812. logMessage = L"End of process time limit has been reached for process ID %1!u!.\n";
  813. break;
  814. case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
  815. logMessage = L"The active process limit has been exceeded.\n";
  816. break;
  817. case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
  818. logMessage = L"The active process count has reached zero.\n";
  819. //
  820. // signal that the last process in the job exited.
  821. //
  822. SetEvent( resource->OfflineEvent );
  823. break;
  824. case JOB_OBJECT_MSG_NEW_PROCESS:
  825. logMessage = L"Process ID %1!u! has been added to the job.\n";
  826. break;
  827. case JOB_OBJECT_MSG_EXIT_PROCESS:
  828. logMessage = L"Process ID %1!u! has exited.\n";
  829. break;
  830. case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
  831. logMessage = L"Process ID %1!u! has abnormally exited.\n";
  832. break;
  833. case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
  834. logMessage = L"Process ID %1!u! has exceeded its memory limit\n";
  835. break;
  836. case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
  837. logMessage = L"Process ID %1!u! has caused the job has to exceed its memory limit.\n";
  838. break;
  839. default:
  840. (g_LogEvent)(resource->ResourceHandle,
  841. LOG_ERROR,
  842. L"Unknown Job message; message ID = %1!u!, msg value = %2!u!\n",
  843. msgId,
  844. msgValue);
  845. goto skip_message;
  846. }
  847. //
  848. // log the appropriate msg
  849. //
  850. (g_LogEvent)(resource->ResourceHandle,
  851. LOG_ERROR,
  852. logMessage,
  853. msgValue);
  854. skip_message:
  855. ;
  856. }
  857. } while (1);
  858. return 0;
  859. }
  860. DWORD
  861. GenJobInitializeCompletionPort(
  862. IN RESOURCE_HANDLE ResourceHandle
  863. )
  864. /*++
  865. Routine Description:
  866. Init all the giblets associatd with the completion port, i.e., create the
  867. port, spin up the thread that waits on the port, etc. Must be called with
  868. GenJobPortLock held.
  869. Arguments:
  870. None
  871. Return Value:
  872. ERROR_SUCCESS if everything worked
  873. --*/
  874. {
  875. DWORD status = ERROR_SUCCESS;
  876. DWORD threadId;
  877. //
  878. // create the completion port
  879. //
  880. GenJobPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
  881. if ( GenJobPort == NULL ) {
  882. status = GetLastError();
  883. (g_LogEvent)(ResourceHandle,
  884. LOG_ERROR,
  885. L"Unable to create completion port. Error: %1!u!.\n",
  886. status );
  887. return status;
  888. }
  889. //
  890. // create the thread that waits on the port
  891. //
  892. GenJobPortThread = CreateThread(NULL, // default security
  893. 0, // default stack
  894. GenJobPortRoutine,
  895. 0, // routine parameter
  896. 0, // creation flags
  897. &threadId);
  898. if ( GenJobPortThread == NULL ) {
  899. status = GetLastError();
  900. (g_LogEvent)(ResourceHandle,
  901. LOG_ERROR,
  902. L"Unable to create completion port thread. Error: %1!u!.\n",
  903. status );
  904. }
  905. return status;
  906. }
  907. DWORD
  908. SetJobObjectClasses(
  909. IN PGENJOB_RESOURCE ResourceEntry
  910. )
  911. /*++
  912. Routine Description:
  913. build the job object class struct from the operational data in the
  914. resource entry and call SetInformationJobObject
  915. Arguments:
  916. ResourceEntry - pointer to netname resource being manipulated
  917. Return Value:
  918. ERROR_SUCCESS if everything worked ok
  919. --*/
  920. {
  921. DWORD status = ERROR_SUCCESS;
  922. PGENJOB_PROPS jobProps = &ResourceEntry->OperationalProps;
  923. JOBOBJECT_BASIC_UI_RESTRICTIONS basicUiLimits;
  924. JOBOBJECT_END_OF_JOB_TIME_INFORMATION timeLimits;
  925. JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedLimits;
  926. JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimits;
  927. //
  928. // init various flag members to their defaults
  929. //
  930. basicUiLimits.UIRestrictionsClass = JOB_OBJECT_UILIMIT_NONE;
  931. securityLimits.SecurityLimitFlags = 0;
  932. extendedLimits.BasicLimitInformation.LimitFlags =
  933. JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
  934. timeLimits.EndOfJobTimeAction = JOB_OBJECT_TERMINATE_AT_END_OF_JOB;
  935. if ( !jobProps->UseDefaults ) {
  936. //
  937. // set basic limits. convert time limits from secs to 100ns units
  938. //
  939. if ( jobProps->SetProcessUserTimeLimit ) {
  940. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
  941. extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart =
  942. jobProps->PerProcessUserTimeLimit * 10 * 1000 * 1000;
  943. }
  944. if ( jobProps->SetJobUserTimeLimit ) {
  945. extendedLimits.BasicLimitInformation.LimitFlags |=
  946. JOB_OBJECT_LIMIT_JOB_TIME;
  947. extendedLimits.BasicLimitInformation.PerJobUserTimeLimit.QuadPart =
  948. jobProps->PerJobUserTimeLimit * 10 * 1000 * 1000;
  949. }
  950. if ( jobProps->SetWorkingSetSize ) {
  951. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
  952. extendedLimits.BasicLimitInformation.MinimumWorkingSetSize = jobProps->MinimumWorkingSetSize;
  953. extendedLimits.BasicLimitInformation.MaximumWorkingSetSize = jobProps->MaximumWorkingSetSize;
  954. }
  955. if ( jobProps->SetActiveProcessLimit ) {
  956. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  957. extendedLimits.BasicLimitInformation.ActiveProcessLimit = jobProps->ActiveProcessLimit;
  958. }
  959. #if 0
  960. if ( jobProps->SetAffininty ) {
  961. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY;
  962. extendedLimits.BasicLimitInformation.Affinity = jobProps->Affinity;
  963. }
  964. #endif
  965. if ( jobProps->SetPriorityClass ) {
  966. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  967. extendedLimits.BasicLimitInformation.PriorityClass = jobProps->PriorityClass;
  968. }
  969. if ( jobProps->SetSchedulingClass ) {
  970. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
  971. extendedLimits.BasicLimitInformation.SchedulingClass = jobProps->SchedulingClass;
  972. }
  973. if ( jobProps->ProcsCanBreakaway ) {
  974. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
  975. }
  976. if ( jobProps->ProcsCanSilentlyBreakaway ) {
  977. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
  978. }
  979. //
  980. // basic UI limits
  981. //
  982. if ( !jobProps->ManipulateDesktops ) {
  983. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
  984. }
  985. if ( !jobProps->ChangeDisplaySettings ) {
  986. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
  987. }
  988. if ( !jobProps->AllowSystemShutdown ) {
  989. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
  990. }
  991. if ( !jobProps->AccessGlobalAtoms ) {
  992. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
  993. }
  994. if ( !jobProps->AllowOtherProcessUSERHandles ) {
  995. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
  996. }
  997. if ( !jobProps->ReadFromClipboard ) {
  998. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
  999. }
  1000. if ( !jobProps->ChangeSystemParameters ) {
  1001. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
  1002. }
  1003. if ( !jobProps->WriteToClipboard ) {
  1004. basicUiLimits.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
  1005. }
  1006. //
  1007. // time limits
  1008. //
  1009. if ( !jobProps->TerminateOnTimeLimit ) {
  1010. timeLimits.EndOfJobTimeAction = JOB_OBJECT_POST_AT_END_OF_JOB;
  1011. }
  1012. //
  1013. // extended limits
  1014. //
  1015. if ( jobProps->SetProcessMemoryLimit ) {
  1016. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  1017. extendedLimits.ProcessMemoryLimit = jobProps->ProcessMemoryLimit;
  1018. }
  1019. if ( jobProps->SetJobMemoryLimit ) {
  1020. extendedLimits.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
  1021. extendedLimits.JobMemoryLimit = jobProps->JobMemoryLimit;
  1022. }
  1023. //
  1024. // security limits
  1025. //
  1026. if ( !jobProps->AllowUseOfRestrictedTokens ) {
  1027. securityLimits.SecurityLimitFlags |= JOB_OBJECT_SECURITY_RESTRICTED_TOKEN;
  1028. }
  1029. if ( !jobProps->AllowLocalAdminTokens ) {
  1030. securityLimits.SecurityLimitFlags |= JOB_OBJECT_SECURITY_NO_ADMIN;
  1031. }
  1032. }
  1033. //
  1034. // extended limits which includes basic. we always do this since there are
  1035. // some basic limit flags we want to set regardless of whether defaults
  1036. // are used
  1037. //
  1038. if ( !SetInformationJobObject(ResourceEntry->JobHandle,
  1039. JobObjectExtendedLimitInformation,
  1040. &extendedLimits,
  1041. sizeof( extendedLimits )))
  1042. {
  1043. status = GetLastError();
  1044. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1045. LOG_ERROR,
  1046. L"Can't set extended limit information. Error: %1!u!.\n",
  1047. status );
  1048. goto error_exit;
  1049. }
  1050. //
  1051. // set the other limits as appropriate
  1052. //
  1053. if ( !SetInformationJobObject(ResourceEntry->JobHandle,
  1054. JobObjectBasicUIRestrictions,
  1055. &basicUiLimits,
  1056. sizeof( basicUiLimits )))
  1057. {
  1058. status = GetLastError();
  1059. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1060. LOG_ERROR,
  1061. L"Can't set basic UI limit information. Error: %1!u!.\n",
  1062. status );
  1063. goto error_exit;
  1064. }
  1065. //
  1066. // time is special in that we only set if they want something other than
  1067. // the default
  1068. //
  1069. if ( !SetInformationJobObject(ResourceEntry->JobHandle,
  1070. JobObjectEndOfJobTimeInformation,
  1071. &timeLimits,
  1072. sizeof( timeLimits )))
  1073. {
  1074. status = GetLastError();
  1075. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1076. LOG_ERROR,
  1077. L"Can't set end of job time information. Error: %1!u!.\n",
  1078. status );
  1079. goto error_exit;
  1080. }
  1081. if ( !SetInformationJobObject(ResourceEntry->JobHandle,
  1082. JobObjectSecurityLimitInformation,
  1083. &securityLimits,
  1084. sizeof( securityLimits )))
  1085. {
  1086. status = GetLastError();
  1087. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1088. LOG_ERROR,
  1089. L"Can't set security limit information. Error: %1!u!.\n",
  1090. status );
  1091. }
  1092. error_exit:
  1093. return status;
  1094. }
  1095. DWORD
  1096. GenJobOnlineThread(
  1097. IN PCLUS_WORKER pWorker,
  1098. IN PGENJOB_RESOURCE ResourceEntry
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. Brings a disk resource online.
  1103. Arguments:
  1104. Worker - Supplies the worker structure
  1105. Context - A pointer to the GenJob block for this resource.
  1106. Returns:
  1107. ERROR_SUCCESS if successful.
  1108. Win32 error code on failure.
  1109. --*/
  1110. {
  1111. RESOURCE_STATUS resourceStatus;
  1112. DWORD status = ERROR_SUCCESS;
  1113. STARTUPINFO startupInfo;
  1114. PROCESS_INFORMATION processInfo;
  1115. LPWSTR nameOfPropInError;
  1116. LPVOID Environment = NULL;
  1117. JOBOBJECT_ASSOCIATE_COMPLETION_PORT portInfo;
  1118. //
  1119. // initial resource status struct
  1120. //
  1121. ResUtilInitializeResourceStatus( &resourceStatus );
  1122. resourceStatus.ResourceState = ClusterResourceFailed;
  1123. //resourceStatus.WaitHint = 0;
  1124. resourceStatus.CheckPoint = 1;
  1125. //
  1126. // create the unnamed completion port if necessary. If online fails at
  1127. // some point, resmon will call GenJobTerminate which decrements the count
  1128. //
  1129. EnterCriticalSection( &GenJobPortLock );
  1130. if ( ++GenJobOnlineResources == 1 ) {
  1131. status = GenJobInitializeCompletionPort( ResourceEntry->ResourceHandle );
  1132. if ( status != ERROR_SUCCESS ) {
  1133. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1134. LOG_ERROR,
  1135. L"Unable to create completon port. Error: %1!u!.\n",
  1136. status );
  1137. LeaveCriticalSection( &GenJobPortLock );
  1138. goto error_exit;
  1139. }
  1140. }
  1141. LeaveCriticalSection( &GenJobPortLock );
  1142. //
  1143. // create an un-named job object
  1144. //
  1145. ResourceEntry->JobHandle = CreateJobObject( NULL, NULL );
  1146. if ( ResourceEntry->JobHandle == NULL ) {
  1147. status = GetLastError();
  1148. (g_LogEvent)(
  1149. ResourceEntry->ResourceHandle,
  1150. LOG_ERROR,
  1151. L"Unable to create job object. Error: %1!u!.\n",
  1152. status );
  1153. goto error_exit;
  1154. }
  1155. //
  1156. // Read our parameters.
  1157. //
  1158. status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
  1159. GenJobResourcePrivateProperties,
  1160. (LPBYTE) &ResourceEntry->OperationalProps,
  1161. TRUE, // CheckForRequiredProperties
  1162. &nameOfPropInError );
  1163. if ( status != ERROR_SUCCESS ) {
  1164. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1165. LOG_ERROR,
  1166. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1167. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1168. status );
  1169. goto error_exit;
  1170. }
  1171. //
  1172. // move our prop values into the job object structs
  1173. //
  1174. status = SetJobObjectClasses( ResourceEntry );
  1175. if ( status != ERROR_SUCCESS ) {
  1176. goto error_exit;
  1177. }
  1178. //
  1179. // set the job object completion port data
  1180. //
  1181. portInfo.CompletionKey = ResourceEntry;
  1182. portInfo.CompletionPort = GenJobPort;
  1183. if ( !SetInformationJobObject(ResourceEntry->JobHandle,
  1184. JobObjectAssociateCompletionPortInformation,
  1185. &portInfo,
  1186. sizeof( portInfo )))
  1187. {
  1188. status = GetLastError();
  1189. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1190. LOG_ERROR,
  1191. L"Unable to associate completion port with job. Error: %1!u!.\n",
  1192. status );
  1193. goto error_exit;
  1194. }
  1195. //
  1196. // fake the network name if told to
  1197. //
  1198. if ( ResourceEntry->OperationalProps.UseNetworkName ) {
  1199. Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  1200. }
  1201. //
  1202. // fire it up!
  1203. //
  1204. ZeroMemory( &startupInfo, sizeof(startupInfo) );
  1205. startupInfo.cb = sizeof(startupInfo);
  1206. startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  1207. if ( ResourceEntry->OperationalProps.InteractWithDesktop ) {
  1208. startupInfo.lpDesktop = L"WinSta0\\Default";
  1209. startupInfo.wShowWindow = SW_SHOW;
  1210. } else {
  1211. startupInfo.wShowWindow = SW_HIDE;
  1212. }
  1213. if ( !CreateProcess( NULL,
  1214. ResourceEntry->OperationalProps.CommandLine,
  1215. NULL,
  1216. NULL,
  1217. FALSE,
  1218. CREATE_UNICODE_ENVIRONMENT,
  1219. Environment,
  1220. ResourceEntry->OperationalProps.CurrentDirectory,
  1221. &startupInfo,
  1222. &processInfo))
  1223. {
  1224. status = GetLastError();
  1225. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  1226. LOG_CRITICAL,
  1227. RES_GENJOB_CREATE_FAILED,
  1228. sizeof(status),
  1229. &status);
  1230. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1231. LOG_ERROR,
  1232. L"Failed to create process. Error: %1!u!.\n",
  1233. status );
  1234. goto error_exit;
  1235. }
  1236. //
  1237. // associate the proc with the job
  1238. //
  1239. if ( !AssignProcessToJobObject(ResourceEntry->JobHandle,
  1240. processInfo.hProcess))
  1241. {
  1242. status = GetLastError();
  1243. (g_LogEvent)(ResourceEntry->ResourceHandle,
  1244. LOG_ERROR,
  1245. L"Failed to assign process to job. Error: %1!u!.\n",
  1246. status );
  1247. goto error_exit;
  1248. }
  1249. //
  1250. // Save the process Id and close the process/thread handles
  1251. //
  1252. ResourceEntry->ProcessId = processInfo.dwProcessId;
  1253. CloseHandle( processInfo.hThread );
  1254. CloseHandle( processInfo.hProcess );
  1255. ResourceEntry->Online = TRUE;
  1256. //
  1257. // job objects are signalled only when a limit is exceeded so an event is
  1258. // used to indicate when the last process in the job has exited.
  1259. //
  1260. resourceStatus.EventHandle = ResourceEntry->OfflineEvent;
  1261. resourceStatus.ResourceState = ClusterResourceOnline;
  1262. error_exit:
  1263. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  1264. &resourceStatus );
  1265. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  1266. ResourceEntry->Online = TRUE;
  1267. } else {
  1268. ResourceEntry->Online = FALSE;
  1269. }
  1270. if (Environment != NULL) {
  1271. RtlDestroyEnvironment(Environment);
  1272. }
  1273. return(status);
  1274. } // GenJobOnlineThread
  1275. DWORD
  1276. WINAPI
  1277. GenJobOnline(
  1278. IN RESID ResourceId,
  1279. IN OUT PHANDLE EventHandle
  1280. )
  1281. /*++
  1282. Routine Description:
  1283. Online routine for Generic Job Object resource.
  1284. Arguments:
  1285. ResourceId - Supplies resource id to be brought online
  1286. EventHandle - Supplies a pointer to a handle to signal on error.
  1287. Return Value:
  1288. ERROR_SUCCESS if successful.
  1289. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  1290. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  1291. acquire 'ownership'.
  1292. Win32 error code if other failure.
  1293. --*/
  1294. {
  1295. PGENJOB_RESOURCE resourceEntry;
  1296. DWORD status = ERROR_SUCCESS;
  1297. resourceEntry = (PGENJOB_RESOURCE)ResourceId;
  1298. if ( resourceEntry == NULL ) {
  1299. DBG_PRINT( "GenJob: Online request for a nonexistent resource id 0x%p.\n",
  1300. ResourceId );
  1301. return(ERROR_RESOURCE_NOT_FOUND);
  1302. }
  1303. if ( resourceEntry->JobHandle != NULL ) {
  1304. (g_LogEvent)(
  1305. resourceEntry->ResourceHandle,
  1306. LOG_ERROR,
  1307. L"Online request and job object handle is not NULL!\n" );
  1308. return(ERROR_NOT_READY);
  1309. }
  1310. (g_LogEvent)(resourceEntry->ResourceHandle,
  1311. LOG_ERROR,
  1312. L"Online request.\n");
  1313. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  1314. status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  1315. GenJobOnlineThread,
  1316. resourceEntry );
  1317. if ( status == ERROR_SUCCESS ) {
  1318. status = ERROR_IO_PENDING;
  1319. }
  1320. return(status);
  1321. } // GenJobOnline
  1322. VOID
  1323. GenJobTearDownCompletionPort(
  1324. VOID
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. Clean up all the mechanisms associated with the completion port. Must be
  1329. called with GenJobPortLock critsec held.
  1330. Arguments:
  1331. None
  1332. Return Value:
  1333. None
  1334. --*/
  1335. {
  1336. DWORD status;
  1337. //
  1338. // setting lpOverlapped to NULL signals the GenJobPortRoutine to exit
  1339. //
  1340. if ( GenJobPortThread != NULL ) {
  1341. PostQueuedCompletionStatus( GenJobPort, 0, 0, NULL );
  1342. status = WaitForSingleObject( GenJobPortThread, INFINITE );
  1343. CloseHandle( GenJobPortThread );
  1344. GenJobPortThread = NULL;
  1345. }
  1346. if ( GenJobPort != NULL ) {
  1347. CloseHandle( GenJobPort );
  1348. GenJobPort = NULL;
  1349. }
  1350. }
  1351. VOID
  1352. WINAPI
  1353. GenJobTerminate(
  1354. IN RESID ResourceId
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. Terminate routine for Generic Job Object resource.
  1359. Arguments:
  1360. ResourceId - Supplies resource id to be terminated
  1361. Return Value:
  1362. None.
  1363. --*/
  1364. {
  1365. PGENJOB_RESOURCE resourceEntry;
  1366. DWORD status;
  1367. resourceEntry = (PGENJOB_RESOURCE)ResourceId;
  1368. if ( resourceEntry == NULL ) {
  1369. DBG_PRINT( "GenJob: Terminate request for a nonexistent resource id 0x%p\n",
  1370. ResourceId );
  1371. return;
  1372. }
  1373. if ( !TerminateJobObject( resourceEntry->JobHandle, 1 ) ) {
  1374. status = GetLastError();
  1375. if ( status != ERROR_ACCESS_DENIED ) {
  1376. (g_LogEvent)(
  1377. resourceEntry->ResourceHandle,
  1378. LOG_ERROR,
  1379. L"Failed to terminate job object, handle %1!u!. Error: %2!u!.\n",
  1380. resourceEntry->JobHandle,
  1381. status );
  1382. }
  1383. }
  1384. CloseHandle( resourceEntry->JobHandle );
  1385. resourceEntry->JobHandle = NULL;
  1386. //
  1387. // get rid of the completion port if there are no more open resources
  1388. //
  1389. if ( resourceEntry->Online == TRUE ) {
  1390. EnterCriticalSection( &GenJobPortLock );
  1391. ASSERT( GenJobOnlineResources > 0 );
  1392. if ( --GenJobOnlineResources == 0 ) {
  1393. GenJobTearDownCompletionPort();
  1394. }
  1395. LeaveCriticalSection( &GenJobPortLock );
  1396. }
  1397. resourceEntry->Online = FALSE;
  1398. } // GenJobTerminate
  1399. DWORD
  1400. WINAPI
  1401. GenJobOffline(
  1402. IN RESID ResourceId
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. Offline routine for Generic Job Object resource.
  1407. Arguments:
  1408. ResourceId - Supplies the resource to be taken offline
  1409. Return Value:
  1410. ERROR_SUCCESS - always successful.
  1411. --*/
  1412. {
  1413. PGENJOB_RESOURCE resourceEntry = (PGENJOB_RESOURCE)ResourceId;
  1414. (g_LogEvent)(resourceEntry->ResourceHandle,
  1415. LOG_ERROR,
  1416. L"Offline request.\n");
  1417. GenJobTerminate( ResourceId );
  1418. return(ERROR_SUCCESS);
  1419. } // GenJobOffline
  1420. BOOL
  1421. WINAPI
  1422. GenJobIsAlive(
  1423. IN RESID ResourceId
  1424. )
  1425. /*++
  1426. Routine Description:
  1427. IsAlive routine for Generice job object resource.
  1428. Arguments:
  1429. ResourceId - Supplies the resource id to be polled.
  1430. Return Value:
  1431. TRUE - Resource is alive and well
  1432. FALSE - Resource is toast.
  1433. --*/
  1434. {
  1435. return VerifyApp( ResourceId, TRUE );
  1436. } // GenJobIsAlive
  1437. BOOLEAN
  1438. VerifyApp(
  1439. IN RESID ResourceId,
  1440. IN BOOLEAN IsAliveFlag
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. Verify that a Generic Job Objects resource is running
  1445. Arguments:
  1446. ResourceId - Supplies the resource id to be polled.
  1447. IsAliveFlag - TRUE if called from IsAlive, otherwise called from LooksAlive.
  1448. Return Value:
  1449. TRUE - Resource is alive and well
  1450. FALSE - Resource is toast.
  1451. --*/
  1452. {
  1453. return TRUE;
  1454. } // VerifyApp
  1455. BOOL
  1456. WINAPI
  1457. GenJobLooksAlive(
  1458. IN RESID ResourceId
  1459. )
  1460. /*++
  1461. Routine Description:
  1462. LooksAlive routine for Generic Job Objects resource.
  1463. Arguments:
  1464. ResourceId - Supplies the resource id to be polled.
  1465. Return Value:
  1466. TRUE - Resource looks like it is alive and well
  1467. FALSE - Resource looks like it is toast.
  1468. --*/
  1469. {
  1470. return VerifyApp( ResourceId, FALSE );
  1471. } // GenJobLooksAlive
  1472. VOID
  1473. WINAPI
  1474. GenJobClose(
  1475. IN RESID ResourceId
  1476. )
  1477. /*++
  1478. Routine Description:
  1479. Close routine for Generic Job Objects resource.
  1480. Arguments:
  1481. ResourceId - Supplies resource id to be closed
  1482. Return Value:
  1483. None.
  1484. --*/
  1485. {
  1486. PGENJOB_RESOURCE resourceEntry;
  1487. DWORD status;
  1488. resourceEntry = (PGENJOB_RESOURCE)ResourceId;
  1489. if ( resourceEntry == NULL ) {
  1490. DBG_PRINT( "GenJob: Close request for a nonexistent resource id 0x%p\n",
  1491. ResourceId );
  1492. return;
  1493. }
  1494. ClusterRegCloseKey( resourceEntry->ParametersKey );
  1495. ClusterRegCloseKey( resourceEntry->ResourceKey );
  1496. CloseClusterResource( resourceEntry->hResource );
  1497. CloseHandle( resourceEntry->OfflineEvent );
  1498. LocalFree( resourceEntry->OperationalProps.CommandLine );
  1499. LocalFree( resourceEntry->OperationalProps.CurrentDirectory );
  1500. LocalFree( resourceEntry );
  1501. } // GenJobClose
  1502. DWORD
  1503. GenJobResourceControl(
  1504. IN RESID ResourceId,
  1505. IN DWORD ControlCode,
  1506. IN PVOID InBuffer,
  1507. IN DWORD InBufferSize,
  1508. OUT PVOID OutBuffer,
  1509. IN DWORD OutBufferSize,
  1510. OUT LPDWORD BytesReturned
  1511. )
  1512. /*++
  1513. Routine Description:
  1514. ResourceControl routine for Generic Job Object resources.
  1515. Perform the control request specified by ControlCode on the specified
  1516. resource.
  1517. Arguments:
  1518. ResourceId - Supplies the resource id for the specific resource.
  1519. ControlCode - Supplies the control code that defines the action
  1520. to be performed.
  1521. InBuffer - Supplies a pointer to a buffer containing input data.
  1522. InBufferSize - Supplies the size, in bytes, of the data pointed
  1523. to by InBuffer.
  1524. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1525. OutBufferSize - Supplies the size, in bytes, of the available space
  1526. pointed to by OutBuffer.
  1527. BytesReturned - Returns the number of bytes of OutBuffer actually
  1528. filled in by the resource. If OutBuffer is too small, BytesReturned
  1529. contains the total number of bytes for the operation to succeed.
  1530. Return Value:
  1531. ERROR_SUCCESS - The function completed successfully.
  1532. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1533. In some cases, this allows the cluster software to perform the work.
  1534. Win32 error code - The function failed.
  1535. --*/
  1536. {
  1537. DWORD status;
  1538. PGENJOB_RESOURCE resourceEntry;
  1539. DWORD required;
  1540. resourceEntry = (PGENJOB_RESOURCE)ResourceId;
  1541. if ( resourceEntry == NULL ) {
  1542. DBG_PRINT( "GenJob: ResourceControl request for a nonexistent resource id 0x%p\n",
  1543. ResourceId );
  1544. return(FALSE);
  1545. }
  1546. switch ( ControlCode ) {
  1547. case CLUSCTL_RESOURCE_UNKNOWN:
  1548. *BytesReturned = 0;
  1549. status = ERROR_SUCCESS;
  1550. break;
  1551. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  1552. status = ResUtilGetPropertyFormats( GenJobResourcePrivateProperties,
  1553. OutBuffer,
  1554. OutBufferSize,
  1555. BytesReturned,
  1556. &required );
  1557. if ( status == ERROR_MORE_DATA ) {
  1558. *BytesReturned = required;
  1559. }
  1560. break;
  1561. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1562. status = ResUtilEnumProperties( GenJobResourcePrivateProperties,
  1563. OutBuffer,
  1564. OutBufferSize,
  1565. BytesReturned,
  1566. &required );
  1567. if ( status == ERROR_MORE_DATA ) {
  1568. *BytesReturned = required;
  1569. }
  1570. break;
  1571. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1572. status = GenJobGetPrivateResProperties( resourceEntry,
  1573. OutBuffer,
  1574. OutBufferSize,
  1575. BytesReturned );
  1576. break;
  1577. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1578. status = GenJobValidatePrivateResProperties( resourceEntry,
  1579. InBuffer,
  1580. InBufferSize,
  1581. NULL );
  1582. break;
  1583. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1584. status = GenJobSetPrivateResProperties( resourceEntry,
  1585. InBuffer,
  1586. InBufferSize );
  1587. break;
  1588. #if LOADBAL_SUPPORT
  1589. case CLUSCTL_RESOURCE_GET_LOADBAL_PROCESS_LIST:
  1590. status = GenJobGetPids( resourceEntry,
  1591. OutBuffer,
  1592. OutBufferSize,
  1593. BytesReturned );
  1594. break;
  1595. #endif
  1596. default:
  1597. status = ERROR_INVALID_FUNCTION;
  1598. break;
  1599. }
  1600. return(status);
  1601. } // GenJobResourceControl
  1602. DWORD
  1603. GenJobResourceTypeControl(
  1604. IN LPCWSTR ResourceTypeName,
  1605. IN DWORD ControlCode,
  1606. IN PVOID InBuffer,
  1607. IN DWORD InBufferSize,
  1608. OUT PVOID OutBuffer,
  1609. IN DWORD OutBufferSize,
  1610. OUT LPDWORD BytesReturned
  1611. )
  1612. /*++
  1613. Routine Description:
  1614. ResourceTypeControl routine for Generic Job Object resources.
  1615. Perform the control request specified by ControlCode for this resource type.
  1616. Arguments:
  1617. ResourceTypeName - Supplies the resource type name.
  1618. ControlCode - Supplies the control code that defines the action
  1619. to be performed.
  1620. InBuffer - Supplies a pointer to a buffer containing input data.
  1621. InBufferSize - Supplies the size, in bytes, of the data pointed
  1622. to by InBuffer.
  1623. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1624. OutBufferSize - Supplies the size, in bytes, of the available space
  1625. pointed to by OutBuffer.
  1626. BytesReturned - Returns the number of bytes of OutBuffer actually
  1627. filled in by the resource. If OutBuffer is too small, BytesReturned
  1628. contains the total number of bytes for the operation to succeed.
  1629. Return Value:
  1630. ERROR_SUCCESS - The function completed successfully.
  1631. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1632. In some cases, this allows the cluster software to perform the work.
  1633. Win32 error code - The function failed.
  1634. --*/
  1635. {
  1636. DWORD status;
  1637. DWORD required;
  1638. switch ( ControlCode ) {
  1639. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1640. *BytesReturned = 0;
  1641. status = ERROR_SUCCESS;
  1642. break;
  1643. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  1644. status = ResUtilGetPropertyFormats( GenJobResourcePrivateProperties,
  1645. OutBuffer,
  1646. OutBufferSize,
  1647. BytesReturned,
  1648. &required );
  1649. if ( status == ERROR_MORE_DATA ) {
  1650. *BytesReturned = required;
  1651. }
  1652. break;
  1653. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1654. status = ResUtilEnumProperties( GenJobResourcePrivateProperties,
  1655. OutBuffer,
  1656. OutBufferSize,
  1657. BytesReturned,
  1658. &required );
  1659. if ( status == ERROR_MORE_DATA ) {
  1660. *BytesReturned = required;
  1661. }
  1662. break;
  1663. default:
  1664. status = ERROR_INVALID_FUNCTION;
  1665. break;
  1666. }
  1667. return(status);
  1668. } // GenJobResourceTypeControl
  1669. DWORD
  1670. GenJobGetPrivateResProperties(
  1671. IN OUT PGENJOB_RESOURCE ResourceEntry,
  1672. OUT PVOID OutBuffer,
  1673. IN DWORD OutBufferSize,
  1674. OUT LPDWORD BytesReturned
  1675. )
  1676. /*++
  1677. Routine Description:
  1678. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1679. for resources of type GenJob.
  1680. Arguments:
  1681. ResourceEntry - Supplies the resource entry on which to operate.
  1682. OutBuffer - Returns the output data.
  1683. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1684. to by OutBuffer.
  1685. BytesReturned - The number of bytes returned in OutBuffer.
  1686. Return Value:
  1687. ERROR_SUCCESS - The function completed successfully.
  1688. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1689. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1690. Win32 error code - The function failed.
  1691. --*/
  1692. {
  1693. DWORD status;
  1694. DWORD required;
  1695. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1696. GenJobResourcePrivateProperties,
  1697. OutBuffer,
  1698. OutBufferSize,
  1699. BytesReturned,
  1700. &required );
  1701. if ( status == ERROR_MORE_DATA ) {
  1702. *BytesReturned = required;
  1703. }
  1704. return(status);
  1705. } // GenJobGetPrivateResProperties
  1706. DWORD
  1707. GenJobValidatePrivateResProperties(
  1708. IN OUT PGENJOB_RESOURCE ResourceEntry,
  1709. IN PVOID InBuffer,
  1710. IN DWORD InBufferSize,
  1711. OUT PGENJOB_PROPS Params
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1716. function for resources of type Generic Job Object.
  1717. Arguments:
  1718. ResourceEntry - Supplies the resource entry on which to operate.
  1719. InBuffer - Supplies a pointer to a buffer containing input data.
  1720. InBufferSize - Supplies the size, in bytes, of the data pointed
  1721. to by InBuffer.
  1722. Params - Supplies the parameter block to fill in.
  1723. Return Value:
  1724. ERROR_SUCCESS - The function completed successfully.
  1725. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1726. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1727. ERROR_DEPENDENCY_NOT_FOUND - Trying to set UseNetworkName when there
  1728. is no dependency on a Network Name resource.
  1729. Win32 error code - The function failed.
  1730. --*/
  1731. {
  1732. DWORD status;
  1733. GENJOB_PROPS currentProps;
  1734. GENJOB_PROPS newProps;
  1735. PGENJOB_PROPS pParams;
  1736. HRESOURCE hResDependency;
  1737. LPWSTR nameOfPropInError;
  1738. //
  1739. // Check if there is input data.
  1740. //
  1741. if ( (InBuffer == NULL) ||
  1742. (InBufferSize < sizeof(DWORD)) ) {
  1743. return(ERROR_INVALID_DATA);
  1744. }
  1745. //
  1746. // Retrieve the current set of private properties from the
  1747. // cluster database.
  1748. //
  1749. ZeroMemory( &currentProps, sizeof(currentProps) );
  1750. status = ResUtilGetPropertiesToParameterBlock(
  1751. ResourceEntry->ParametersKey,
  1752. GenJobResourcePrivateProperties,
  1753. (LPBYTE) &currentProps,
  1754. FALSE, /*CheckForRequiredProperties*/
  1755. &nameOfPropInError
  1756. );
  1757. if ( status != ERROR_SUCCESS ) {
  1758. (g_LogEvent)(
  1759. ResourceEntry->ResourceHandle,
  1760. LOG_ERROR,
  1761. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1762. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1763. status );
  1764. goto FnExit;
  1765. }
  1766. //
  1767. // Duplicate the resource parameter block.
  1768. //
  1769. if ( Params == NULL ) {
  1770. pParams = &newProps;
  1771. } else {
  1772. pParams = Params;
  1773. }
  1774. ZeroMemory( pParams, sizeof(GENJOB_PROPS) );
  1775. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1776. (LPBYTE) &currentProps,
  1777. GenJobResourcePrivateProperties );
  1778. if ( status != ERROR_SUCCESS ) {
  1779. return(status);
  1780. }
  1781. //
  1782. // Parse and validate the properties.
  1783. //
  1784. status = ResUtilVerifyPropertyTable( GenJobResourcePrivateProperties,
  1785. NULL,
  1786. TRUE, // Allow unknowns
  1787. InBuffer,
  1788. InBufferSize,
  1789. (LPBYTE) pParams );
  1790. if ( status == ERROR_SUCCESS ) {
  1791. //
  1792. // Validate the CurrentDirectory
  1793. //
  1794. if ( pParams->CurrentDirectory &&
  1795. !ResUtilIsPathValid( pParams->CurrentDirectory ) ) {
  1796. status = ERROR_INVALID_PARAMETER;
  1797. goto FnExit;
  1798. }
  1799. //
  1800. // If the resource should use the network name as the computer
  1801. // name, make sure there is a dependency on a Network Name
  1802. // resource.
  1803. //
  1804. if ( pParams->UseNetworkName ) {
  1805. hResDependency = ResUtilGetResourceDependency(ResourceEntry->hResource,
  1806. CLUS_RESTYPE_NAME_NETNAME);
  1807. if ( hResDependency == NULL ) {
  1808. status = ERROR_DEPENDENCY_NOT_FOUND;
  1809. } else {
  1810. CloseClusterResource( hResDependency );
  1811. }
  1812. }
  1813. }
  1814. FnExit:
  1815. //
  1816. // Cleanup our parameter block.
  1817. //
  1818. if ( ( (status != ERROR_SUCCESS)
  1819. && (pParams != NULL) )
  1820. || ( pParams == &newProps )
  1821. ) {
  1822. ResUtilFreeParameterBlock( (LPBYTE) &pParams,
  1823. (LPBYTE) &currentProps,
  1824. GenJobResourcePrivateProperties );
  1825. }
  1826. ResUtilFreeParameterBlock(
  1827. (LPBYTE) &currentProps,
  1828. NULL,
  1829. GenJobResourcePrivateProperties
  1830. );
  1831. return(status);
  1832. } // GenJobValidatePrivateResProperties
  1833. DWORD
  1834. GenJobSetPrivateResProperties(
  1835. IN OUT PGENJOB_RESOURCE ResourceEntry,
  1836. IN PVOID InBuffer,
  1837. IN DWORD InBufferSize
  1838. )
  1839. /*++
  1840. Routine Description:
  1841. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function for
  1842. resources of type Generic Job Object. Some parameters (command line,
  1843. current dir, desktop, and netname) cause no change in the resource if it
  1844. is online and the parameters have changed value. If any job object
  1845. parameters are specified at the same time, they DO NOT get set.
  1846. Arguments:
  1847. ResourceEntry - Supplies the resource entry on which to operate.
  1848. InBuffer - Supplies a pointer to a buffer containing input data.
  1849. InBufferSize - Supplies the size, in bytes, of the data pointed
  1850. to by InBuffer.
  1851. Return Value:
  1852. ERROR_SUCCESS - The function completed successfully.
  1853. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1854. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1855. Win32 error code - The function failed.
  1856. --*/
  1857. {
  1858. DWORD status;
  1859. GENJOB_PROPS params;
  1860. ZeroMemory( &params, sizeof(GENJOB_PROPS) );
  1861. //
  1862. // Parse and validate the properties.
  1863. //
  1864. status = GenJobValidatePrivateResProperties( ResourceEntry,
  1865. InBuffer,
  1866. InBufferSize,
  1867. &params );
  1868. if ( status != ERROR_SUCCESS ) {
  1869. return(status);
  1870. }
  1871. //
  1872. // Save the parameter values.
  1873. //
  1874. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1875. GenJobResourcePrivateProperties,
  1876. NULL,
  1877. (LPBYTE) &params,
  1878. InBuffer,
  1879. InBufferSize,
  1880. (LPBYTE) &ResourceEntry->StoredProps );
  1881. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1882. (LPBYTE) &ResourceEntry->OperationalProps,
  1883. GenJobResourcePrivateProperties );
  1884. //
  1885. // If the resource is online, return a non-success status.
  1886. //
  1887. if (status == ERROR_SUCCESS) {
  1888. if ( ResourceEntry->Online ) {
  1889. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1890. } else {
  1891. status = ERROR_SUCCESS;
  1892. }
  1893. }
  1894. return status;
  1895. } // GenJobSetPrivateResProperties
  1896. #if LOADBAL_SUPPORT
  1897. DWORD
  1898. GenJobGetPids(
  1899. IN OUT PGENJOB_RESOURCE ResourceEntry,
  1900. OUT PVOID OutBuffer,
  1901. IN DWORD OutBufferSize,
  1902. OUT LPDWORD BytesReturned
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. Get array of PIDs (as DWORDS) to return for load balancing purposes.
  1907. Arguments:
  1908. ResourceEntry - Supplies the resource entry on which to operate.
  1909. OutBuffer - Supplies a pointer to a buffer for output data.
  1910. OutBufferSize - Supplies the size, in bytes, of the buffer pointed
  1911. to by OutBuffer.
  1912. BytesReturned - The number of bytes returned in OutBuffer.
  1913. Return Value:
  1914. ERROR_SUCCESS if successful.
  1915. A Win32 error code on failure.
  1916. --*/
  1917. {
  1918. CLUSPROP_BUFFER_HELPER props;
  1919. props.pb = OutBuffer;
  1920. *BytesReturned = sizeof(*props.pdw);
  1921. if ( OutBufferSize < sizeof(*props.pdw) ) {
  1922. return(ERROR_MORE_DATA);
  1923. }
  1924. *(props.pdw) = ResourceEntry->ProcessId;
  1925. return(ERROR_SUCCESS);
  1926. } // GenJobGetPids
  1927. #endif
  1928. DWORD
  1929. WINAPI
  1930. Startup(
  1931. IN LPCWSTR ResourceType,
  1932. IN DWORD MinVersionSupported,
  1933. IN DWORD MaxVersionSupported,
  1934. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  1935. IN PLOG_EVENT_ROUTINE LogEvent,
  1936. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  1937. )
  1938. /*++
  1939. Routine Description:
  1940. Startup a particular resource type. This means verifying the version
  1941. requested, and returning the function table for this resource type.
  1942. remove when moving to clusres
  1943. Arguments:
  1944. ResourceType - Supplies the type of resource.
  1945. MinVersionSupported - The minimum version number supported by the cluster
  1946. service on this system.
  1947. MaxVersionSupported - The maximum version number supported by the cluster
  1948. service on this system.
  1949. SetResourceStatus - xxx
  1950. LogEvent - xxx
  1951. FunctionTable - Returns the Function Table for this resource type.
  1952. Return Value:
  1953. ERROR_SUCCESS if successful.
  1954. A Win32 error code on failure.
  1955. --*/
  1956. {
  1957. if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  1958. (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  1959. return(ERROR_REVISION_MISMATCH);
  1960. }
  1961. if ( !ClusResLogEvent ) {
  1962. ClusResLogEvent = LogEvent;
  1963. ClusResSetResourceStatus = SetResourceStatus;
  1964. }
  1965. if ( lstrcmpiW( ResourceType, CLUS_RESTYPE_NAME_GENJOB ) == 0 ) {
  1966. *FunctionTable = &GenJobFunctionTable;
  1967. return(ERROR_SUCCESS);
  1968. } else {
  1969. return(ERROR_CLUSTER_RESNAME_NOT_FOUND);
  1970. }
  1971. } // Startup
  1972. //***********************************************************
  1973. //
  1974. // Define Function Table
  1975. //
  1976. //***********************************************************
  1977. CLRES_V1_FUNCTION_TABLE( GenJobFunctionTable, // Name
  1978. CLRES_VERSION_V1_00, // Version
  1979. GenJob, // Prefix
  1980. NULL, // Arbitrate
  1981. NULL, // Release
  1982. GenJobResourceControl,// ResControl
  1983. GenJobResourceTypeControl ); // ResTypeControl