462 lines
12 KiB
C
462 lines
12 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|