|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
process.c
Abstract:
This module contains the worker routines called to create and maintain the application process structure for the Client-Server Runtime Subsystem to the Session Manager SubSystem.
Author:
Steve Wood (stevewo) 10-Oct-1990
Revision History:
--*/
#include "csrsrv.h"
#include <wchar.h>
// ProcessSequenceCount will never be a value less than FIRST_SEQUENCE_COUNT
// currently GDI needs 0 - 4 to be reserved.
ULONG ProcessSequenceCount = FIRST_SEQUENCE_COUNT;
#define THREAD_HASH_SIZE 256
#define THREAD_ID_TO_HASH(id) (HandleToUlong(id)&(THREAD_HASH_SIZE-1))
LIST_ENTRY CsrThreadHashTable[THREAD_HASH_SIZE];
SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = { sizeof(SECURITY_QUALITY_OF_SERVICE), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE };
PCSR_PROCESS FindProcessForShutdown( PLUID CallerLuid );
NTSTATUS ReadUnicodeString(HANDLE ProcessHandle, PUNICODE_STRING RemoteString, PUNICODE_STRING LocalString );
VOID CsrpSetToNormalPriority( VOID ) { KPRIORITY SetBasePriority;
SetBasePriority = FOREGROUND_BASE_PRIORITY + 4; NtSetInformationProcess( NtCurrentProcess(), ProcessBasePriority, (PVOID) &SetBasePriority, sizeof(SetBasePriority) ); }
VOID CsrpSetToShutdownPriority( VOID ) { NTSTATUS Status; BOOLEAN WasEnabled; KPRIORITY SetBasePriority;
Status = RtlAdjustPrivilege( SE_INC_BASE_PRIORITY_PRIVILEGE, TRUE, FALSE, &WasEnabled);
if (!NT_SUCCESS(Status)) return;
SetBasePriority = FOREGROUND_BASE_PRIORITY + 6; NtSetInformationProcess( NtCurrentProcess(), ProcessBasePriority, (PVOID) &SetBasePriority, sizeof(SetBasePriority) ); }
VOID CsrSetForegroundPriority( IN PCSR_PROCESS Process ) { PROCESS_FOREGROUND_BACKGROUND Fg;
Fg.Foreground = TRUE;
NtSetInformationProcess( Process->ProcessHandle, ProcessForegroundInformation, (PVOID)&Fg, sizeof(Fg) ); }
VOID CsrSetBackgroundPriority( IN PCSR_PROCESS Process ) { PROCESS_FOREGROUND_BACKGROUND Fg;
Fg.Foreground = FALSE;
NtSetInformationProcess( Process->ProcessHandle, ProcessForegroundInformation, (PVOID)&Fg, sizeof(Fg) ); }
//
// Though this function does not seem to cleanup on failure, failure
// will cause Csrss to exit, so any allocated memory will be freed and
// any open handle will be closed.
//
NTSTATUS CsrInitializeProcessStructure( VOID) { NTSTATUS Status; ULONG i;
Status = RtlInitializeCriticalSection(&CsrProcessStructureLock); if (!NT_SUCCESS(Status)) { return Status; }
CsrRootProcess = CsrAllocateProcess(); if (CsrRootProcess == NULL) { return STATUS_NO_MEMORY; }
InitializeListHead( &CsrRootProcess->ListLink ); CsrRootProcess->ProcessHandle = (HANDLE) -1; CsrRootProcess->ClientId = NtCurrentTeb()->ClientId; for (i = 0; i < THREAD_HASH_SIZE; i++) { InitializeListHead(&CsrThreadHashTable[i]); }
Status = RtlInitializeCriticalSection(&CsrWaitListsLock);
return Status; }
PCSR_PROCESS CsrAllocateProcess( VOID) { PCSR_PROCESS Process; ULONG ProcessSize;
//
// Allocate an Windows Process Object. At the end of the process
// structure is an array of pointers to each server DLL's per process
// data. The per process data is contained in the memory after the
// array.
//
ProcessSize = (ULONG)QUAD_ALIGN(sizeof( CSR_PROCESS ) + (CSR_MAX_SERVER_DLL * sizeof(PVOID))) + CsrTotalPerProcessDataLength; Process = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), ProcessSize ); if (Process == NULL) { return( NULL ); }
//
// Initialize the fields of the process object
//
RtlZeroMemory( Process, ProcessSize);
//
// grab the ProcessSequenceNumber and increment it, making sure that it
// is never less than FIRST_SEQUENCE_COUNT.
//
Process->SequenceNumber = ProcessSequenceCount++;
if (ProcessSequenceCount < FIRST_SEQUENCE_COUNT) ProcessSequenceCount = FIRST_SEQUENCE_COUNT;
CsrLockedReferenceProcess(Process);
InitializeListHead( &Process->ThreadList ); return( Process ); }
VOID CsrDeallocateProcess( IN PCSR_PROCESS Process ) { RtlFreeHeap( CsrHeap, 0, Process ); }
//
// NOTE: The process structure lock must be held when calling this routine.
//
VOID CsrInsertProcess( IN PCSR_PROCESS CallingProcess, IN PCSR_PROCESS Process ) { PCSR_SERVER_DLL LoadedServerDll; ULONG i;
ASSERT(ProcessStructureListLocked());
InsertTailList( &CsrRootProcess->ListLink, &Process->ListLink );
for (i=0; i<CSR_MAX_SERVER_DLL; i++) { LoadedServerDll = CsrLoadedServerDll[i]; if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) { (*LoadedServerDll->AddProcessRoutine)(CallingProcess, Process); } } }
//
// NOTE: The process structure lock must be held when calling this routine.
//
VOID CsrRemoveProcess( IN PCSR_PROCESS Process ) { PCSR_SERVER_DLL LoadedServerDll; ULONG i;
ASSERT(ProcessStructureListLocked());
RemoveEntryList( &Process->ListLink ); ReleaseProcessStructureLock();
for (i=0; i<CSR_MAX_SERVER_DLL; i++) { LoadedServerDll = CsrLoadedServerDll[i]; if (LoadedServerDll && LoadedServerDll->DisconnectRoutine) { (LoadedServerDll->DisconnectRoutine)(Process); } }
}
NTSTATUS CsrCreateProcess( IN HANDLE ProcessHandle, IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId, IN PCSR_NT_SESSION Session, IN ULONG DebugFlags, IN PCLIENT_ID DebugUserInterface OPTIONAL ) { PCSR_PROCESS Process; PCSR_THREAD Thread; NTSTATUS Status; ULONG i; PVOID ProcessDataPtr; CLIENT_ID CallingClientId; PCSR_THREAD CallingThread; PCSR_PROCESS CallingProcess; KERNEL_USER_TIMES TimeInfo;
CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
//
// remember the client id of the calling process.
//
CallingClientId = CallingThread->ClientId;
AcquireProcessStructureLock();
//
// look for calling thread.
//
CallingThread = CsrLocateThreadByClientId(&CallingProcess, &CallingClientId); if (CallingThread == NULL) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; }
Process = CsrAllocateProcess(); if (Process == NULL) { Status = STATUS_NO_MEMORY; ReleaseProcessStructureLock(); return( Status ); }
//
// copy per-process data from parent to child
//
CallingProcess = (CSR_SERVER_QUERYCLIENTTHREAD())->Process; ProcessDataPtr = (PVOID)QUAD_ALIGN(&Process->ServerDllPerProcessData[CSR_MAX_SERVER_DLL]); for (i=0; i<CSR_MAX_SERVER_DLL; i++) { if (CsrLoadedServerDll[i] != NULL && CsrLoadedServerDll[i]->PerProcessDataLength) { Process->ServerDllPerProcessData[i] = ProcessDataPtr; RtlMoveMemory(ProcessDataPtr, CallingProcess->ServerDllPerProcessData[i], CsrLoadedServerDll[i]->PerProcessDataLength ); ProcessDataPtr = (PVOID)QUAD_ALIGN((PCHAR)ProcessDataPtr + CsrLoadedServerDll[i]->PerProcessDataLength); } else { Process->ServerDllPerProcessData[i] = NULL; } }
Status = NtSetInformationProcess( ProcessHandle, ProcessExceptionPort, (PVOID)&CsrApiPort, sizeof(HANDLE) ); if ( !NT_SUCCESS(Status) ) { CsrDeallocateProcess( Process ); ReleaseProcessStructureLock(); return( STATUS_NO_MEMORY ); }
//
// If we are creating a process group, the group leader has the same
// process id and sequence number of itself. If the leader dies and
// his pid is recycled, the sequence number mismatch will prevent it
// from being viewed as a group leader.
//
if ( DebugFlags & CSR_CREATE_PROCESS_GROUP ) { Process->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess); Process->ProcessGroupSequence = Process->SequenceNumber; } else { Process->ProcessGroupId = CallingProcess->ProcessGroupId; Process->ProcessGroupSequence = CallingProcess->ProcessGroupSequence; }
if ( DebugFlags & CSR_PROCESS_CONSOLEAPP ) { Process->Flags |= CSR_PROCESS_CONSOLEAPP; }
DebugFlags &= ~(CSR_PROCESS_CONSOLEAPP | CSR_CREATE_PROCESS_GROUP);
if ( !DebugFlags && CallingProcess->DebugFlags & CSR_DEBUG_PROCESS_TREE ) { Process->DebugFlags = CSR_DEBUG_PROCESS_TREE; Process->DebugUserInterface = CallingProcess->DebugUserInterface; } if ( DebugFlags & (CSR_DEBUG_THIS_PROCESS | CSR_DEBUG_PROCESS_TREE) && ARGUMENT_PRESENT(DebugUserInterface) ) { Process->DebugFlags = DebugFlags; Process->DebugUserInterface = *DebugUserInterface; }
if ( Process->DebugFlags ) {
//
// Process is being debugged, so set up debug port
//
Status = NtSetInformationProcess( ProcessHandle, ProcessDebugPort, (PVOID)&CsrApiPort, sizeof(HANDLE) ); ASSERT(NT_SUCCESS(Status)); if ( !NT_SUCCESS(Status) ) { CsrDeallocateProcess( Process ); ReleaseProcessStructureLock(); return( STATUS_NO_MEMORY ); } } //
// capture the thread's createtime so that we can use
// this as a sequence number
//
Status = NtQueryInformationThread( ThreadHandle, ThreadTimes, (PVOID)&TimeInfo, sizeof(TimeInfo), NULL ); if ( !NT_SUCCESS(Status) ) { CsrDeallocateProcess( Process ); ReleaseProcessStructureLock(); return( Status ); }
Thread = CsrAllocateThread( Process ); if (Thread == NULL) { CsrDeallocateProcess( Process ); ReleaseProcessStructureLock(); return( STATUS_NO_MEMORY ); }
Thread->CreateTime = TimeInfo.CreateTime;
Thread->ClientId = *ClientId; Thread->ThreadHandle = ThreadHandle;
ProtectHandle(ThreadHandle);
Thread->Flags = 0; CsrInsertThread( Process, Thread );
CsrReferenceNtSession(Session); Process->NtSession = Session;
Process->ClientId = *ClientId; Process->ProcessHandle = ProcessHandle;
CsrSetBackgroundPriority(Process);
Process->ShutdownLevel = 0x00000280;
CsrInsertProcess((CSR_SERVER_QUERYCLIENTTHREAD())->Process, Process); ReleaseProcessStructureLock(); return STATUS_SUCCESS; }
NTSTATUS CsrDestroyProcess( IN PCLIENT_ID ClientId, IN NTSTATUS ExitStatus ) { PLIST_ENTRY ListHead, ListNext; PCSR_THREAD DyingThread; PCSR_PROCESS DyingProcess;
CLIENT_ID DyingClientId;
DyingClientId = *ClientId;
AcquireProcessStructureLock();
DyingThread = CsrLocateThreadByClientId( &DyingProcess, &DyingClientId ); if (DyingThread == NULL) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; }
//
// prevent multiple destroys from causing problems. Scottlu and Markl
// beleive all known race conditions are now fixed. This is simply a
// precaution since we know that if this happens we process reference
// count underflow
//
if ( DyingProcess->Flags & CSR_PROCESS_DESTROYED ) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; }
DyingProcess->Flags |= CSR_PROCESS_DESTROYED;
ListHead = &DyingProcess->ThreadList; ListNext = ListHead->Flink; while (ListNext != ListHead) { DyingThread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) { ListNext = ListNext->Flink; continue; } else { DyingThread->Flags |= CSR_THREAD_DESTROYED; } AcquireWaitListsLock(); if (DyingThread->WaitBlock != NULL) { CsrNotifyWaitBlock(DyingThread->WaitBlock, NULL, NULL, NULL, CSR_PROCESS_TERMINATING, TRUE ); } ReleaseWaitListsLock(); CsrLockedDereferenceThread(DyingThread); ListNext = ListHead->Flink; }
ReleaseProcessStructureLock(); return STATUS_SUCCESS; }
NTSTATUS CsrCreateThread( IN PCSR_PROCESS Process, IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId, IN BOOLEAN ValidateCaller ) { PCSR_THREAD Thread; CLIENT_ID CallingClientId; PCSR_THREAD CallingThread; PCSR_PROCESS CallingProcess; KERNEL_USER_TIMES TimeInfo; NTSTATUS Status;
if (ValidateCaller) { CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
//
// remember the client id of the calling process.
//
CallingClientId = CallingThread->ClientId;
AcquireProcessStructureLock();
//
// look for calling thread.
//
CallingThread = CsrLocateThreadByClientId( &CallingProcess, &CallingClientId ); if (CallingThread == NULL) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; } } else { AcquireProcessStructureLock(); } Status = NtQueryInformationThread( ThreadHandle, ThreadTimes, (PVOID)&TimeInfo, sizeof(TimeInfo), NULL ); if ( !NT_SUCCESS(Status) ) { ReleaseProcessStructureLock(); return( Status ); }
if (Process->Flags & CSR_PROCESS_DESTROYED) { IF_DEBUG { DbgPrint("CSRSS: CsrCreateThread - process %p is destroyed\n", Process); } ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; }
Thread = CsrAllocateThread( Process ); if (Thread == NULL) { ReleaseProcessStructureLock(); return( STATUS_NO_MEMORY ); }
Thread->CreateTime = TimeInfo.CreateTime;
Thread->ClientId = *ClientId; Thread->ThreadHandle = ThreadHandle;
ProtectHandle(ThreadHandle);
Thread->Flags = 0; CsrInsertThread( Process, Thread ); ReleaseProcessStructureLock(); return STATUS_SUCCESS; }
NTSTATUS CsrCreateRemoteThread( IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId ) { PCSR_THREAD Thread; PCSR_PROCESS Process; NTSTATUS Status; HANDLE hThread; KERNEL_USER_TIMES TimeInfo;
Status = NtQueryInformationThread( ThreadHandle, ThreadTimes, (PVOID)&TimeInfo, sizeof(TimeInfo), NULL ); if ( !NT_SUCCESS(Status) ) { return( Status ); }
Status = CsrLockProcessByClientId( ClientId->UniqueProcess, &Process ); if (!NT_SUCCESS( Status )) { return( Status ); }
//
// Don't create the thread structure if the thread
// has already terminated.
//
if ( TimeInfo.ExitTime.QuadPart != 0 ) { CsrUnlockProcess( Process ); return( STATUS_THREAD_IS_TERMINATING ); }
Thread = CsrAllocateThread( Process ); if (Thread == NULL) { CsrUnlockProcess( Process ); return( STATUS_NO_MEMORY ); } Status = NtDuplicateObject( NtCurrentProcess(), ThreadHandle, NtCurrentProcess(), &hThread, 0L, 0L, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { hThread = ThreadHandle; }
Thread->CreateTime = TimeInfo.CreateTime;
Thread->ClientId = *ClientId; Thread->ThreadHandle = hThread;
ProtectHandle(hThread);
Thread->Flags = 0; CsrInsertThread( Process, Thread ); CsrUnlockProcess( Process ); return STATUS_SUCCESS; }
NTSTATUS CsrDestroyThread( IN PCLIENT_ID ClientId ) { CLIENT_ID DyingClientId; PCSR_THREAD DyingThread; PCSR_PROCESS DyingProcess;
DyingClientId = *ClientId;
AcquireProcessStructureLock();
DyingThread = CsrLocateThreadByClientId( &DyingProcess, &DyingClientId ); if (DyingThread == NULL) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; }
if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) { ReleaseProcessStructureLock(); return STATUS_THREAD_IS_TERMINATING; } else { DyingThread->Flags |= CSR_THREAD_DESTROYED; }
AcquireWaitListsLock(); if (DyingThread->WaitBlock != NULL) { CsrNotifyWaitBlock(DyingThread->WaitBlock, NULL, NULL, NULL, CSR_PROCESS_TERMINATING, TRUE ); } ReleaseWaitListsLock(); CsrLockedDereferenceThread(DyingThread);
ReleaseProcessStructureLock(); return STATUS_SUCCESS; }
PCSR_THREAD CsrAllocateThread( IN PCSR_PROCESS Process ) { PCSR_THREAD Thread; ULONG ThreadSize;
//
// Allocate an Windows Thread Object.
//
ThreadSize = QUAD_ALIGN(sizeof( CSR_THREAD )); Thread = (PCSR_THREAD)RtlAllocateHeap( CsrHeap, MAKE_TAG( THREAD_TAG ), ThreadSize ); if (Thread == NULL) { return( NULL ); }
//
// Initialize the fields of the thread object
//
RtlZeroMemory( Thread, ThreadSize );
CsrLockedReferenceThread(Thread); CsrLockedReferenceProcess(Process); Thread->Process = Process;
return( Thread ); }
VOID CsrDeallocateThread( IN PCSR_THREAD Thread ) { ASSERT (Thread->WaitBlock == NULL); RtlFreeHeap( CsrHeap, 0, Thread ); }
//
// NOTE: The process structure lock must be held while calling this routine.
//
VOID CsrInsertThread( IN PCSR_PROCESS Process, IN PCSR_THREAD Thread) { ULONG i; ASSERT(ProcessStructureListLocked());
InsertTailList(&Process->ThreadList, &Thread->Link); Process->ThreadCount++; i = THREAD_ID_TO_HASH(Thread->ClientId.UniqueThread); InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks); }
//
// NOTE: The process structure lock must be held while calling this routine.
//
VOID CsrRemoveThread( IN PCSR_THREAD Thread) { ASSERT(ProcessStructureListLocked());
RemoveEntryList(&Thread->Link); Thread->Process->ThreadCount--;
if (Thread->HashLinks.Flink) { RemoveEntryList(&Thread->HashLinks); }
//
// If this is the last thread, then make sure we undo the reference
// that this thread had on the process.
//
if (Thread->Process->ThreadCount == 0) { if (!(Thread->Process->Flags & CSR_PROCESS_LASTTHREADOK)) { Thread->Process->Flags |= CSR_PROCESS_LASTTHREADOK; CsrLockedDereferenceProcess(Thread->Process); } }
Thread->Flags |= CSR_THREAD_TERMINATING; }
NTSTATUS CsrLockProcessByClientId( IN HANDLE UniqueProcessId, OUT PCSR_PROCESS *Process ) { NTSTATUS Status; PLIST_ENTRY ListHead, ListNext; PCSR_PROCESS ProcessPtr;
AcquireProcessStructureLock();
ASSERT( Process != NULL ); *Process = NULL;
Status = STATUS_UNSUCCESSFUL; ListHead = &CsrRootProcess->ListLink; ListNext = ListHead; do { ProcessPtr = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink ); if (ProcessPtr->ClientId.UniqueProcess == UniqueProcessId) { Status = STATUS_SUCCESS; break; } ListNext = ListNext->Flink; } while (ListNext != ListHead);
if (NT_SUCCESS( Status )) { CsrLockedReferenceProcess(ProcessPtr); *Process = ProcessPtr; } else { ReleaseProcessStructureLock(); }
return( Status ); }
NTSTATUS CsrUnlockProcess( IN PCSR_PROCESS Process ) { CsrLockedDereferenceProcess( Process ); ReleaseProcessStructureLock(); return( STATUS_SUCCESS ); }
NTSTATUS CsrLockThreadByClientId( IN HANDLE UniqueThreadId, OUT PCSR_THREAD *Thread) { NTSTATUS Status; ULONG Index; PLIST_ENTRY ListHead, ListNext; PCSR_THREAD ThreadPtr;
AcquireProcessStructureLock();
ASSERT(Thread != NULL);
Index = THREAD_ID_TO_HASH(UniqueThreadId);
ListHead = &CsrThreadHashTable[Index]; ListNext = ListHead->Flink; while (ListNext != ListHead) { ThreadPtr = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks ); if (ThreadPtr->ClientId.UniqueThread == UniqueThreadId && !(ThreadPtr->Flags & CSR_THREAD_DESTROYED)) { break; }
ListNext = ListNext->Flink; }
if (ListNext != ListHead) { *Thread = ThreadPtr; Status = STATUS_SUCCESS; CsrLockedReferenceThread(ThreadPtr); } else { Status = STATUS_UNSUCCESSFUL; ReleaseProcessStructureLock(); }
return Status; }
//
// NOTE: The process structure lock must be held while calling this routine.
//
NTSTATUS CsrUnlockThread( IN PCSR_THREAD Thread) { ASSERT(ProcessStructureListLocked());
CsrLockedDereferenceThread(Thread); ReleaseProcessStructureLock();
return STATUS_SUCCESS; }
//
// NOTE: The process structure lock must be held while calling this routine.
//
PCSR_THREAD CsrLocateThreadByClientId( OUT PCSR_PROCESS *Process OPTIONAL, IN PCLIENT_ID ClientId) { ULONG Index; PLIST_ENTRY ListHead, ListNext; PCSR_THREAD Thread;
ASSERT(ProcessStructureListLocked());
Index = THREAD_ID_TO_HASH(ClientId->UniqueThread);
if (ARGUMENT_PRESENT(Process)) { *Process = NULL; }
ListHead = &CsrThreadHashTable[Index]; ListNext = ListHead->Flink; while (ListNext != ListHead) { Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks ); if (Thread->ClientId.UniqueThread == ClientId->UniqueThread && Thread->ClientId.UniqueProcess == ClientId->UniqueProcess) { if (ARGUMENT_PRESENT(Process)) { *Process = Thread->Process; }
return Thread; }
ListNext = ListNext->Flink; }
return NULL; }
//
// NOTE: The process structure lock must be held while calling this routine.
//
PCSR_THREAD CsrLocateServerThread( IN PCLIENT_ID ClientId) { PLIST_ENTRY ListHead, ListNext; PCSR_THREAD Thread;
ListHead = &CsrRootProcess->ThreadList; ListNext = ListHead->Flink; while (ListNext != ListHead) { Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); if (Thread->ClientId.UniqueThread == ClientId->UniqueThread) { return Thread; }
ListNext = ListNext->Flink; }
return NULL; }
BOOLEAN CsrImpersonateClient( IN PCSR_THREAD Thread) { NTSTATUS Status; PCSR_THREAD CallingThread;
CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
if (Thread == NULL) { Thread = CallingThread; if (Thread == NULL) { return FALSE; } }
Status = NtImpersonateThread(NtCurrentThread(), Thread->ThreadHandle, &CsrSecurityQos); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: Can't impersonate client thread - Status = %lx\n", Status); if (Status != STATUS_BAD_IMPERSONATION_LEVEL) { DbgBreakPoint(); } }
return FALSE; }
//
// Keep track of recursion by printer drivers.
//
if (CallingThread != NULL) { ++CallingThread->ImpersonateCount; }
return TRUE; }
BOOLEAN CsrRevertToSelf( VOID) { HANDLE NewToken; NTSTATUS Status; PCSR_THREAD CallingThread;
CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
//
// Keep track of recursion by printer drivers.
//
if (CallingThread != NULL) { if (CallingThread->ImpersonateCount == 0) { IF_DEBUG { DbgPrint( "CSRSS: CsrRevertToSelf called while not impersonating\n" ); DbgBreakPoint(); }
return FALSE; }
if (--CallingThread->ImpersonateCount > 0) { return TRUE; } }
NewToken = NULL; Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, (PVOID)&NewToken, (ULONG)sizeof(HANDLE)); ASSERT(NT_SUCCESS(Status)); return NT_SUCCESS(Status); }
/*++
Routine Description:
This function must be called by client DLL's whenever they create a thread that runs in the context of CSR. This function is not called for server threads that are attached to a client in the "server handle" field. This function replaces the old static thread tables.
Arguments:
ThreadHandle - Supplies a handle to the thread.
ClientId - Supplies the address of the thread's client id.
Flags - Not Used.
Return Value:
Returns the address of the static server thread created by this function.
--*/
PVOID CsrAddStaticServerThread( IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId, IN ULONG Flags ) { PCSR_THREAD Thread;
AcquireProcessStructureLock();
ASSERT(CsrRootProcess != NULL); Thread = CsrAllocateThread(CsrRootProcess); if (Thread) { Thread->ThreadHandle = ThreadHandle;
ProtectHandle(ThreadHandle);
Thread->ClientId = *ClientId; Thread->Flags = Flags; InsertTailList(&CsrRootProcess->ThreadList, &Thread->Link); CsrRootProcess->ThreadCount++; }
ReleaseProcessStructureLock(); return (PVOID)Thread; }
NTSTATUS CsrExecServerThread( IN PUSER_THREAD_START_ROUTINE StartAddress, IN ULONG Flags ) { PCSR_THREAD Thread; NTSTATUS Status; HANDLE ThreadHandle; CLIENT_ID ClientId;
AcquireProcessStructureLock();
ASSERT(CsrRootProcess != NULL); Thread = CsrAllocateThread(CsrRootProcess); if (Thread == NULL) { Status = STATUS_NO_MEMORY; goto Exit; }
Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 0, (PUSER_THREAD_START_ROUTINE)StartAddress, NULL, &ThreadHandle, &ClientId); if (NT_SUCCESS(Status)) { Thread->ThreadHandle = ThreadHandle;
ProtectHandle(ThreadHandle);
Thread->ClientId = ClientId; Thread->Flags = Flags; InsertTailList(&CsrRootProcess->ThreadList, &Thread->Link); CsrRootProcess->ThreadCount++; } else { CsrDeallocateThread(Thread); }
Exit: ReleaseProcessStructureLock(); return Status; }
VOID CsrReferenceThread( PCSR_THREAD t ) { ASSERT (t != NULL);
AcquireProcessStructureLock();
ASSERT((t->Flags & CSR_THREAD_DESTROYED) == 0); ASSERT(t->ReferenceCount != 0);
t->ReferenceCount++; ReleaseProcessStructureLock(); }
VOID CsrProcessRefcountZero( PCSR_PROCESS p ) { ASSERT (p != NULL);
CsrRemoveProcess(p); if (p->NtSession) { CsrDereferenceNtSession(p->NtSession,0); }
//
// process might not have made it through dll init routine.
//
if ( p->ClientPort ) { NtClose(p->ClientPort); } NtClose(p->ProcessHandle ); CsrDeallocateProcess(p); }
VOID CsrDereferenceProcess( PCSR_PROCESS p ) { LONG LockCount;
ASSERT (p != NULL);
AcquireProcessStructureLock();
LockCount = --(p->ReferenceCount);
ASSERT(LockCount >= 0); if ( !LockCount ) { CsrProcessRefcountZero(p); } else { ReleaseProcessStructureLock(); } }
VOID CsrThreadRefcountZero( PCSR_THREAD t ) { PCSR_PROCESS p; NTSTATUS Status;
ASSERT (t != NULL); p = t->Process; ASSERT (p != NULL);
CsrRemoveThread(t);
ReleaseProcessStructureLock();
UnProtectHandle(t->ThreadHandle); Status = NtClose(t->ThreadHandle); ASSERT(NT_SUCCESS(Status)); CsrDeallocateThread(t);
CsrDereferenceProcess(p); }
ULONG CsrDereferenceThread( PCSR_THREAD t) { ULONG LockCount;
ASSERT (t != NULL);
AcquireProcessStructureLock();
ASSERT(t->ReferenceCount > 0);
LockCount = --(t->ReferenceCount); if (!LockCount) { CsrThreadRefcountZero(t); } else { ReleaseProcessStructureLock(); }
return LockCount; }
VOID CsrLockedReferenceProcess( PCSR_PROCESS p) { ASSERT (p != NULL); p->ReferenceCount++; }
VOID CsrLockedReferenceThread( PCSR_THREAD t) { ASSERT (t != NULL); t->ReferenceCount++; }
VOID CsrLockedDereferenceProcess( PCSR_PROCESS p) { LONG LockCount;
ASSERT (p != NULL);
LockCount = --(p->ReferenceCount);
ASSERT(LockCount >= 0); if (!LockCount) { CsrProcessRefcountZero(p); AcquireProcessStructureLock(); } }
VOID CsrLockedDereferenceThread( PCSR_THREAD t ) { LONG LockCount;
ASSERT (t != NULL);
LockCount = --(t->ReferenceCount);
ASSERT(LockCount >= 0); if ( !LockCount ) { CsrThreadRefcountZero(t); AcquireProcessStructureLock(); } }
//
// This routine will shutdown processes so either a logoff or a shutdown can
// occur. This simply calls the shutdown process handlers for each .dll until
// one .dll recognizes this process and will shut it down. Only the processes
// with the passed sid are shutdown.
//
NTSTATUS CsrShutdownProcesses( PLUID CallerLuid, ULONG Flags ) { PLIST_ENTRY ListHead, ListNext; PCSR_PROCESS Process; ULONG i; PCSR_SERVER_DLL LoadedServerDll; ULONG Command; BOOLEAN fFirstPass; NTSTATUS Status = STATUS_UNSUCCESSFUL;
AcquireProcessStructureLock();
//
// Mark the root process as system context.
//
CsrRootProcess->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT;
//
// Clear all the bits indicating that shutdown has visited the existing
// processes.
//
ListHead = &CsrRootProcess->ListLink; ListNext = ListHead->Flink; while (ListNext != ListHead) { Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink); Process->Flags &= ~CSR_PROCESS_SHUTDOWNSKIP; Process->ShutdownFlags = 0; ListNext = ListNext->Flink; }
CsrpSetToShutdownPriority(); while (TRUE) { //
// Find the next process to shutdown.
//
Process = FindProcessForShutdown(CallerLuid); if (Process == NULL) { ReleaseProcessStructureLock(); Status = STATUS_SUCCESS; break; }
CsrLockedReferenceProcess(Process);
fFirstPass = TRUE; TryAgain: for (i = 0; i < CSR_MAX_SERVER_DLL; i++) { LoadedServerDll = CsrLoadedServerDll[i]; if (LoadedServerDll && LoadedServerDll->ShutdownProcessRoutine) { //
// Release process structure lock before calling off.
// CSR_PROCESS structure is still reference counted.
//
ReleaseProcessStructureLock(); Command = (*LoadedServerDll->ShutdownProcessRoutine)(Process, Flags, fFirstPass); AcquireProcessStructureLock();
if (Command == SHUTDOWN_KNOWN_PROCESS) { //
// Process structure is unlocked.
//
break; } else if (Command == SHUTDOWN_UNKNOWN_PROCESS) { //
// Process structure is locked.
//
continue; } else if (Command == SHUTDOWN_CANCEL) { #if DBG
if (Flags & 4) { DbgPrint("Process %x cancelled forced shutdown\n", Process->ClientId.UniqueProcess); DbgBreakPoint(); } #endif
//
// Unlock process structure.
//
ReleaseProcessStructureLock(); Status = STATUS_CANCELLED; goto ExitLoop; } } }
//
// No subsystem has an exact match. Now go through them again and
// let them know there was no exact match. Some .dll should terminate
// it for us (most likely, console).
//
if (fFirstPass && Command == SHUTDOWN_UNKNOWN_PROCESS) { fFirstPass = FALSE; goto TryAgain; }
//
// Dereference this process structure if nothing knows about it.
//
if (i == CSR_MAX_SERVER_DLL) { CsrLockedDereferenceProcess(Process); } }
ExitLoop:
CsrpSetToNormalPriority();
return Status; }
PCSR_PROCESS FindProcessForShutdown( PLUID CallerLuid) { LUID ProcessLuid; LUID SystemLuid = SYSTEM_LUID; PLIST_ENTRY ListHead, ListNext; PCSR_PROCESS Process; PCSR_PROCESS ProcessT = NULL; PCSR_THREAD Thread; ULONG dwLevel = 0; NTSTATUS Status;
ListHead = &CsrRootProcess->ListLink; ListNext = ListHead->Flink; while (ListNext != ListHead) { Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink); ListNext = ListNext->Flink;
//
// If we've visited this process already, then skip it.
//
if (Process->Flags & CSR_PROCESS_SHUTDOWNSKIP) { continue; }
//
// See if this process is running under the passed sid. If not, mark
// it as visited and continue.
//
Status = CsrGetProcessLuid(Process->ProcessHandle, &ProcessLuid); if (Status == STATUS_ACCESS_DENIED && Process->ThreadCount > 0) { //
// Impersonate one of the threads and try again.
//
Thread = CONTAINING_RECORD(Process->ThreadList.Flink, CSR_THREAD, Link); if (CsrImpersonateClient(Thread)) { Status = CsrGetProcessLuid(NULL, &ProcessLuid); CsrRevertToSelf(); } else { Status = STATUS_BAD_IMPERSONATION_LEVEL; } }
if (!NT_SUCCESS(Status)) { //
// We don't have access to this process's luid, so skip it.
//
Process->Flags |= CSR_PROCESS_SHUTDOWNSKIP; continue; }
//
// Is it equal to the system context luid? If so, we want to
// remember this because we don't terminate this process: we only
// notify them.
//
if (RtlEqualLuid(&ProcessLuid, &SystemLuid)) { Process->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT; } else { //
// See if this process's luid is the same as the luid we're supposed
// to shut down (CallerSid).
//
if (!RtlEqualLuid(&ProcessLuid, CallerLuid)) { //
// If not equal to either, mark it as such.
//
Process->ShutdownFlags |= SHUTDOWN_OTHERCONTEXT; } }
if (Process->ShutdownLevel > dwLevel || ProcessT == NULL) { dwLevel = Process->ShutdownLevel; ProcessT = Process; } }
if (ProcessT != NULL) { ProcessT->Flags |= CSR_PROCESS_SHUTDOWNSKIP; return ProcessT; }
return NULL; }
NTSTATUS CsrGetProcessLuid( HANDLE ProcessHandle, PLUID LuidProcess ) { HANDLE UserToken = NULL; PTOKEN_STATISTICS pStats; ULONG BytesRequired; NTSTATUS Status, CloseStatus;
if (ProcessHandle == NULL) {
//
// Check for a thread token first
//
Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE, &UserToken);
if (!NT_SUCCESS(Status)) { if (Status != STATUS_NO_TOKEN) return Status;
//
// No thread token, go to the process
//
ProcessHandle = NtCurrentProcess(); UserToken = NULL; } }
if (UserToken == NULL) { Status = NtOpenProcessToken(ProcessHandle, TOKEN_QUERY, &UserToken); if (!NT_SUCCESS(Status)) return Status; }
Status = NtQueryInformationToken( UserToken, // Handle
TokenStatistics, // TokenInformationClass
NULL, // TokenInformation
0, // TokenInformationLength
&BytesRequired // ReturnLength
);
if (Status != STATUS_BUFFER_TOO_SMALL) { NtClose(UserToken); return Status; }
//
// Allocate space for the user info
//
pStats = (PTOKEN_STATISTICS)RtlAllocateHeap(CsrHeap, MAKE_TAG( TMP_TAG ), BytesRequired); if (pStats == NULL) { NtClose(UserToken); return Status; }
//
// Read in the user info
//
Status = NtQueryInformationToken( UserToken, // Handle
TokenStatistics, // TokenInformationClass
pStats, // TokenInformation
BytesRequired, // TokenInformationLength
&BytesRequired // ReturnLength
);
//
// We're finished with the token handle
//
CloseStatus = NtClose(UserToken); ASSERT(NT_SUCCESS(CloseStatus));
//
// Return the authentication LUID
//
*LuidProcess = pStats->AuthenticationId;
RtlFreeHeap(CsrHeap, 0, pStats); return Status; }
VOID CsrSetCallingSpooler( BOOLEAN fSet) { //
// Obsolete function that may be called by third part drivers.
//
UNREFERENCED_PARAMETER(fSet); }
//
// This routine creates a process based on a message passed in to sb port.
// Used by smss to have Posix and OS/2 apps created in the appropriate
// (terminal server) session.
//
BOOLEAN CsrSbCreateProcess( IN OUT PSBAPIMSG m ) { NTSTATUS Status; RTL_USER_PROCESS_INFORMATION ProcessInformation; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; PROCESS_SESSION_INFORMATION ProcessInfo; PSBCREATEPROCESS a = &(m->u.CreateProcess); HANDLE RemoteProcess = NULL; CLIENT_ID RemoteClientId; UNICODE_STRING ImageFileName, DefaultLibPath, CurrentDirectory, CommandLine; PVOID DefaultEnvironment = NULL; PROCESS_BASIC_INFORMATION ProcInfo; OBJECT_ATTRIBUTES ObjA;
RtlInitUnicodeString(&ImageFileName,NULL); RtlInitUnicodeString(&DefaultLibPath,NULL); RtlInitUnicodeString(&CurrentDirectory,NULL); RtlInitUnicodeString(&CommandLine,NULL);
Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &ProcInfo, sizeof(ProcInfo), NULL );
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: NtQueryInformationProcess failed - Status = %lx\n", Status ); goto Done; }
InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL ); RemoteClientId.UniqueProcess = (HANDLE)ProcInfo.InheritedFromUniqueProcessId; RemoteClientId.UniqueThread = NULL;
Status = NtOpenProcess(&RemoteProcess, PROCESS_ALL_ACCESS, &ObjA, &RemoteClientId);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: NtOpenProcess failed - Status = %lx\n", Status ); goto Done; }
//
// Read pointer parameters from calling process's virtual memory
//
Status = ReadUnicodeString(RemoteProcess,a->i.ImageFileName,&ImageFileName);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString ImageFileName failed - Status = %lx\n", Status ); goto Done; }
Status = ReadUnicodeString(RemoteProcess,a->i.DefaultLibPath,&DefaultLibPath);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString DefaultLibPath failed - Status = %lx\n", Status ); goto Done; }
Status = ReadUnicodeString(RemoteProcess,a->i.CurrentDirectory,&CurrentDirectory);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString CurrentDirectory failed - Status = %lx\n", Status ); goto Done; }
Status = ReadUnicodeString(RemoteProcess,a->i.CommandLine,&CommandLine);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString CommandLine failed - Status = %lx\n", Status ); goto Done; }
//
// Copy our environment to be used by new process
//
Status = RtlCreateEnvironment(TRUE, &DefaultEnvironment);
if (!NT_SUCCESS( Status )) { DbgPrint( "CSRSS: CsrSrvCreateProcess: Can't create environemnt\n"); goto Done; }
Status = RtlCreateProcessParameters( &ProcessParameters, &ImageFileName, DefaultLibPath.Length == 0 ? NULL : &DefaultLibPath, &CurrentDirectory, &CommandLine, DefaultEnvironment, NULL, NULL, NULL, NULL );
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: RtlCreateProcessParameters failed - Status = %lx\n", Status ); goto Done; } if (a->i.Flags & SMP_DEBUG_FLAG) { ProcessParameters->DebugFlags = TRUE; } else { ProcessParameters->DebugFlags = a->i.DefaultDebugFlags; }
if ( a->i.Flags & SMP_SUBSYSTEM_FLAG ) { ProcessParameters->Flags |= RTL_USER_PROC_RESERVE_1MB; }
ProcessInformation.Length = sizeof( RTL_USER_PROCESS_INFORMATION ); Status = RtlCreateUserProcess( &ImageFileName, OBJ_CASE_INSENSITIVE, ProcessParameters, NULL, NULL, RemoteProcess, // set smss as the parent
FALSE, NULL, NULL, &ProcessInformation );
RtlDestroyProcessParameters( ProcessParameters );
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: RtlCreateUserProcess failed - Status = %lx\n", Status ); goto Done; }
if (IsTerminalServer()) {
//
// Set the MuSessionId in the PEB of the new process
//
ProcessInfo.SessionId = NtCurrentPeb()->SessionId; if (ProcessInfo.SessionId) { PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Attributes; HANDLE DirectoryHandle = NULL; WCHAR szSessionString[MAX_SESSION_PATH];
//
// Change the devmap of the process to per session.
//
swprintf(szSessionString, L"%ws\\%ld%ws", SESSION_ROOT, NtCurrentPeb()->SessionId, DOSDEVICES); RtlInitUnicodeString(&UnicodeString, szSessionString);
InitializeObjectAttributes(&Attributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenDirectoryObject(&DirectoryHandle, DIRECTORY_ALL_ACCESS, &Attributes); if (!NT_SUCCESS(Status)) { DbgPrint("CSRSS: NtOpenDirectoryObject failed in CsrSbCreateProcess - status = %lx\n", Status); goto Done; }
ProcessDeviceMapInfo.Set.DirectoryHandle = DirectoryHandle; Status = NtSetInformationProcess(ProcessInformation.Process, ProcessDeviceMap, &ProcessDeviceMapInfo.Set, sizeof(ProcessDeviceMapInfo.Set)); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtSetInformationProcess failed in CsrSbCreateProcess - status = %lx\n", Status); if (DirectoryHandle) { NtClose(DirectoryHandle); }
goto Done; }
if (DirectoryHandle) { NtClose(DirectoryHandle); } }
Status = NtSetInformationProcess( ProcessInformation.Process, ProcessSessionInformation, &ProcessInfo, sizeof( ProcessInfo ));
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: NtSetInformationProcess failed - Status = %lx\n", Status ); goto Done; } }
if (!(a->i.Flags & SMP_DONT_START)) { if (ProcessInformation.ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_NATIVE ) { NtTerminateProcess( ProcessInformation.Process, STATUS_INVALID_IMAGE_FORMAT );
NtWaitForSingleObject( ProcessInformation.Thread, FALSE, NULL );
NtClose( ProcessInformation.Thread ); NtClose( ProcessInformation.Process );
Status = STATUS_INVALID_IMAGE_FORMAT; goto Done; }
Status = NtResumeThread( ProcessInformation.Thread, NULL ); if (!NT_SUCCESS(Status)) { DbgPrint( "CSRSS: CsrSrvCreateProcess - NtResumeThread failed Status %lx\n",Status ); goto Done; }
if (!(a->i.Flags & SMP_ASYNC_FLAG)) { NtWaitForSingleObject( ProcessInformation.Thread, FALSE, NULL ); }
NtClose( ProcessInformation.Thread ); NtClose( ProcessInformation.Process );
}
//
// Copy output parameters to message
//
a->o.SubSystemType = ProcessInformation.ImageInformation.SubSystemType; a->o.ClientId.UniqueProcess = ProcessInformation.ClientId.UniqueProcess; a->o.ClientId.UniqueThread = ProcessInformation.ClientId.UniqueThread;
//
// Convert handles to caller's process
//
Status = NtDuplicateObject( NtCurrentProcess(), ProcessInformation.Process, RemoteProcess, &a->o.Process, 0, FALSE, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS(Status) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: NtDuplicateObject failed for process - Status = %lx\n", Status ); goto Done; }
Status = NtDuplicateObject( NtCurrentProcess(), ProcessInformation.Thread, RemoteProcess, &a->o.Thread, 0, FALSE, DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS(Status) ) { DbgPrint( "CSRSS: CsrSrvCreateProcess: NtDuplicateObject failed for thread - Status = %lx\n", Status ); goto Done; }
Done: if (NULL != ImageFileName.Buffer) RtlFreeHeap(CsrHeap,0,ImageFileName.Buffer); if (NULL != DefaultLibPath.Buffer) RtlFreeHeap(CsrHeap,0,DefaultLibPath.Buffer); if (NULL != CurrentDirectory.Buffer) RtlFreeHeap(CsrHeap,0,CurrentDirectory.Buffer); if (NULL != CommandLine.Buffer) RtlFreeHeap(CsrHeap,0,CommandLine.Buffer); if (NULL != RemoteProcess) NtClose(RemoteProcess);
m->ReturnedStatus = Status; return TRUE; }
//
// This routine will copy a UNICODE_STRING from a remote process to this one
//
NTSTATUS ReadUnicodeString(HANDLE ProcessHandle, PUNICODE_STRING RemoteString, PUNICODE_STRING LocalString ) { PWSTR Buffer = NULL; NTSTATUS Status;
RtlInitUnicodeString(LocalString, NULL);
if (NULL != RemoteString) { Status = NtReadVirtualMemory(ProcessHandle, RemoteString, LocalString, sizeof(UNICODE_STRING), NULL);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: ReadUnicodeString: NtReadVirtualMemory failed - Status = %lx\n", Status ); return Status; }
if ((0 != LocalString->Length) && (NULL != LocalString->Buffer)) { Buffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), LocalString->Length + sizeof(WCHAR) );
if (Buffer == NULL) { return STATUS_NO_MEMORY; }
Status = NtReadVirtualMemory(ProcessHandle, LocalString->Buffer, Buffer, LocalString->Length + sizeof(WCHAR), NULL);
if ( !NT_SUCCESS( Status ) ) { DbgPrint( "CSRSS: ReadUnicodeString: NtReadVirtualMemory Buffer failed - Status = %lx\n", Status );
RtlFreeHeap(CsrHeap,0,Buffer); LocalString->Buffer = NULL; // don't want caller to free this
return Status; }
LocalString->Buffer = Buffer; } }
return STATUS_SUCCESS; }
#if CSRSS_PROTECT_HANDLES
BOOLEAN ProtectHandle( HANDLE hObject ) { NTSTATUS Status; OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
Status = NtQueryObject( hObject, ObjectHandleFlagInformation, &HandleInfo, sizeof( HandleInfo ), NULL ); if (NT_SUCCESS( Status )) { HandleInfo.ProtectFromClose = TRUE;
Status = NtSetInformationObject( hObject, ObjectHandleFlagInformation, &HandleInfo, sizeof( HandleInfo ) ); if (NT_SUCCESS( Status )) { return TRUE; } }
return FALSE; }
BOOLEAN UnProtectHandle( HANDLE hObject ) { NTSTATUS Status; OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
Status = NtQueryObject( hObject, ObjectHandleFlagInformation, &HandleInfo, sizeof( HandleInfo ), NULL ); if (NT_SUCCESS( Status )) { HandleInfo.ProtectFromClose = FALSE;
Status = NtSetInformationObject( hObject, ObjectHandleFlagInformation, &HandleInfo, sizeof( HandleInfo ) ); if (NT_SUCCESS( Status )) { return TRUE; } }
return FALSE; } #endif // CSRSS_PROTECT_HANDLES
|