/****************************** 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; }