3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/job.c
6 * PURPOSE: Job Native Functions
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) (stubs)
9 * Thomas Weidenmueller <w3seek@reactos.com>
12 /* Note: Jobs are only supported on Win2K+ */
13 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 #define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */
22 POBJECT_TYPE EXPORTED PsJobType
= NULL
;
24 LIST_ENTRY PsJobListHead
;
25 static FAST_MUTEX PsJobListLock
;
27 static GENERIC_MAPPING PiJobMapping
=
29 STANDARD_RIGHTS_READ
| JOB_OBJECT_QUERY
,
30 STANDARD_RIGHTS_WRITE
| JOB_OBJECT_ASSIGN_PROCESS
| JOB_OBJECT_SET_ATTRIBUTES
| JOB_OBJECT_TERMINATE
| JOB_OBJECT_SET_SECURITY_ATTRIBUTES
,
31 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
32 STANDARD_RIGHTS_ALL
| JOB_OBJECT_ALL_ACCESS
35 /* FUNCTIONS *****************************************************************/
38 PiDeleteJob ( PVOID ObjectBody
)
40 PEJOB Job
= (PEJOB
)ObjectBody
;
42 /* remove the reference to the completion port if associated */
43 if(Job
->CompletionPort
!= NULL
)
45 ObDereferenceObject(Job
->CompletionPort
);
48 /* unlink the job object */
49 if(Job
->JobLinks
.Flink
!= NULL
)
51 ExAcquireFastMutex(&PsJobListLock
);
52 RemoveEntryList(&Job
->JobLinks
);
53 ExReleaseFastMutex(&PsJobListLock
);
56 ExDeleteResource(&Job
->JobLock
);
61 PsInitJobManagment ( VOID
)
64 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
66 DPRINT1("Creating Job Object Type\n");
68 /* Initialize the Job type */
69 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
70 RtlInitUnicodeString(&Name
, L
"Job");
71 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
72 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(EJOB
);
73 ObjectTypeInitializer
.GenericMapping
= PiJobMapping
;
74 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
75 ObjectTypeInitializer
.ValidAccessMask
= JOB_OBJECT_ALL_ACCESS
;
76 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
77 ObjectTypeInitializer
.DeleteProcedure
= PiDeleteJob
;
78 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &PsJobType
);
80 InitializeListHead(&PsJobListHead
);
81 ExInitializeFastMutex(&PsJobListLock
);
85 PspAssignProcessToJob (
89 DPRINT("PspAssignProcessToJob() is unimplemented!\n");
90 return STATUS_NOT_IMPLEMENTED
;
94 PspTerminateJobObject (
96 KPROCESSOR_MODE AccessMode
,
99 DPRINT("PspTerminateJobObject() is unimplemented!\n");
100 return STATUS_NOT_IMPLEMENTED
;
109 NtAssignProcessToJobObject (
111 HANDLE ProcessHandle
)
114 KPROCESSOR_MODE PreviousMode
;
119 PreviousMode
= ExGetPreviousMode();
121 /* make sure we're having a handle with enough rights, especially the to
122 terminate the process. otherwise one could abuse the job objects to
123 terminate processes without having rights granted to do so! The reason
124 I open the process handle before the job handle is that a simple test showed
125 that it first complains about a invalid process handle! The other way around
126 would be simpler though... */
127 Status
= ObReferenceObjectByHandle(
134 if(NT_SUCCESS(Status
))
136 if(Process
->Job
== NULL
)
140 Status
= ObReferenceObjectByHandle(
142 JOB_OBJECT_ASSIGN_PROCESS
,
147 if(NT_SUCCESS(Status
))
149 /* lock the process so we can safely assign the process. Note that in the
150 meanwhile another thread could have assigned this process to a job! */
152 Status
= PsLockProcess(Process
, FALSE
);
153 if(NT_SUCCESS(Status
))
155 if(Process
->Job
== NULL
&& Process
->Session
== Job
->SessionId
)
157 /* Just store the pointer to the job object in the process, we'll
158 assign it later. The reason we can't do this here is that locking
159 the job object might require it to wait, which is a bad thing
160 while holding the process lock! */
165 /* process is already assigned to a job or session id differs! */
166 Status
= STATUS_ACCESS_DENIED
;
168 PsUnlockProcess(Process
);
170 if(NT_SUCCESS(Status
))
172 /* let's actually assign the process to the job as we're not holding
173 the process lock anymore! */
174 Status
= PspAssignProcessToJob(Process
, Job
);
178 ObDereferenceObject(Job
);
183 /* process is already assigned to a job or session id differs! */
184 Status
= STATUS_ACCESS_DENIED
;
187 ObDereferenceObject(Process
);
201 ACCESS_MASK DesiredAccess
,
202 POBJECT_ATTRIBUTES ObjectAttributes
)
206 KPROCESSOR_MODE PreviousMode
;
207 PEPROCESS CurrentProcess
;
208 NTSTATUS Status
= STATUS_SUCCESS
;
212 PreviousMode
= ExGetPreviousMode();
213 CurrentProcess
= PsGetCurrentProcess();
215 /* check for valid buffers */
216 if(PreviousMode
== UserMode
)
220 /* probe with 32bit alignment */
221 ProbeForWrite(JobHandle
,
227 Status
= _SEH_GetExceptionCode();
231 if(!NT_SUCCESS(Status
))
237 Status
= ObCreateObject(PreviousMode
,
247 if(NT_SUCCESS(Status
))
249 /* FIXME - Zero all fields as we don't yet implement all of them */
250 RtlZeroMemory(Job
, sizeof(EJOB
));
252 /* make sure that early destruction doesn't attempt to remove the object from
253 the list before it even gets added! */
254 Job
->JobLinks
.Flink
= NULL
;
256 /* setup the job object */
257 InitializeListHead(&Job
->ProcessListHead
);
258 Job
->SessionId
= CurrentProcess
->Session
; /* inherit the session id from the caller */
260 Status
= ExInitializeResource(&Job
->JobLock
);
261 if(!NT_SUCCESS(Status
))
263 DPRINT1("Failed to initialize job lock!!!\n");
264 ObDereferenceObject(Job
);
267 KeInitializeEvent(&Job
->Event
, NotificationEvent
, FALSE
);
269 /* link the object into the global job list */
270 ExAcquireFastMutex(&PsJobListLock
);
271 InsertTailList(&PsJobListHead
, &Job
->JobLinks
);
272 ExReleaseFastMutex(&PsJobListLock
);
274 Status
= ObInsertObject(Job
,
280 if(NT_SUCCESS(Status
))
282 /* pass the handle back to the caller */
285 /* NOTE: if the caller passed invalid buffers to receive the handle it's his
286 own fault! the object will still be created and live... It's possible
287 to find the handle using ObFindHandleForObject()! */
292 Status
= _SEH_GetExceptionCode();
308 IN HANDLE ProcessHandle
,
309 IN HANDLE JobHandle OPTIONAL
)
311 KPROCESSOR_MODE PreviousMode
;
315 PreviousMode
= ExGetPreviousMode();
319 Status
= ObReferenceObjectByHandle(
321 PROCESS_QUERY_INFORMATION
,
326 if(NT_SUCCESS(Status
))
328 /* FIXME - make sure the job object doesn't get exchanged or deleted while trying to
329 reference it, e.g. by locking it somehow until it is referenced... */
331 PEJOB ProcessJob
= Process
->Job
;
333 if(ProcessJob
!= NULL
)
335 if(JobHandle
== NULL
)
337 /* the process is assigned to a job */
338 Status
= STATUS_PROCESS_IN_JOB
;
340 else /* JobHandle != NULL */
344 /* get the job object and compare the object pointer with the one assigned to the process */
345 Status
= ObReferenceObjectByHandle(JobHandle
,
351 if(NT_SUCCESS(Status
))
353 Status
= ((ProcessJob
== JobObject
) ? STATUS_PROCESS_IN_JOB
: STATUS_PROCESS_NOT_IN_JOB
);
354 ObDereferenceObject(JobObject
);
360 /* the process is not assigned to any job */
361 Status
= STATUS_PROCESS_NOT_IN_JOB
;
363 ObDereferenceObject(Process
);
377 ACCESS_MASK DesiredAccess
,
378 POBJECT_ATTRIBUTES ObjectAttributes
)
380 KPROCESSOR_MODE PreviousMode
;
382 NTSTATUS Status
= STATUS_SUCCESS
;
386 PreviousMode
= ExGetPreviousMode();
388 /* check for valid buffers */
389 if(PreviousMode
== UserMode
)
393 /* probe with 32bit alignment */
394 ProbeForWrite(JobHandle
,
400 Status
= _SEH_GetExceptionCode();
404 if(!NT_SUCCESS(Status
))
410 if(NT_SUCCESS(Status
))
412 Status
= ObOpenObjectByName(ObjectAttributes
,
419 if(NT_SUCCESS(Status
))
427 Status
= _SEH_GetExceptionCode();
442 NtQueryInformationJobObject (
444 JOBOBJECTINFOCLASS JobInformationClass
,
445 PVOID JobInformation
,
446 ULONG JobInformationLength
,
447 PULONG ReturnLength
)
450 return STATUS_NOT_IMPLEMENTED
;
459 NtSetInformationJobObject (
461 JOBOBJECTINFOCLASS JobInformationClass
,
462 PVOID JobInformation
,
463 ULONG JobInformationLength
)
466 return STATUS_NOT_IMPLEMENTED
;
475 NtTerminateJobObject (
477 NTSTATUS ExitStatus
)
479 KPROCESSOR_MODE PreviousMode
;
485 PreviousMode
= ExGetPreviousMode();
487 Status
= ObReferenceObjectByHandle(
489 JOB_OBJECT_TERMINATE
,
494 if(NT_SUCCESS(Status
))
496 Status
= PspTerminateJobObject(
500 ObDereferenceObject(Job
);
512 PsGetJobLock ( PEJOB Job
)
515 return (PVOID
)&Job
->JobLock
;
524 PsGetJobSessionId ( PEJOB Job
)
527 return (PVOID
)Job
->SessionId
;
536 PsGetJobUIRestrictionsClass ( PEJOB Job
)
539 return Job
->UIRestrictionsClass
;
548 PsSetJobUIRestrictionsClass (
550 ULONG UIRestrictionsClass
)
553 InterlockedExchangeUL(&Job
->UIRestrictionsClass
, UIRestrictionsClass
);
554 /* FIXME - walk through the job process list and update the restrictions? */