windows-nt/Source/XPSP1/NT/base/win32/server/srvtask.c

462 lines
12 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
srvtask.c
Abstract:
This module implements windows server tasking functions
Author:
Mark Lucovsky (markl) 13-Nov-1990
Revision History:
--*/
#include "basesrv.h"
#if defined(_WIN64)
#include <wow64t.h>
#endif // defined(_WIN64)
PFNNOTIFYPROCESSCREATE UserNotifyProcessCreate = NULL;
void
BaseSetProcessCreateNotify(
IN PFNNOTIFYPROCESSCREATE ProcessCreateRoutine
)
{
UserNotifyProcessCreate = ProcessCreateRoutine;
}
ULONG
BaseSrvCreateProcess(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status, Status1;
PBASE_CREATEPROCESS_MSG a = (PBASE_CREATEPROCESS_MSG)&m->u.ApiMessageData;
HANDLE CsrClientProcess = NULL;
HANDLE NewProcess = NULL;
HANDLE Thread = NULL;
PCSR_THREAD t;
ULONG DebugFlags;
DWORD dwFlags;
PCSR_PROCESS ProcessVDM;
#if defined(_WIN64)
PPEB32 Peb32 = NULL;
#endif // defined(_WIN64)
PPEB NewPeb = NULL;
USHORT ProcessorArchitecture = a->ProcessorArchitecture;
t = CSR_SERVER_QUERYCLIENTTHREAD();
CsrClientProcess = t->Process->ProcessHandle;
#if defined(_WIN64)
if (ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
#endif // defined(_WIN64)
//
// Get handles to the process and thread local to the
// Windows server.
//
if ((dwFlags = (DWORD)((ULONG_PTR)a->ProcessHandle) & 3)) {
a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle & ~3);
}
Status = NtDuplicateObject(
CsrClientProcess,
a->ProcessHandle,
NtCurrentProcess(),
&NewProcess,
0L,
0L,
DUPLICATE_SAME_ACCESS
);
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
Status = NtDuplicateObject(
CsrClientProcess,
a->ThreadHandle,
NtCurrentProcess(),
&Thread,
0L,
0L,
DUPLICATE_SAME_ACCESS
);
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
{
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
Status =
NtQueryInformationProcess(
NewProcess,
ProcessBasicInformation,
&ProcessBasicInfo,
sizeof(ProcessBasicInfo),
NULL);
if (!NT_SUCCESS(Status)) {
DbgPrintEx(
DPFLTR_SXS_ID,
DPFLTR_ERROR_LEVEL,
"SXS: NtQueryInformationProcess failed.\n", Status);
goto Cleanup;
}
NewPeb = ProcessBasicInfo.PebBaseAddress;
}
if ((a->CreationFlags & CREATE_IGNORE_SYSTEM_DEFAULT) == 0) {
Status = BaseSrvSxsDoSystemDefaultActivationContext(ProcessorArchitecture, NewProcess, NewPeb);
if ((!NT_SUCCESS(Status)) && (Status != STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY)) {
goto Cleanup;
}
}
Status = BaseSrvSxsCreateProcess(CsrClientProcess, NewProcess, m, NewPeb);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
DebugFlags = 0;
if ( a->CreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) ) {
if ( a->CreationFlags & DEBUG_PROCESS ) {
DebugFlags |= CSR_DEBUG_PROCESS_TREE;
}
if ( a->CreationFlags & DEBUG_ONLY_THIS_PROCESS ) {
DebugFlags |= CSR_DEBUG_THIS_PROCESS;
}
}
if ( a->CreationFlags & CREATE_NEW_PROCESS_GROUP ) {
DebugFlags |= CSR_CREATE_PROCESS_GROUP;
}
if ( !(dwFlags & 2) ) {
DebugFlags |= CSR_PROCESS_CONSOLEAPP;
}
Status = CsrCreateProcess(
NewProcess,
Thread,
&a->ClientId,
t->Process->NtSession,
DebugFlags,
NULL
);
switch(Status) {
case STATUS_THREAD_IS_TERMINATING:
if (a->VdmBinaryType )
BaseSrvVDMTerminated (a->hVDM, a->VdmTask);
*ReplyStatus = CsrClientDied;
goto Cleanup;
case STATUS_SUCCESS:
//
// notify USER that a process is being created. USER needs to know
// for various synchronization issues such as startup activation,
// startup synchronization, and type ahead.
//
// Turn on 0x8 bit of dwFlags if this is a WOW process being
// created so that UserSrv knows to ignore the console's call
// to UserNotifyConsoleApplication.
//
if (IS_WOW_BINARY(a->VdmBinaryType)) {
dwFlags |= 8;
}
if (UserNotifyProcessCreate != NULL) {
if (!(*UserNotifyProcessCreate)((DWORD)((ULONG_PTR)a->ClientId.UniqueProcess),
(DWORD)((ULONG_PTR)t->ClientId.UniqueThread),
0, dwFlags)) {
//
// FIX, FIX - error cleanup. Shouldn't we close the duplicated
// process and thread handles above?
//
}
}
//
// Update the VDM sequence number.
//
if (a->VdmBinaryType) {
Status = BaseSrvUpdateVDMSequenceNumber(a->VdmBinaryType,
a->hVDM,
a->VdmTask,
a->ClientId.UniqueProcess);
if (!NT_SUCCESS( Status )) {
//
// FIX, FIX - error cleanup. Shouldn't we close the
// duplicated process and thread handles above?
//
BaseSrvVDMTerminated (a->hVDM, a->VdmTask);
}
}
break;
default:
goto Cleanup;
}
// We don't use the usual Exit: pattern here in order to more carefully
// preserve the preexisting behavior, which apparently leaks handles in error cases.
return( (ULONG)Status );
Cleanup:
if (NewProcess != NULL) {
Status1 = NtClose(NewProcess);
RTL_SOFT_ASSERT(NT_SUCCESS(Status1));
}
if (Thread != NULL) {
Status1 = NtClose(Thread);
RTL_SOFT_ASSERT(NT_SUCCESS(Status1));
}
return( (ULONG)Status );
}
ULONG
BaseSrvCreateThread(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_CREATETHREAD_MSG a = (PBASE_CREATETHREAD_MSG)&m->u.ApiMessageData;
HANDLE Thread;
NTSTATUS Status;
PCSR_PROCESS Process;
PCSR_THREAD t;
t = CSR_SERVER_QUERYCLIENTTHREAD();
Process = t->Process;
if (Process->ClientId.UniqueProcess != a->ClientId.UniqueProcess) {
if ( a->ClientId.UniqueProcess == NtCurrentTeb()->ClientId.UniqueProcess ) {
return STATUS_SUCCESS;
}
Status = CsrLockProcessByClientId( a->ClientId.UniqueProcess,
&Process
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
}
//
// Get handles to the thread local to the
// Windows server.
//
Status = NtDuplicateObject(
t->Process->ProcessHandle,
a->ThreadHandle,
NtCurrentProcess(),
&Thread,
0L,
0L,
DUPLICATE_SAME_ACCESS
);
if ( NT_SUCCESS(Status) ) {
Status = CsrCreateThread(
Process,
Thread,
&a->ClientId,
TRUE
);
if (!NT_SUCCESS(Status)) {
NtClose(Thread);
}
}
if (Process != t->Process) {
CsrUnlockProcess( Process );
}
return( (ULONG)Status );
ReplyStatus; // get rid of unreferenced parameter warning message
}
ULONG
BaseSrvRegisterThread(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_CREATETHREAD_MSG a = (PBASE_CREATETHREAD_MSG)&m->u.ApiMessageData;
HANDLE Thread;
NTSTATUS Status;
PCSR_PROCESS Process;
PCSR_THREAD CsrThread, ExistingThread;
OBJECT_ATTRIBUTES NullAttributes;
//
// We assume the following:
//
// We are called via a LPC_DATAGRAM since this is the only way
// that CSR will let the call go through. (csr requires
// LPC_REQUEST to be sent only by threads in its list). This
// means that CSR_SERVER_QUERYCLIENTTHREAD(); does not return a
// valid value.
Status = CsrLockProcessByClientId( a->ClientId.UniqueProcess,
&Process
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
//
// Get handle to the thread local to the
// Windows server. Since this is called as a
// LPC_DATAGRAM message, the thread handle is
// not passed in the message, but instead the
// calling thread is opened
//
InitializeObjectAttributes( &NullAttributes, NULL, 0, NULL, NULL );
Status = NtOpenThread(&Thread,
THREAD_ALL_ACCESS,
&NullAttributes,
&a->ClientId);
if ( NT_SUCCESS(Status) ) {
Status = CsrCreateThread(
Process,
Thread,
&a->ClientId,
FALSE
);
if (!NT_SUCCESS(Status)) {
NtClose(Thread);
}
}
CsrUnlockProcess( Process );
return( (ULONG)Status );
ReplyStatus; // get rid of unreferenced parameter warning message
}
EXCEPTION_DISPOSITION
FatalExceptionFilter(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
DbgPrint("CSRSRV: Fatal Server Side Exception. Exception Info %lx\n",
ExceptionInfo
);
DbgBreakPoint();
return EXCEPTION_EXECUTE_HANDLER;
}
ULONG
BaseSrvExitProcess(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_EXITPROCESS_MSG a = (PBASE_EXITPROCESS_MSG)&m->u.ApiMessageData;
PCSR_THREAD t;
ULONG rc = (ULONG)STATUS_ACCESS_DENIED;
t = CSR_SERVER_QUERYCLIENTTHREAD();
try {
*ReplyStatus = CsrClientDied;
rc = (ULONG)CsrDestroyProcess( &t->ClientId, (NTSTATUS)a->uExitCode );
}
except(FatalExceptionFilter( GetExceptionInformation() )) {
DbgBreakPoint();
}
return rc;
}
ULONG
BaseSrvGetTempFile(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_GETTEMPFILE_MSG a = (PBASE_GETTEMPFILE_MSG)&m->u.ApiMessageData;
BaseSrvGetTempFileUnique++;
a->uUnique = BaseSrvGetTempFileUnique;
return( (ULONG)a->uUnique & 0xffff );
ReplyStatus; // get rid of unreferenced parameter warning message
}
ULONG
BaseSrvDebugProcess(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
return STATUS_UNSUCCESSFUL;
}
ULONG
BaseSrvDebugProcessStop(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
return STATUS_UNSUCCESSFUL;
}
ULONG
BaseSrvSetProcessShutdownParam(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PCSR_PROCESS p;
PBASE_SHUTDOWNPARAM_MSG a = (PBASE_SHUTDOWNPARAM_MSG)&m->u.ApiMessageData;
p = CSR_SERVER_QUERYCLIENTTHREAD()->Process;
if (a->ShutdownFlags & (~(SHUTDOWN_NORETRY))) {
return !STATUS_SUCCESS;
}
p->ShutdownLevel = a->ShutdownLevel;
p->ShutdownFlags = a->ShutdownFlags;
return STATUS_SUCCESS;
ReplyStatus;
}
ULONG
BaseSrvGetProcessShutdownParam(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PCSR_PROCESS p;
PBASE_SHUTDOWNPARAM_MSG a = (PBASE_SHUTDOWNPARAM_MSG)&m->u.ApiMessageData;
p = CSR_SERVER_QUERYCLIENTTHREAD()->Process;
a->ShutdownLevel = p->ShutdownLevel;
a->ShutdownFlags = p->ShutdownFlags & SHUTDOWN_NORETRY;
return STATUS_SUCCESS;
ReplyStatus;
}