NT4/private/windows/base/server/srvtask.c
2020-09-30 17:12:29 +02:00

559 lines
16 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"
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;
PBASE_CREATEPROCESS_MSG a = (PBASE_CREATEPROCESS_MSG)&m->u.ApiMessageData;
HANDLE Process, Thread;
PCSR_THREAD t;
ULONG DebugFlags;
PCLIENT_ID DebugUserInterface;
DWORD dwFlags;
PCSR_PROCESS ProcessVDM;
t = CSR_SERVER_QUERYCLIENTTHREAD();
//
// Get handles to the process and thread local to the
// Windows server.
//
if (dwFlags = ((DWORD)a->ProcessHandle) & 3) {
a->ProcessHandle = (HANDLE)((DWORD)a->ProcessHandle & ~3);
}
Status = NtDuplicateObject(
t->Process->ProcessHandle,
a->ProcessHandle,
NtCurrentProcess(),
&Process,
0L,
0L,
DUPLICATE_SAME_ACCESS
);
if ( !NT_SUCCESS(Status) ) {
return( (ULONG)Status );
}
Status = NtDuplicateObject(
t->Process->ProcessHandle,
a->ThreadHandle,
NtCurrentProcess(),
&Thread,
0L,
0L,
DUPLICATE_SAME_ACCESS
);
if ( !NT_SUCCESS(Status) ) {
//
// FIX, FIX - error cleanup
//
NtClose(Process);
return( (ULONG)Status );
}
DebugUserInterface = NULL;
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;
}
DebugUserInterface = &a->DebuggerClientId;
}
if ( a->CreationFlags & CREATE_NEW_PROCESS_GROUP ) {
DebugFlags |= CSR_CREATE_PROCESS_GROUP;
}
if ( a->CreationFlags & NORMAL_PRIORITY_CLASS ) {
DebugFlags |= CSR_NORMAL_PRIORITY_CLASS;
}
else if ( a->CreationFlags & IDLE_PRIORITY_CLASS ) {
DebugFlags |= CSR_IDLE_PRIORITY_CLASS;
}
else if ( a->CreationFlags & HIGH_PRIORITY_CLASS ) {
DebugFlags |= CSR_HIGH_PRIORITY_CLASS;
}
else if ( a->CreationFlags & REALTIME_PRIORITY_CLASS ) {
DebugFlags |= CSR_REALTIME_PRIORITY_CLASS;
}
else {
//
// No class specified. If current process is idle class, then
// new process is idle. Otherwise, new process is normal.
//
if ( CsrComputePriorityClass(t->Process) == CSR_IDLE_PRIORITY_CLASS ) {
DebugFlags |= CSR_IDLE_PRIORITY_CLASS;
}
else {
DebugFlags |= CSR_NORMAL_PRIORITY_CLASS;
}
}
if ( !(dwFlags & 2) ) {
DebugFlags |= CSR_PROCESS_CONSOLEAPP;
}
Status = CsrCreateProcess(
Process,
Thread,
&a->ClientId,
t->Process->NtSession,
DebugFlags,
DebugUserInterface
);
switch(Status) {
case STATUS_THREAD_IS_TERMINATING:
if (a->IsVDM && !(a->CreationFlags & CREATE_SEPARATE_WOW_VDM))
BaseSrvVDMTerminated (a->hVDM, a->IsVDM);
*ReplyStatus = CsrClientDied;
break;
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 (a->IsVDM && a->hVDM == (HANDLE)-1)
dwFlags |= 8;
if (UserNotifyProcessCreate != NULL) {
if (!(*UserNotifyProcessCreate)((DWORD)a->ClientId.UniqueProcess,
(DWORD)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. Note BaseSrv doesn't keep track
// of separate WOW VDMs.
//
if (a->IsVDM && !(a->CreationFlags & CREATE_SEPARATE_WOW_VDM)){
Status = CsrLockProcessByClientId( a->ClientId.UniqueProcess,
&ProcessVDM
);
if (!NT_SUCCESS( Status )) {
//
// FIX, FIX - error cleanup. Shouldn't we close the
// duplicated process and thread handles above?
//
BaseSrvVDMTerminated (a->hVDM, a->IsVDM);
break;
}
ProcessVDM->fVDM = TRUE;
BaseSrvUpdateVDMSequenceNumber (a->hVDM,
ProcessVDM->SequenceNumber,
a->IsVDM
);
CsrUnlockProcess(ProcessVDM);
}
break;
}
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
);
}
if (Process != t->Process) {
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;
t = CSR_SERVER_QUERYCLIENTTHREAD();
try {
*ReplyStatus = CsrClientDied;
return( (ULONG)CsrDestroyProcess( &t->ClientId, (NTSTATUS)a->uExitCode ) );
}
except(FatalExceptionFilter( GetExceptionInformation() )) {
DbgBreakPoint();
}
}
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
}
typedef
NTSTATUS
(*PCREATE_REMOTE_THREAD)(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
ULONG
BaseSrvDebugProcess(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_DEBUGPROCESS_MSG a = (PBASE_DEBUGPROCESS_MSG)&m->u.ApiMessageData;
HANDLE Thread,ProcessHandle,Token;
PCSR_PROCESS Process;
DWORD ThreadId;
PTOKEN_DEFAULT_DACL lpDefaultDacl;
TOKEN_DEFAULT_DACL DefaultDacl;
ULONG DaclLength;
SECURITY_ATTRIBUTES ThreadAttributes;
SECURITY_DESCRIPTOR SecurityDescriptor;
UNICODE_STRING ModuleNameString_U;
PVOID ModuleHandle;
STRING ProcedureNameString;
PCREATE_REMOTE_THREAD CreateRemoteThreadRoutine;
if (a->dwProcessId == -1 && a->AttachCompleteRoutine == NULL) {
HANDLE DebugPort;
DebugPort = (HANDLE)NULL;
Status = NtQueryInformationProcess(
NtCurrentProcess(),
ProcessDebugPort,
(PVOID)&DebugPort,
sizeof(DebugPort),
NULL
);
if ( NT_SUCCESS(Status) && DebugPort ) {
return (ULONG)STATUS_ACCESS_DENIED;
}
return STATUS_SUCCESS;
}
#if DEVL
if (a->dwProcessId != -1) {
#endif // DEVL
if ( a->AttachCompleteRoutine == NULL ) {
Status = CsrLockProcessByClientId((HANDLE)a->dwProcessId,&Process);
if ( NT_SUCCESS(Status) ) {
ProcessHandle = Process->ProcessHandle;
Status = NtOpenProcessToken(ProcessHandle,
TOKEN_QUERY,
&Token
);
if ( !NT_SUCCESS(Status) ) {
CsrUnlockProcess(Process);
return Status;
}
lpDefaultDacl = &DefaultDacl;
Status = NtQueryInformationToken(Token,
TokenDefaultDacl,
lpDefaultDacl,
sizeof(DefaultDacl),
&DaclLength
);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
Status = STATUS_ACCESS_DENIED;
}
else {
Status = STATUS_SUCCESS;
}
if ( Process->DebugUserInterface.UniqueProcess ||
Process->DebugUserInterface.UniqueThread ) {
Status = STATUS_ACCESS_DENIED;
}
NtClose(Token);
CsrUnlockProcess(Process);
}
return (ULONG)Status;
}
//
// Can't call base, but I know it is there
//
RtlInitUnicodeString( &ModuleNameString_U, L"kernel32" );
Status = LdrLoadDll( UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle );
if ( !NT_SUCCESS(Status) ) {
return (ULONG)Status;
}
RtlInitString( &ProcedureNameString, "CreateRemoteThread" );
Status = LdrGetProcedureAddress( ModuleHandle,
&ProcedureNameString,
(ULONG) NULL,
(PVOID *) &CreateRemoteThreadRoutine
);
if ( !NT_SUCCESS(Status) ) {
LdrUnloadDll( ModuleHandle );
return (ULONG)Status;
}
Status = CsrLockProcessByClientId((HANDLE)a->dwProcessId,&Process);
if ( NT_SUCCESS(Status) ) {
ProcessHandle = Process->ProcessHandle;
Status = NtOpenProcessToken(ProcessHandle,
TOKEN_QUERY,
&Token
);
if (!NT_SUCCESS(Status)) {
CsrUnlockProcess(Process);
LdrUnloadDll( ModuleHandle );
return (ULONG)Status;
}
lpDefaultDacl = &DefaultDacl;
Status = NtQueryInformationToken(Token,
TokenDefaultDacl,
lpDefaultDacl,
sizeof(DefaultDacl),
&DaclLength
);
if (!NT_SUCCESS(Status)) {
lpDefaultDacl = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DaclLength);
if (lpDefaultDacl) {
Status = NtQueryInformationToken(Token,
TokenDefaultDacl,
lpDefaultDacl,
DaclLength,
&DaclLength
);
}
else {
Status = STATUS_NO_MEMORY;
}
NtClose(Token);
if (!NT_SUCCESS(Status)) {
CsrUnlockProcess(Process);
LdrUnloadDll( ModuleHandle );
return (ULONG)Status;
}
}
else {
NtClose(Token);
}
ThreadAttributes.nLength = sizeof(ThreadAttributes);
RtlCreateSecurityDescriptor(&SecurityDescriptor,SECURITY_DESCRIPTOR_REVISION1);
ThreadAttributes.lpSecurityDescriptor = &SecurityDescriptor;
SecurityDescriptor.Control = SE_DACL_PRESENT;
SecurityDescriptor.Dacl = lpDefaultDacl->DefaultDacl;
ThreadAttributes.bInheritHandle = FALSE;
CsrUnlockProcess(Process);
}
#if DEVL
}
#endif // DEVL
//
// Set up the specified user-interface as the debugger of the
// target process. Whip through the target process and
// suspend all threads. Then Send CreateProcess, LoadModule, and
// CreateThread Messages. Finally send the attach complete
// exception.
//
Status = CsrDebugProcess(
a->dwProcessId,
&a->DebuggerClientId,
(PCSR_ATTACH_COMPLETE_ROUTINE)a->AttachCompleteRoutine
);
#if DEVL
if (a->dwProcessId != -1) {
#endif // DEVL
if ( NT_SUCCESS(Status) ) {
Thread = (PVOID)(CreateRemoteThreadRoutine)(ProcessHandle,
&ThreadAttributes,
0L,
(LPTHREAD_START_ROUTINE)a->AttachCompleteRoutine,
0,
0,
&ThreadId
);
LdrUnloadDll( ModuleHandle );
if ( lpDefaultDacl != &DefaultDacl ) {
RtlFreeHeap(RtlProcessHeap(), 0,lpDefaultDacl);
}
if ( !Thread ) {
return (ULONG)STATUS_UNSUCCESSFUL;
}
NtClose(Thread);
}
#if DEVL
}
#endif // DEVL
return (ULONG) Status;
}
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;
}