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 *****************************************************************/
17 #include <internal/debug.h>
19 #if defined (ALLOC_PRAGMA)
20 #pragma alloc_text(INIT, PsInitJobManagment)
25 /* GLOBALS *******************************************************************/
27 POBJECT_TYPE PsJobType
= NULL
;
29 LIST_ENTRY PsJobListHead
;
30 static FAST_MUTEX PsJobListLock
;
32 static GENERIC_MAPPING PiJobMapping
=
34 STANDARD_RIGHTS_READ
| JOB_OBJECT_QUERY
,
35 STANDARD_RIGHTS_WRITE
| JOB_OBJECT_ASSIGN_PROCESS
| JOB_OBJECT_SET_ATTRIBUTES
| JOB_OBJECT_TERMINATE
| JOB_OBJECT_SET_SECURITY_ATTRIBUTES
,
36 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
37 STANDARD_RIGHTS_ALL
| JOB_OBJECT_ALL_ACCESS
40 /* FUNCTIONS *****************************************************************/
43 PiDeleteJob ( PVOID ObjectBody
)
45 PEJOB Job
= (PEJOB
)ObjectBody
;
47 /* remove the reference to the completion port if associated */
48 if(Job
->CompletionPort
!= NULL
)
50 ObDereferenceObject(Job
->CompletionPort
);
53 /* unlink the job object */
54 if(Job
->JobLinks
.Flink
!= NULL
)
56 ExAcquireFastMutex(&PsJobListLock
);
57 RemoveEntryList(&Job
->JobLinks
);
58 ExReleaseFastMutex(&PsJobListLock
);
61 ExDeleteResource(&Job
->JobLock
);
67 PsInitJobManagment ( VOID
)
70 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
72 DPRINT("Creating Job Object Type\n");
74 /* Initialize the Job type */
75 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
76 RtlInitUnicodeString(&Name
, L
"Job");
77 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
78 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(EJOB
);
79 ObjectTypeInitializer
.GenericMapping
= PiJobMapping
;
80 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
81 ObjectTypeInitializer
.ValidAccessMask
= JOB_OBJECT_ALL_ACCESS
;
82 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
83 ObjectTypeInitializer
.DeleteProcedure
= PiDeleteJob
;
84 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &PsJobType
);
86 InitializeListHead(&PsJobListHead
);
87 ExInitializeFastMutex(&PsJobListLock
);
92 PspAssignProcessToJob (
96 DPRINT("PspAssignProcessToJob() is unimplemented!\n");
97 return STATUS_NOT_IMPLEMENTED
;
102 PspTerminateJobObject (
104 KPROCESSOR_MODE AccessMode
,
105 NTSTATUS ExitStatus
)
107 DPRINT("PspTerminateJobObject() is unimplemented!\n");
108 return STATUS_NOT_IMPLEMENTED
;
117 NtAssignProcessToJobObject (
119 HANDLE ProcessHandle
)
122 KPROCESSOR_MODE PreviousMode
;
127 PreviousMode
= ExGetPreviousMode();
129 /* make sure we're having a handle with enough rights, especially the to
130 terminate the process. otherwise one could abuse the job objects to
131 terminate processes without having rights granted to do so! The reason
132 I open the process handle before the job handle is that a simple test showed
133 that it first complains about a invalid process handle! The other way around
134 would be simpler though... */
135 Status
= ObReferenceObjectByHandle(
142 if(NT_SUCCESS(Status
))
144 if(Process
->Job
== NULL
)
148 Status
= ObReferenceObjectByHandle(
150 JOB_OBJECT_ASSIGN_PROCESS
,
155 if(NT_SUCCESS(Status
))
157 /* lock the process so we can safely assign the process. Note that in the
158 meanwhile another thread could have assigned this process to a job! */
160 Status
= PsLockProcess(Process
, FALSE
);
161 if(NT_SUCCESS(Status
))
163 if(Process
->Job
== NULL
&& Process
->Session
== Job
->SessionId
)
165 /* Just store the pointer to the job object in the process, we'll
166 assign it later. The reason we can't do this here is that locking
167 the job object might require it to wait, which is a bad thing
168 while holding the process lock! */
173 /* process is already assigned to a job or session id differs! */
174 Status
= STATUS_ACCESS_DENIED
;
176 PsUnlockProcess(Process
);
178 if(NT_SUCCESS(Status
))
180 /* let's actually assign the process to the job as we're not holding
181 the process lock anymore! */
182 Status
= PspAssignProcessToJob(Process
, Job
);
186 ObDereferenceObject(Job
);
191 /* process is already assigned to a job or session id differs! */
192 Status
= STATUS_ACCESS_DENIED
;
195 ObDereferenceObject(Process
);
209 ACCESS_MASK DesiredAccess
,
210 POBJECT_ATTRIBUTES ObjectAttributes
)
214 KPROCESSOR_MODE PreviousMode
;
215 PEPROCESS CurrentProcess
;
216 NTSTATUS Status
= STATUS_SUCCESS
;
220 PreviousMode
= ExGetPreviousMode();
221 CurrentProcess
= PsGetCurrentProcess();
223 /* check for valid buffers */
224 if(PreviousMode
!= KernelMode
)
228 ProbeForWriteHandle(JobHandle
);
232 Status
= _SEH_GetExceptionCode();
236 if(!NT_SUCCESS(Status
))
242 Status
= ObCreateObject(PreviousMode
,
252 if(NT_SUCCESS(Status
))
254 /* FIXME - Zero all fields as we don't yet implement all of them */
255 RtlZeroMemory(Job
, sizeof(EJOB
));
257 /* make sure that early destruction doesn't attempt to remove the object from
258 the list before it even gets added! */
259 Job
->JobLinks
.Flink
= NULL
;
261 /* setup the job object */
262 InitializeListHead(&Job
->ProcessListHead
);
263 Job
->SessionId
= CurrentProcess
->Session
; /* inherit the session id from the caller */
265 Status
= ExInitializeResource(&Job
->JobLock
);
266 if(!NT_SUCCESS(Status
))
268 DPRINT1("Failed to initialize job lock!!!\n");
269 ObDereferenceObject(Job
);
272 KeInitializeEvent(&Job
->Event
, NotificationEvent
, FALSE
);
274 /* link the object into the global job list */
275 ExAcquireFastMutex(&PsJobListLock
);
276 InsertTailList(&PsJobListHead
, &Job
->JobLinks
);
277 ExReleaseFastMutex(&PsJobListLock
);
279 Status
= ObInsertObject(Job
,
285 if(NT_SUCCESS(Status
))
287 /* pass the handle back to the caller */
290 /* NOTE: if the caller passed invalid buffers to receive the handle it's his
291 own fault! the object will still be created and live... It's possible
292 to find the handle using ObFindHandleForObject()! */
297 Status
= _SEH_GetExceptionCode();
313 IN HANDLE ProcessHandle
,
314 IN HANDLE JobHandle OPTIONAL
)
316 KPROCESSOR_MODE PreviousMode
;
320 PreviousMode
= ExGetPreviousMode();
324 Status
= ObReferenceObjectByHandle(
326 PROCESS_QUERY_INFORMATION
,
331 if(NT_SUCCESS(Status
))
333 /* FIXME - make sure the job object doesn't get exchanged or deleted while trying to
334 reference it, e.g. by locking it somehow until it is referenced... */
336 PEJOB ProcessJob
= Process
->Job
;
338 if(ProcessJob
!= NULL
)
340 if(JobHandle
== NULL
)
342 /* the process is assigned to a job */
343 Status
= STATUS_PROCESS_IN_JOB
;
345 else /* JobHandle != NULL */
349 /* get the job object and compare the object pointer with the one assigned to the process */
350 Status
= ObReferenceObjectByHandle(JobHandle
,
356 if(NT_SUCCESS(Status
))
358 Status
= ((ProcessJob
== JobObject
) ? STATUS_PROCESS_IN_JOB
: STATUS_PROCESS_NOT_IN_JOB
);
359 ObDereferenceObject(JobObject
);
365 /* the process is not assigned to any job */
366 Status
= STATUS_PROCESS_NOT_IN_JOB
;
368 ObDereferenceObject(Process
);
382 ACCESS_MASK DesiredAccess
,
383 POBJECT_ATTRIBUTES ObjectAttributes
)
385 KPROCESSOR_MODE PreviousMode
;
387 NTSTATUS Status
= STATUS_SUCCESS
;
391 PreviousMode
= ExGetPreviousMode();
393 /* check for valid buffers */
394 if(PreviousMode
!= KernelMode
)
398 ProbeForWriteHandle(JobHandle
);
402 Status
= _SEH_GetExceptionCode();
406 if(!NT_SUCCESS(Status
))
412 if(NT_SUCCESS(Status
))
414 Status
= ObOpenObjectByName(ObjectAttributes
,
421 if(NT_SUCCESS(Status
))
429 Status
= _SEH_GetExceptionCode();
444 NtQueryInformationJobObject (
446 JOBOBJECTINFOCLASS JobInformationClass
,
447 PVOID JobInformation
,
448 ULONG JobInformationLength
,
449 PULONG ReturnLength
)
452 return STATUS_NOT_IMPLEMENTED
;
461 NtSetInformationJobObject (
463 JOBOBJECTINFOCLASS JobInformationClass
,
464 PVOID JobInformation
,
465 ULONG JobInformationLength
)
468 return STATUS_NOT_IMPLEMENTED
;
477 NtTerminateJobObject (
479 NTSTATUS ExitStatus
)
481 KPROCESSOR_MODE PreviousMode
;
487 PreviousMode
= ExGetPreviousMode();
489 Status
= ObReferenceObjectByHandle(
491 JOB_OBJECT_TERMINATE
,
496 if(NT_SUCCESS(Status
))
498 Status
= PspTerminateJobObject(
502 ObDereferenceObject(Job
);
514 PsGetJobLock ( PEJOB Job
)
517 return (PVOID
)&Job
->JobLock
;
526 PsGetJobSessionId ( PEJOB Job
)
529 return (PVOID
)Job
->SessionId
;
538 PsGetJobUIRestrictionsClass ( PEJOB Job
)
541 return Job
->UIRestrictionsClass
;
550 PsSetJobUIRestrictionsClass (
552 ULONG UIRestrictionsClass
)
555 InterlockedExchangeUL(&Job
->UIRestrictionsClass
, UIRestrictionsClass
);
556 /* FIXME - walk through the job process list and update the restrictions? */