559 lines
16 KiB
C
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;
|
|
}
|