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.
510 lines
13 KiB
510 lines
13 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: job.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* This module contains the code to implement the job object in NTUSER.
|
|
*
|
|
* History:
|
|
* 29-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
PW32JOB CreateW32Job(PEJOB Job);
|
|
VOID UpdateJob(PW32JOB pW32Job);
|
|
void SetProcessFlags(PW32JOB pW32Job, PPROCESSINFO ppi);
|
|
BOOL JobCalloutAddProcess(PW32JOB, PPROCESSINFO);
|
|
BOOL JobCalloutTerminate(PW32JOB);
|
|
|
|
/***************************************************************************\
|
|
* UserJobCallout
|
|
*
|
|
* History:
|
|
* 29-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
NTSTATUS UserJobCallout(
|
|
PKWIN32_JOBCALLOUT_PARAMETERS Parm)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PW32JOB pW32Job = NULL;
|
|
PEJOB Job;
|
|
PSW32JOBCALLOUTTYPE CalloutType;
|
|
PVOID Data;
|
|
|
|
|
|
Job = Parm->Job;
|
|
CalloutType = Parm->CalloutType;
|
|
Data = Parm->Data;
|
|
|
|
/*
|
|
* The EJOB lock must be acquired at this time.
|
|
*/
|
|
UserAssert(ExIsResourceAcquiredExclusiveLite(PsGetJobLock(Job)));
|
|
|
|
UserAssert(gpresUser != NULL);
|
|
|
|
BEGIN_REENTERCRIT();
|
|
|
|
BEGINATOMICCHECK();
|
|
|
|
/*
|
|
* find the W32JOB in the global list (if any)
|
|
*/
|
|
pW32Job = gpJobsList;
|
|
|
|
while (pW32Job) {
|
|
if (pW32Job->Job == Job) {
|
|
break;
|
|
}
|
|
pW32Job = pW32Job->pNext;
|
|
}
|
|
|
|
switch (CalloutType) {
|
|
case PsW32JobCalloutSetInformation:
|
|
|
|
if (pW32Job == NULL) {
|
|
|
|
/*
|
|
* The W32Job is not created yet. Assert that this is not
|
|
* a call to remove UI restrictions
|
|
*/
|
|
UserAssert(Data != 0);
|
|
|
|
if ((pW32Job = CreateW32Job(Job)) == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
/*
|
|
* The W32Job structure is already created. Return if
|
|
* the restrictions are the same as before.
|
|
*/
|
|
if (PtrToUlong(Data) == pW32Job->restrictions) {
|
|
TAGMSG0(DBGTAG_Job, "UserJobCallout: SetInformation same as before");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the restrictions
|
|
*/
|
|
pW32Job->restrictions = PtrToUlong(Data);
|
|
|
|
UpdateJob(pW32Job);
|
|
break;
|
|
|
|
case PsW32JobCalloutAddProcess:
|
|
|
|
/*
|
|
* 'Data' parameter is a pointer to W32PROCESS. So this callout
|
|
* happens only for GUI processes.
|
|
*/
|
|
UserAssert(PsGetJobUIRestrictionsClass(Job) != 0);
|
|
|
|
/*
|
|
* Assert that the W32JOB structure is already created.
|
|
*/
|
|
UserAssert(pW32Job != NULL);
|
|
|
|
TAGMSG3(DBGTAG_Job, "UserJobCallout: AddProcess Job %#p W32Job %#p Process %#p",
|
|
Job, pW32Job, (ULONG_PTR)Data);
|
|
|
|
/*
|
|
* this callout must be only for GUI processes
|
|
*/
|
|
UserAssert(Data != NULL);
|
|
|
|
JobCalloutAddProcess(pW32Job, (PPROCESSINFO)Data);
|
|
|
|
break;
|
|
|
|
case PsW32JobCalloutTerminate:
|
|
|
|
TAGMSG2(DBGTAG_Job, "UserJobCallout: Terminate Job %#p W32Job %#p",
|
|
Job, pW32Job);
|
|
|
|
if (pW32Job) {
|
|
JobCalloutTerminate(pW32Job);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TAGMSG2(DBGTAG_Job, "UserJobCallout: Invalid callout 0x%x Job %#p",
|
|
CalloutType, Job);
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
ENDATOMICCHECK();
|
|
|
|
END_REENTERCRIT();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CreateW32Job
|
|
*
|
|
* Creates a W32Job
|
|
*
|
|
* History:
|
|
* 18-Mar-1998 CLupu Created.
|
|
\***************************************************************************/
|
|
PW32JOB CreateW32Job(
|
|
PEJOB Job)
|
|
{
|
|
PW32JOB pW32Job;
|
|
|
|
TAGMSG1(DBGTAG_Job, "CreateW32Job: EJOB %#p", Job);
|
|
|
|
pW32Job = UserAllocPoolZInit(sizeof(W32JOB), TAG_W32JOB);
|
|
|
|
if (pW32Job == NULL) {
|
|
RIPMSG0(RIP_ERROR, "CreateW32Job: memory allocation error");
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Create the global atom table for this job
|
|
*/
|
|
CreateGlobalAtomTable(&pW32Job->pAtomTable);
|
|
|
|
if (pW32Job->pAtomTable == NULL) {
|
|
RIPMSG1(RIP_ERROR, "CreateW32Job: fail to create the atom table for job %#p",
|
|
pW32Job);
|
|
|
|
UserFreePool(pW32Job);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Link it in the W32 job's list
|
|
*/
|
|
pW32Job->pNext = gpJobsList;
|
|
gpJobsList = pW32Job;
|
|
|
|
pW32Job->Job = Job;
|
|
|
|
TAGMSG2(DBGTAG_Job, "CreateW32Job: pW32Job %#P created for EJOB %#p",
|
|
pW32Job, Job);
|
|
|
|
return pW32Job;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* UpdateJob
|
|
*
|
|
* Walks the processinfo list in userk to update all the processes assigned
|
|
* to this job .
|
|
*
|
|
* History:
|
|
* 20-Mar-1998 CLupu Created.
|
|
\***************************************************************************/
|
|
VOID UpdateJob(
|
|
PW32JOB pW32Job)
|
|
{
|
|
PPROCESSINFO ppi;
|
|
|
|
UserAssert(ExIsResourceAcquiredExclusiveLite(PsGetJobLock(pW32Job->Job)));
|
|
CheckCritIn();
|
|
|
|
TAGMSG1(DBGTAG_Job, "UpdateJob: pW32Job %#p", pW32Job);
|
|
|
|
/*
|
|
* walk the GUI processes list to see if any new process got
|
|
* assigned to the current job.
|
|
*/
|
|
ppi = gppiList;
|
|
|
|
while (ppi) {
|
|
if (PsGetProcessJob(ppi->Process) == pW32Job->Job) {
|
|
|
|
/*
|
|
* the process is assigned to this job
|
|
*/
|
|
if (ppi->pW32Job == NULL) {
|
|
|
|
/*
|
|
* add the process to the W32 job
|
|
*/
|
|
JobCalloutAddProcess(pW32Job, ppi);
|
|
} else {
|
|
|
|
/*
|
|
* The process is already added to the job. Just
|
|
* update the restrictions.
|
|
*/
|
|
SetProcessFlags(pW32Job, ppi);
|
|
}
|
|
}
|
|
ppi = ppi->ppiNextRunning;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* RemoveProcessFromJob
|
|
*
|
|
* This is called during the delete process callout.
|
|
*
|
|
* History:
|
|
* 30-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
BOOL RemoveProcessFromJob(
|
|
PPROCESSINFO ppi)
|
|
{
|
|
PW32JOB pW32Job;
|
|
UINT ip;
|
|
|
|
CheckCritIn();
|
|
|
|
pW32Job = ppi->pW32Job;
|
|
|
|
TAGMSG2(DBGTAG_Job, "RemoveProcessFromJob: ppi %#p pW32Job %#p",
|
|
ppi, pW32Job);
|
|
|
|
/*
|
|
* The job might not have UI restrictions
|
|
*/
|
|
if (pW32Job == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* remove the ppi from the job's ppi table
|
|
*/
|
|
for (ip = 0; ip < pW32Job->uProcessCount; ip++) {
|
|
|
|
UserAssert(pW32Job->ppiTable[ip]->pW32Job == pW32Job);
|
|
|
|
if (ppi == pW32Job->ppiTable[ip]) {
|
|
|
|
ppi->pW32Job = NULL;
|
|
|
|
RtlMoveMemory(pW32Job->ppiTable + ip,
|
|
pW32Job->ppiTable + ip + 1,
|
|
(pW32Job->uProcessCount - ip - 1) * sizeof(PPROCESSINFO));
|
|
|
|
(pW32Job->uProcessCount)--;
|
|
|
|
/*
|
|
* free the process array if this is the last one.
|
|
*/
|
|
if (pW32Job->uProcessCount == 0) {
|
|
UserFreePool(pW32Job->ppiTable);
|
|
pW32Job->ppiTable = NULL;
|
|
pW32Job->uMaxProcesses = 0;
|
|
}
|
|
|
|
TAGMSG2(DBGTAG_Job, "RemoveProcessFromJob: ppi %#p removed from pW32Job %#p",
|
|
ppi, pW32Job);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
TAGMSG2(DBGTAG_Job, "RemoveProcessFromJob: ppi %#p not found in pW32Job %#p",
|
|
ppi, pW32Job);
|
|
|
|
UserAssert(0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetProcessFlags
|
|
*
|
|
* History:
|
|
* 29-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
void SetProcessFlags(
|
|
PW32JOB pW32Job,
|
|
PPROCESSINFO ppi)
|
|
{
|
|
PTHREADINFO pti;
|
|
|
|
CheckCritIn();
|
|
|
|
TAGMSG3(DBGTAG_Job, "SetProcessFlags: pW32Job %#p ppi %#p restrictions %#p",
|
|
pW32Job, ppi, pW32Job->restrictions);
|
|
|
|
UserAssert(ppi->pW32Job == pW32Job);
|
|
|
|
if (pW32Job->restrictions == 0) {
|
|
((PW32PROCESS)ppi)->W32PF_Flags &= ~W32PF_RESTRICTED;
|
|
} else {
|
|
((PW32PROCESS)ppi)->W32PF_Flags |= W32PF_RESTRICTED;
|
|
}
|
|
|
|
KeAttachProcess(PsGetProcessPcb(ppi->Process));
|
|
|
|
/*
|
|
* walk the pti list and set the restricted flag as appropriate
|
|
*/
|
|
pti = ppi->ptiList;
|
|
|
|
if (pW32Job->restrictions == 0) {
|
|
while (pti) {
|
|
try {
|
|
pti->pClientInfo->dwTIFlags &= ~TIF_RESTRICTED;
|
|
} except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
|
|
continue;
|
|
}
|
|
pti->TIF_flags &= ~TIF_RESTRICTED;
|
|
pti = pti->ptiSibling;
|
|
}
|
|
} else {
|
|
while (pti) {
|
|
try {
|
|
pti->pClientInfo->dwTIFlags |= TIF_RESTRICTED;
|
|
} except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
|
|
continue;
|
|
}
|
|
pti->TIF_flags |= TIF_RESTRICTED;
|
|
pti = pti->ptiSibling;
|
|
}
|
|
}
|
|
|
|
KeDetachProcess();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* JobCalloutAddProcess
|
|
*
|
|
* History:
|
|
* 30-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
BOOL JobCalloutAddProcess(
|
|
PW32JOB pW32Job,
|
|
PPROCESSINFO ppi)
|
|
{
|
|
PPROCESSINFO* ppiTable;
|
|
|
|
CheckCritIn();
|
|
|
|
UserAssert(pW32Job != NULL);
|
|
|
|
/*
|
|
* This process is not yet initialized
|
|
*/
|
|
if (ppi->Process == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(ppi->W32PF_Flags & W32PF_PROCESSCONNECTED)) {
|
|
TAGMSG2(DBGTAG_Job, "JobCalloutAddProcess: pW32Job %#p ppi %#p not yet initialized",
|
|
pW32Job, ppi);
|
|
return FALSE;
|
|
}
|
|
|
|
TAGMSG2(DBGTAG_Job, "JobCalloutAddProcess: pW32Job %#p ppi %#p",
|
|
pW32Job, ppi);
|
|
|
|
#if DBG
|
|
/*
|
|
* Make sure the process is not already in the job's process list
|
|
*/
|
|
{
|
|
UINT ip;
|
|
for (ip = 0; ip < pW32Job->uProcessCount; ip++) {
|
|
|
|
UserAssert(pW32Job->ppiTable[ip]->pW32Job == pW32Job);
|
|
UserAssert(ppi != pW32Job->ppiTable[ip]);
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
/*
|
|
* save the pW32Job pointer in the process info
|
|
*/
|
|
UserAssert(ppi->pW32Job == NULL);
|
|
|
|
ppi->pW32Job = pW32Job;
|
|
|
|
if (pW32Job->uProcessCount == pW32Job->uMaxProcesses) {
|
|
|
|
/*
|
|
* No more room. Allocate more space for the process table
|
|
*/
|
|
if (pW32Job->uMaxProcesses == 0) {
|
|
|
|
UserAssert(pW32Job->ppiTable == NULL);
|
|
|
|
ppiTable = UserAllocPool(JP_DELTA * sizeof(PPROCESSINFO), TAG_W32JOBEXTRA);
|
|
|
|
} else {
|
|
UserAssert(pW32Job->ppiTable != NULL);
|
|
|
|
ppiTable = UserReAllocPool(pW32Job->ppiTable,
|
|
pW32Job->uMaxProcesses * sizeof(PPROCESSINFO),
|
|
(pW32Job->uMaxProcesses + JP_DELTA) * sizeof(PPROCESSINFO),
|
|
TAG_W32JOBEXTRA);
|
|
}
|
|
|
|
if (ppiTable == NULL) {
|
|
RIPMSG0(RIP_ERROR, "JobCalloutAddProcess: memory allocation error\n");
|
|
return FALSE;
|
|
}
|
|
|
|
pW32Job->ppiTable = ppiTable;
|
|
pW32Job->uMaxProcesses += JP_DELTA;
|
|
}
|
|
|
|
/*
|
|
* now add the process to the job
|
|
*/
|
|
pW32Job->ppiTable[pW32Job->uProcessCount] = ppi;
|
|
(pW32Job->uProcessCount)++;
|
|
|
|
SetProcessFlags(pW32Job, ppi);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* JobCalloutTerminate
|
|
*
|
|
* This is called during the job object delete routine.
|
|
*
|
|
* History:
|
|
* 30-Jul-1997 CLupu Created.
|
|
\***************************************************************************/
|
|
BOOL JobCalloutTerminate(
|
|
PW32JOB pW32Job)
|
|
{
|
|
CheckCritIn();
|
|
|
|
UserAssert(pW32Job != NULL);
|
|
|
|
TAGMSG1(DBGTAG_Job, "JobCalloutTerminate: pW32Job %#p", pW32Job);
|
|
|
|
/*
|
|
* No processes should be attached to this job
|
|
*/
|
|
UserAssert(pW32Job->ppiTable == NULL);
|
|
UserAssert(pW32Job->uProcessCount == 0);
|
|
UserAssert(pW32Job->uMaxProcesses == 0);
|
|
|
|
if (pW32Job->pgh) {
|
|
UserAssert(pW32Job->ughCrt > 0);
|
|
UserAssert(pW32Job->ughMax > 0);
|
|
|
|
UserFreePool(pW32Job->pgh);
|
|
pW32Job->pgh = NULL;
|
|
pW32Job->ughCrt = 0;
|
|
pW32Job->ughMax = 0;
|
|
}
|
|
|
|
/*
|
|
* remove the W32 job from the job's list
|
|
*/
|
|
REMOVE_FROM_LIST(W32JOB, gpJobsList, pW32Job, pNext);
|
|
|
|
RtlDestroyAtomTable(pW32Job->pAtomTable);
|
|
|
|
UserFreePool(pW32Job);
|
|
|
|
return TRUE;
|
|
}
|