PVOID UserCreateHeap( HANDLE hSection, PVOID pvBaseAddress, DWORD dwSize) { PVOID pUserBase; ULONG ulViewSize; LARGE_INTEGER liOffset; PEPROCESS Process = PsGetCurrentProcess(); RTL_HEAP_PARAMETERS HeapParams; NTSTATUS Status; /* * Map the section into the current process and commit the * first page of the section. */ ulViewSize = 0; liOffset.QuadPart = 0; pUserBase = NULL; Status = MmMapViewOfSection(hSection, Process, &pUserBase, 0, PAGE_SIZE, &liOffset, &ulViewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ); if (!NT_SUCCESS(Status)) return NULL; MmUnmapViewOfSection(Process, pUserBase); /* * We now have a committed page to create the heap in. */ RtlZeroMemory(&HeapParams, sizeof(HeapParams)); HeapParams.Length = sizeof(HeapParams); HeapParams.InitialCommit = PAGE_SIZE; HeapParams.InitialReserve = dwSize; HeapParams.CommitRoutine = UserCommitMemory; return RtlCreateHeap( HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, pvBaseAddress, dwSize, PAGE_SIZE, NULL, &HeapParams ); }
/* * @implemented */ NTSTATUS NTAPI NtSecureConnectPort(OUT PHANDLE PortHandle, IN PUNICODE_STRING PortName, IN PSECURITY_QUALITY_OF_SERVICE Qos, IN OUT PPORT_VIEW ClientView OPTIONAL, IN PSID ServerSid OPTIONAL, IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, OUT PULONG MaxMessageLength OPTIONAL, IN OUT PVOID ConnectionInformation OPTIONAL, IN OUT PULONG ConnectionInformationLength OPTIONAL) { ULONG ConnectionInfoLength = 0; PLPCP_PORT_OBJECT Port, ClientPort; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); NTSTATUS Status = STATUS_SUCCESS; HANDLE Handle; PVOID SectionToMap; PLPCP_MESSAGE Message; PLPCP_CONNECTION_MESSAGE ConnectMessage; PETHREAD Thread = PsGetCurrentThread(); ULONG PortMessageLength; LARGE_INTEGER SectionOffset; PTOKEN Token; PTOKEN_USER TokenUserInfo; PAGED_CODE(); LPCTRACE(LPC_CONNECT_DEBUG, "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n", PortName, Qos, ClientView, ServerView, ServerSid); /* Validate client view */ if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW))) { /* Fail */ return STATUS_INVALID_PARAMETER; } /* Validate server view */ if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW))) { /* Fail */ return STATUS_INVALID_PARAMETER; } /* Check if caller sent connection information length */ if (ConnectionInformationLength) { /* Retrieve the input length */ ConnectionInfoLength = *ConnectionInformationLength; } /* Get the port */ Status = ObReferenceObjectByName(PortName, 0, NULL, PORT_CONNECT, LpcPortObjectType, PreviousMode, NULL, (PVOID *)&Port); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to reference port '%wZ': 0x%lx\n", PortName, Status); return Status; } /* This has to be a connection port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT) { /* It isn't, so fail */ ObDereferenceObject(Port); return STATUS_INVALID_PORT_HANDLE; } /* Check if we have a SID */ if (ServerSid) { /* Make sure that we have a server */ if (Port->ServerProcess) { /* Get its token and query user information */ Token = PsReferencePrimaryToken(Port->ServerProcess); //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo); // FIXME: Need SeQueryInformationToken Status = STATUS_SUCCESS; TokenUserInfo = ExAllocatePoolWithTag(PagedPool, sizeof(TOKEN_USER), TAG_SE); TokenUserInfo->User.Sid = ServerSid; PsDereferencePrimaryToken(Token); /* Check for success */ if (NT_SUCCESS(Status)) { /* Compare the SIDs */ if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid)) { /* Fail */ Status = STATUS_SERVER_SID_MISMATCH; } /* Free token information */ ExFreePoolWithTag(TokenUserInfo, TAG_SE); } } else { /* Invalid SID */ Status = STATUS_SERVER_SID_MISMATCH; } /* Check if SID failed */ if (!NT_SUCCESS(Status)) { /* Quit */ ObDereferenceObject(Port); return Status; } } /* Create the client port */ Status = ObCreateObject(PreviousMode, LpcPortObjectType, NULL, PreviousMode, NULL, sizeof(LPCP_PORT_OBJECT), 0, 0, (PVOID *)&ClientPort); if (!NT_SUCCESS(Status)) { /* Failed, dereference the server port and return */ ObDereferenceObject(Port); return Status; } /* Setup the client port */ RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT)); ClientPort->Flags = LPCP_CLIENT_PORT; ClientPort->ConnectionPort = Port; ClientPort->MaxMessageLength = Port->MaxMessageLength; ClientPort->SecurityQos = *Qos; InitializeListHead(&ClientPort->LpcReplyChainHead); InitializeListHead(&ClientPort->LpcDataInfoChainHead); /* Check if we have dynamic security */ if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING) { /* Remember that */ ClientPort->Flags |= LPCP_SECURITY_DYNAMIC; } else { /* Create our own client security */ Status = SeCreateClientSecurity(Thread, Qos, FALSE, &ClientPort->StaticSecurity); if (!NT_SUCCESS(Status)) { /* Security failed, dereference and return */ ObDereferenceObject(ClientPort); return Status; } } /* Initialize the port queue */ Status = LpcpInitializePortQueue(ClientPort); if (!NT_SUCCESS(Status)) { /* Failed */ ObDereferenceObject(ClientPort); return Status; } /* Check if we have a client view */ if (ClientView) { /* Get the section handle */ Status = ObReferenceObjectByHandle(ClientView->SectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE, MmSectionObjectType, PreviousMode, (PVOID*)&SectionToMap, NULL); if (!NT_SUCCESS(Status)) { /* Fail */ ObDereferenceObject(Port); return Status; } /* Set the section offset */ SectionOffset.QuadPart = ClientView->SectionOffset; /* Map it */ Status = MmMapViewOfSection(SectionToMap, PsGetCurrentProcess(), &ClientPort->ClientSectionBase, 0, 0, &SectionOffset, &ClientView->ViewSize, ViewUnmap, 0, PAGE_READWRITE); /* Update the offset */ ClientView->SectionOffset = SectionOffset.LowPart; /* Check for failure */ if (!NT_SUCCESS(Status)) { /* Fail */ ObDereferenceObject(SectionToMap); ObDereferenceObject(Port); return Status; } /* Update the base */ ClientView->ViewBase = ClientPort->ClientSectionBase; /* Reference and remember the process */ ClientPort->MappingProcess = PsGetCurrentProcess(); ObReferenceObject(ClientPort->MappingProcess); } else { /* No section */ SectionToMap = NULL; } /* Normalize connection information */ if (ConnectionInfoLength > Port->MaxConnectionInfoLength) { /* Use the port's maximum allowed value */ ConnectionInfoLength = Port->MaxConnectionInfoLength; } /* Allocate a message from the port zone */ Message = LpcpAllocateFromPortZone(); if (!Message) { /* Fail if we couldn't allocate a message */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); return STATUS_NO_MEMORY; } /* Set pointer to the connection message and fill in the CID */ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); Message->Request.ClientId = Thread->Cid; /* Check if we have a client view */ if (ClientView) { /* Set the view size */ Message->Request.ClientViewSize = ClientView->ViewSize; /* Copy the client view and clear the server view */ RtlCopyMemory(&ConnectMessage->ClientView, ClientView, sizeof(PORT_VIEW)); RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW)); } else { /* Set the size to 0 and clear the connect message */ Message->Request.ClientViewSize = 0; RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE)); } /* Set the section and client port. Port is NULL for now */ ConnectMessage->ClientPort = NULL; ConnectMessage->SectionToMap = SectionToMap; /* Set the data for the connection request message */ Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength + sizeof(LPCP_CONNECTION_MESSAGE); Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) + Message->Request.u1.s1.DataLength; Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST; /* Check if we have connection information */ if (ConnectionInformation) { /* Copy it in */ RtlCopyMemory(ConnectMessage + 1, ConnectionInformation, ConnectionInfoLength); } /* Acquire the port lock */ KeAcquireGuardedMutex(&LpcpLock); /* Check if someone already deleted the port name */ if (Port->Flags & LPCP_NAME_DELETED) { /* Fail the request */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { /* Associate no thread yet */ Message->RepliedToThread = NULL; /* Generate the Message ID and set it */ Message->Request.MessageId = LpcpNextMessageId++; if (!LpcpNextMessageId) LpcpNextMessageId = 1; Thread->LpcReplyMessageId = Message->Request.MessageId; /* Insert the message into the queue and thread chain */ InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry); InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain); Thread->LpcReplyMessage = Message; /* Now we can finally reference the client port and link it*/ ObReferenceObject(ClientPort); ConnectMessage->ClientPort = ClientPort; /* Enter a critical region */ KeEnterCriticalRegion(); } /* Add another reference to the port */ ObReferenceObject(Port); /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Check for success */ if (NT_SUCCESS(Status)) { LPCTRACE(LPC_CONNECT_DEBUG, "Messages: %p/%p. Ports: %p/%p. Status: %lx\n", Message, ConnectMessage, Port, ClientPort, Status); /* If this is a waitable port, set the event */ if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent, 1, FALSE); /* Release the queue semaphore and leave the critical region */ LpcpCompleteWait(Port->MsgQueue.Semaphore); KeLeaveCriticalRegion(); /* Now wait for a reply */ LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode); } /* Check for failure */ if (!NT_SUCCESS(Status)) goto Cleanup; /* Free the connection message */ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread); /* Check if we got a message back */ if (Message) { /* Check for new return length */ if ((Message->Request.u1.s1.DataLength - sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength) { /* Set new normalized connection length */ ConnectionInfoLength = Message->Request.u1.s1.DataLength - sizeof(LPCP_CONNECTION_MESSAGE); } /* Check if we had connection information */ if (ConnectionInformation) { /* Check if we had a length pointer */ if (ConnectionInformationLength) { /* Return the length */ *ConnectionInformationLength = ConnectionInfoLength; } /* Return the connection information */ RtlCopyMemory(ConnectionInformation, ConnectMessage + 1, ConnectionInfoLength ); } /* Make sure we had a connected port */ if (ClientPort->ConnectedPort) { /* Get the message length before the port might get killed */ PortMessageLength = Port->MaxMessageLength; /* Insert the client port */ Status = ObInsertObject(ClientPort, NULL, PORT_ALL_ACCESS, 0, (PVOID *)NULL, &Handle); if (NT_SUCCESS(Status)) { /* Return the handle */ *PortHandle = Handle; LPCTRACE(LPC_CONNECT_DEBUG, "Handle: %p. Length: %lx\n", Handle, PortMessageLength); /* Check if maximum length was requested */ if (MaxMessageLength) *MaxMessageLength = PortMessageLength; /* Check if we had a client view */ if (ClientView) { /* Copy it back */ RtlCopyMemory(ClientView, &ConnectMessage->ClientView, sizeof(PORT_VIEW)); } /* Check if we had a server view */ if (ServerView) { /* Copy it back */ RtlCopyMemory(ServerView, &ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW)); } } } else { /* No connection port, we failed */ if (SectionToMap) ObDereferenceObject(SectionToMap); /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Check if it's because the name got deleted */ if (!(ClientPort->ConnectionPort) || (Port->Flags & LPCP_NAME_DELETED)) { /* Set the correct status */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { /* Otherwise, the caller refused us */ Status = STATUS_PORT_CONNECTION_REFUSED; } /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Kill the port */ ObDereferenceObject(ClientPort); } /* Free the message */ LpcpFreeToPortZone(Message, 0); } else { /* No reply message, fail */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); Status = STATUS_PORT_CONNECTION_REFUSED; } /* Return status */ ObDereferenceObject(Port); return Status; Cleanup: /* We failed, free the message */ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread); /* Check if the semaphore got signaled */ if (KeReadStateSemaphore(&Thread->LpcReplySemaphore)) { /* Wait on it */ KeWaitForSingleObject(&Thread->LpcReplySemaphore, WrExecutive, KernelMode, FALSE, NULL); } /* Check if we had a message and free it */ if (Message) LpcpFreeToPortZone(Message, 0); /* Dereference other objects */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); /* Return status */ ObDereferenceObject(Port); return Status; }
ViewBase = NULL; SectionOffset.LowPart = 0; SectionOffset.HighPart = 0; ViewSize = 0; // // Map the system dll into the user part of the address space // st = MmMapViewOfSection( PspSystemDll.Section, Process, &ViewBase, 0L, 0L, &SectionOffset, &ViewSize, ViewShare, 0L, PAGE_READWRITE ); if ( st != STATUS_SUCCESS ) { #if DBG DbgPrint("PS: Unable to map system dll at based address.\n"); #endif st = STATUS_CONFLICTING_ADDRESSES; } if ( ARGUMENT_PRESENT(DllBase) ) { *DllBase = ViewBase;
NTSTATUS MuInitializeUserModeHelper ( PMU_GLOBAL_DATA GlobalData ) { NTSTATUS status; HANDLE file, proc, dllsec; SIZE_T imgsize = 0; PVOID secobj, dllbase = NULL; LARGE_INTEGER secofs; UNICODE_STRING fp; IO_STATUS_BLOCK iosb; OBJECT_ATTRIBUTES oa; WCHAR path[MAX_PATH]; wcscpy(path, MU_ROOTDIR_SYSTEM32); wcscat(path, MU_FILENAME_HELPER_DLL); RtlInitUnicodeString(&fp, path); InitializeObjectAttributes(&oa, &fp, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); status = ZwOpenFile(&file, GENERIC_READ, &oa, &iosb, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(status)) { status = ZwCreateSection(&dllsec, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE_READWRITE, SEC_IMAGE, file); ZwClose(file); if (!NT_SUCCESS(status)) return status; status = ObReferenceObjectByHandle(dllsec, SECTION_ALL_ACCESS, *MmSectionObjectType, KernelMode, &secobj, NULL); ZwClose(dllsec); if (NT_SUCCESS(status)) { secofs.QuadPart = 0; status = MmMapViewOfSection(secobj, PsGetCurrentProcess(), &dllbase, 0, 0, &secofs, &imgsize, ViewShare, 0, PAGE_EXECUTE_READWRITE); if (NT_SUCCESS(status)) { status = MuLinkDll(GlobalData, dllbase); MmUnmapViewOfSection(PsGetCurrentProcess(), dllbase); } if (!NT_SUCCESS(status)) { ObDereferenceObject(secobj); secobj = NULL; } GlobalData->DllSection = secobj; GlobalData->DllImageSize = imgsize; GlobalData->DllImageBase = dllbase; } } return status; }
BOOL APIENTRY EngMapSection( IN PVOID pvSection, IN BOOL bMap, IN HANDLE hProcess, OUT PVOID* pvBaseAddress) { NTSTATUS Status; PENGSECTION pSection = pvSection; PEPROCESS pepProcess; /* Get a pointer to the process */ Status = ObReferenceObjectByHandle(hProcess, PROCESS_VM_OPERATION, NULL, KernelMode, (PVOID*)&pepProcess, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Could not access process %p, Status=0x%lx\n", hProcess, Status); return FALSE; } if (bMap) { /* Make sure the section isn't already mapped */ ASSERT(pSection->pvMappedBase == NULL); /* Map the section into the process address space */ Status = MmMapViewOfSection(pSection->pvSectionObject, pepProcess, &pSection->pvMappedBase, 0, pSection->cjViewSize, NULL, &pSection->cjViewSize, 0, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to map a section Status=0x%x\n", Status); } } else { /* Make sure the section is mapped */ ASSERT(pSection->pvMappedBase); /* Unmap the section from the process address space */ Status = MmUnmapViewOfSection(pepProcess, pSection->pvMappedBase); if (NT_SUCCESS(Status)) { pSection->pvMappedBase = NULL; } else { DPRINT1("Failed to unmap a section @ %p Status=0x%x\n", pSection->pvMappedBase, Status); } } /* Dereference the process */ ObDereferenceObject(pepProcess); /* Set the new mapping base and return bool status */ *pvBaseAddress = pSection->pvMappedBase; return NT_SUCCESS(Status); }
NTSTATUS APIENTRY Win32kProcessCallback(struct _EPROCESS *Process, BOOLEAN Create) { PPROCESSINFO ppiCurrent, *pppi; NTSTATUS Status; ASSERT(Process->Peb); UserEnterExclusive(); if (Create) { SIZE_T ViewSize = 0; LARGE_INTEGER Offset; PVOID UserBase = NULL; PRTL_USER_PROCESS_PARAMETERS pParams = Process->Peb->ProcessParameters; /* We might be called with an already allocated win32 process */ ppiCurrent = PsGetProcessWin32Process(Process); if (ppiCurrent != NULL) { /* There is no more to do for us (this is a success code!) */ Status = STATUS_ALREADY_WIN32; goto Leave; } /* Allocate a new win32 process */ ppiCurrent = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESSINFO), USERTAG_PROCESSINFO); if (ppiCurrent == NULL) { ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n", HandleToUlong(Process->UniqueProcessId)); Status = STATUS_NO_MEMORY; goto Leave; } RtlZeroMemory(ppiCurrent, sizeof(PROCESSINFO)); PsSetProcessWin32Process(Process, ppiCurrent, NULL); #if DBG DbgInitDebugChannels(); #if KDBG KdRosRegisterCliCallback(DbgGdiKdbgCliCallback); #endif #endif TRACE_CH(UserProcess,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent, HandleToUlong(Process->UniqueProcessId)); /* map the global heap into the process */ Offset.QuadPart = 0; Status = MmMapViewOfSection(GlobalUserHeapSection, PsGetCurrentProcess(), &UserBase, 0, 0, &Offset, &ViewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */ if (!NT_SUCCESS(Status)) { TRACE_CH(UserProcess,"Failed to map the global heap! 0x%x\n", Status); goto Leave; } ppiCurrent->HeapMappings.Next = NULL; ppiCurrent->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap; ppiCurrent->HeapMappings.UserMapping = UserBase; ppiCurrent->HeapMappings.Count = 1; InitializeListHead(&ppiCurrent->MenuListHead); InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList); InitializeListHead(&ppiCurrent->GDIDcAttrFreeList); InitializeListHead(&ppiCurrent->PrivateFontListHead); ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock); InitializeListHead(&ppiCurrent->DriverObjListHead); ExInitializeFastMutex(&ppiCurrent->DriverObjListLock); ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout(); if (!EngCreateEvent((PEVENT *)&ppiCurrent->InputIdleEvent)) { KeBugCheck(0); } KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE); /* map the gdi handle table to user land */ Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process); Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT; pParams = Process->Peb->ProcessParameters; ppiCurrent->peProcess = Process; /* setup process flags */ ppiCurrent->W32PF_flags = W32PF_THREADCONNECTED; if ( pParams && pParams->WindowFlags & STARTF_SCRNSAVER ) { ppiScrnSaver = ppiCurrent; ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER; } // Fixme check if this process is allowed. ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application it will get toggled off. /* Create pools for GDI object attributes */ ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG'); ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG'); ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG'); ASSERT(ppiCurrent->pPoolDcAttr); ASSERT(ppiCurrent->pPoolBrushAttr); ASSERT(ppiCurrent->pPoolRgnAttr); /* Add the process to the global list */ ppiCurrent->ppiNext = gppiList; gppiList = ppiCurrent; } else { /* Get the Win32 Process */ ppiCurrent = PsGetProcessWin32Process(Process); ASSERT(ppiCurrent); TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent); ppiCurrent->W32PF_flags |= W32PF_TERMINATED; if (ppiScrnSaver == ppiCurrent) ppiScrnSaver = NULL; if (ppiCurrent->InputIdleEvent) { EngFreeMem(ppiCurrent->InputIdleEvent); ppiCurrent->InputIdleEvent = NULL; } IntCleanupMenus(Process, ppiCurrent); IntCleanupCurIcons(Process, ppiCurrent); GDI_CleanupForProcess(Process); co_IntGraphicsCheck(FALSE); /* * Deregister logon application automatically */ if(LogonProcess == ppiCurrent) { LogonProcess = NULL; } /* Close the startup desktop */ if(ppiCurrent->rpdeskStartup) ObDereferenceObject(ppiCurrent->rpdeskStartup); if(ppiCurrent->hdeskStartup) ZwClose(ppiCurrent->hdeskStartup); /* Close the current window station */ UserSetProcessWindowStation(NULL); /* Destroy GDI pools */ GdiPoolDestroy(ppiCurrent->pPoolDcAttr); GdiPoolDestroy(ppiCurrent->pPoolBrushAttr); GdiPoolDestroy(ppiCurrent->pPoolRgnAttr); if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL; pppi = &gppiList; while (*pppi != NULL && *pppi != ppiCurrent) pppi = &(*pppi)->ppiNext; ASSERT(*pppi == ppiCurrent); *pppi = ppiCurrent->ppiNext; TRACE_CH(UserProcess,"Freeing ppi 0x%p\n", ppiCurrent); #if DBG if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL)) { DbgUserDumpHandleTable(); } #endif /* Free the PROCESSINFO */ PsSetProcessWin32Process(Process, NULL, ppiCurrent); ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO); } Status = STATUS_SUCCESS; Leave: UserLeave(); return Status; }