mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
789 lines
19 KiB
789 lines
19 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: rcmdsrv.c
|
|
*
|
|
* Copyright (c) 1991, Microsoft Corporation
|
|
*
|
|
* Remote shell server main module
|
|
*
|
|
* History:
|
|
* 06-29-92 Davidc Created.
|
|
* 05-05-94 DaveTh Modified for RCMD service.
|
|
\***************************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <windef.h>
|
|
#include <nturtl.h>
|
|
#include <winbase.h>
|
|
|
|
#include "rcmdsrv.h"
|
|
|
|
#define PIPE_NAME TEXT("\\\\.\\pipe\\rcmdsvc")
|
|
|
|
#define REQUIRED_SYSTEM_ACCESS POLICY_MODE_INTERACTIVE
|
|
|
|
//
|
|
// Define pipe timeout (ms)
|
|
// Only used by WaitNamedPipe
|
|
//
|
|
|
|
#define PIPE_TIMEOUT 1000
|
|
|
|
//
|
|
// Session count semaphore and wait array - limits number of active sessions.
|
|
//
|
|
|
|
#define RCMD_STOP_EVENT 0
|
|
#define PIPE_CONNECTED_EVENT 1
|
|
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
DWORD
|
|
GetCommandHeader (
|
|
HANDLE PipeHandle,
|
|
PCOMMAND_HEADER LpCommandHeader
|
|
);
|
|
|
|
DWORD
|
|
SendResponseHeader (
|
|
HANDLE PipeHandle,
|
|
PRESPONSE_HEADER LpResponseHeader
|
|
);
|
|
|
|
HANDLE
|
|
GetClientToken (
|
|
HANDLE PipeHandle
|
|
);
|
|
|
|
|
|
//
|
|
// Stop service function. Signals global stop event. Rcmd will wait
|
|
// for session threads to wind down.
|
|
//
|
|
|
|
DWORD
|
|
RcmdStop ( )
|
|
{
|
|
|
|
DWORD Result;
|
|
|
|
//
|
|
// Signal threads and session create loop to stop with global stop event.
|
|
//
|
|
|
|
if (!SetEvent( RcmdStopEvent )) {
|
|
Result = GetLastError();
|
|
RcDbgPrint ("Failure setting stop event, %d\n", Result);
|
|
return(Result);
|
|
}
|
|
|
|
if (WaitForSingleObject(RcmdStopCompleteEvent, INFINITE) == WAIT_FAILED) {
|
|
return(GetLastError());
|
|
|
|
} else {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Remote command service main routine - returns when all session threads have
|
|
// exited and cleanup is complete
|
|
//
|
|
|
|
int
|
|
Rcmd ( )
|
|
|
|
{
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
HANDLE SessionHandle = NULL;
|
|
HANDLE TokenToUse;
|
|
COMMAND_HEADER CommandHeader;
|
|
RESPONSE_HEADER ResponseHeader;
|
|
DWORD WaitResult;
|
|
BOOL Result;
|
|
NTSTATUS NtStatus;
|
|
BOOLEAN WasEnabled;
|
|
DWORD SessionNumber;
|
|
ULONG i;
|
|
OVERLAPPED PipeConnectOverlapped;
|
|
HANDLE PipeConnectEvent;
|
|
HANDLE PipeConnectWaitList[2];
|
|
BOOLEAN UserHasAccess;
|
|
|
|
|
|
//
|
|
// Create a console for the service process to get stdin, ctl-c support
|
|
//
|
|
|
|
if (!AllocConsole()) {
|
|
RcDbgPrint("Failed to allocate console, error = %d\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
//
|
|
// Set process privileges so that the DACL on the process token can later
|
|
// be modified.
|
|
//
|
|
|
|
NtStatus = RtlAdjustPrivilege(
|
|
SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
|
|
TRUE, // enable privilege.
|
|
FALSE, // for process, not just client token
|
|
&WasEnabled );
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
RcDbgPrint("Adjust process token failed, error = %lx.\n", NtStatus);
|
|
return(1);
|
|
}
|
|
|
|
//
|
|
// Setup the security descriptor to put on the named pipe.
|
|
// BUGBUG - Set access to client or system, not WORLD
|
|
//
|
|
|
|
Result = InitializeSecurityDescriptor(
|
|
&SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
if (!Result) {
|
|
RcDbgPrint("Init named pipe DACL security descriptor failed, error = %d\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
Result = SetSecurityDescriptorDacl(
|
|
&SecurityDescriptor,
|
|
TRUE,
|
|
NULL,
|
|
FALSE);
|
|
|
|
if (!Result) {
|
|
RcDbgPrint("Init named pipe DACL security descriptor failed, error = %d\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
SecurityAttributes.nLength = sizeof(SecurityAttributes);
|
|
SecurityAttributes.lpSecurityDescriptor = &SecurityDescriptor;
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
|
|
//
|
|
// SessionThreadHandles is the table of session thread handles on
|
|
// which to wait for session completion. Entry[0] is an exception.
|
|
// It is the handle to the global service stop event.
|
|
//
|
|
|
|
for (i=0; i <= MAX_SESSIONS; i++ ) {
|
|
SessionThreadHandles[i] = NULL;
|
|
}
|
|
|
|
SessionThreadHandles[RCMD_STOP_EVENT] = RcmdStopEvent;
|
|
|
|
//
|
|
// Initialize pipe connect handle list - wait for client pipe
|
|
// connection or stop event
|
|
//
|
|
|
|
PipeConnectWaitList[RCMD_STOP_EVENT] = RcmdStopEvent;
|
|
|
|
if ((PipeConnectEvent = CreateEvent (
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL )) == NULL) {
|
|
|
|
RcDbgPrint("Create connect pipe event failed, error = %d\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
PipeConnectWaitList[PIPE_CONNECTED_EVENT] = PipeConnectEvent;
|
|
|
|
//
|
|
// Initialize overlapped structure - only one connect pending at a time
|
|
//
|
|
|
|
PipeConnectOverlapped.hEvent = PipeConnectEvent;
|
|
PipeConnectOverlapped.Internal = 0;
|
|
PipeConnectOverlapped.InternalHigh = 0;
|
|
PipeConnectOverlapped.Offset =0;
|
|
PipeConnectOverlapped.OffsetHigh =0;
|
|
|
|
|
|
//
|
|
// Loop waiting for a client to connect. When client connects,
|
|
// impersonate to obtain client token, then create client session
|
|
// thread, pipes and command proces. Return to top of loop,
|
|
// create another named pipe and wait for the next client. If
|
|
// stop event is signalled, exit loop with break.
|
|
//
|
|
|
|
while (TRUE) {
|
|
|
|
HANDLE ConnectHandle;
|
|
HANDLE PipeHandle;
|
|
|
|
//
|
|
// Find first available session - if none available, wait for
|
|
// a thread handle to be signalled (session thread exit). Close
|
|
// the handle, mark the entry non-active, and create the session.
|
|
// If the stop event is signalled, break out.
|
|
//
|
|
|
|
SessionNumber = 1;
|
|
while ((SessionNumber <= MAX_SESSIONS) &&
|
|
(SessionThreadHandles[SessionNumber] != NULL)) {
|
|
SessionNumber++;
|
|
}
|
|
|
|
if (SessionNumber > MAX_SESSIONS) {
|
|
|
|
//
|
|
// No unused sessions - wait for one to finish (exit)
|
|
// Also, wait for the service stop event
|
|
//
|
|
|
|
Result = WaitForMultipleObjects (
|
|
MAX_SESSIONS+1,
|
|
SessionThreadHandles,
|
|
FALSE,
|
|
INFINITE);
|
|
|
|
if (Result == (WAIT_OBJECT_0 + RCMD_STOP_EVENT)) {
|
|
break; // service stopping - exit connect loop
|
|
|
|
//
|
|
// Session done - mark as available and close thread handle
|
|
//
|
|
|
|
} else if ((Result > (WAIT_OBJECT_0 + RCMD_STOP_EVENT)) &&
|
|
(Result <= (WAIT_OBJECT_0 + MAX_SESSIONS))) {
|
|
SessionNumber = Result - WAIT_OBJECT_0;
|
|
if (!CloseHandle(SessionThreadHandles[SessionNumber])) {
|
|
RcDbgPrint("Sesssion thread close, error = %d\n", GetLastError());
|
|
break; // critical error - exit connect loop
|
|
}
|
|
SessionThreadHandles[SessionNumber] = NULL;
|
|
|
|
} else {
|
|
RcDbgPrint("Sesssion thread table wait failed, error = %d\n", GetLastError());
|
|
break; // critical error - exit connect loop
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create an instance of the named pipe
|
|
//
|
|
|
|
PipeHandle = CreateNamedPipe(PIPE_NAME,
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_BYTE | PIPE_WAIT,
|
|
MAX_SESSIONS, // Number of pipes
|
|
0, // Default out buffer size
|
|
0, // Default in buffer size
|
|
PIPE_TIMEOUT, // Timeout in ms
|
|
&SecurityAttributes
|
|
);
|
|
|
|
if (PipeHandle == INVALID_HANDLE_VALUE ) {
|
|
RcDbgPrint("Failed to create named pipe instance, error = %d\n", GetLastError());
|
|
break; // critical error - exit connect loop
|
|
}
|
|
|
|
|
|
//
|
|
// Wait for a client to connect. If stop event is signalled, break
|
|
// out of loop.
|
|
//
|
|
// Pipe connect is async - should never be true
|
|
//
|
|
|
|
assert (!ConnectNamedPipe(PipeHandle, &PipeConnectOverlapped));
|
|
|
|
Result = GetLastError();
|
|
|
|
if (Result == ERROR_PIPE_CONNECTED) {
|
|
//
|
|
// Already conncted (between create and connect) - go
|
|
// setup session
|
|
//
|
|
|
|
} else if (Result == ERROR_IO_PENDING) {
|
|
|
|
//
|
|
// Waiting for connect or service stop event
|
|
//
|
|
|
|
Result = WaitForMultipleObjects(
|
|
2,
|
|
PipeConnectWaitList,
|
|
FALSE,
|
|
INFINITE);
|
|
|
|
if (Result == (WAIT_OBJECT_0+RCMD_STOP_EVENT)) {
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; //stopping - exit connect loop
|
|
|
|
} else if (Result == (WAIT_OBJECT_0+PIPE_CONNECTED_EVENT)) {
|
|
|
|
//
|
|
// Connected - go setup the session
|
|
//
|
|
|
|
} else {
|
|
RcDbgPrint("Connect wait failed, error = %d\n", GetLastError());
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical error - exit connect loop
|
|
}
|
|
|
|
} else {
|
|
|
|
RcDbgPrint("Connect named pipe failed, error = %d\n", GetLastError());
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical error - exit connect loop
|
|
}
|
|
|
|
//
|
|
// Now connected - Get command header. Client failures that occur
|
|
// are "non-critical" and result in disconnection, sending a response
|
|
// to the client (when appropriate) and resuming the loop for the
|
|
// next client.
|
|
//
|
|
|
|
Result = GetCommandHeader(PipeHandle, &CommandHeader);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// If failure, just disconnect, since we couldn't even read
|
|
// the header.
|
|
//
|
|
|
|
RcDbgPrint("Command header read read failed, error = %d\n", Result);
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
continue; // client failure - return to connect loop
|
|
}
|
|
|
|
//
|
|
// Get client's token and save for the spawned session command
|
|
// process. Should only be local failures in this case since
|
|
// the client had to logon and get a token to get this far.
|
|
//
|
|
|
|
TokenToUse = GetClientToken (PipeHandle);
|
|
|
|
if (TokenToUse == NULL) {
|
|
RcDbgPrint ("Client token failure\n");
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical failure - exit connect loop
|
|
}
|
|
|
|
//
|
|
// Check to see if user has adequate system access.
|
|
//
|
|
|
|
if ((Result = CheckUserSystemAccess(
|
|
TokenToUse,
|
|
REQUIRED_SYSTEM_ACCESS,
|
|
&UserHasAccess)) != ERROR_SUCCESS) {
|
|
|
|
RcDbgPrint("System access check failure, error = %d\n",Result);
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical failure - exit connect loop
|
|
}
|
|
|
|
if (!UserHasAccess) {
|
|
|
|
//
|
|
// Client has insufficient access - send response indicating
|
|
// the error, disconnect and go round for next one
|
|
//
|
|
|
|
ResponseHeader.SupportedLevel =
|
|
(RC_ERROR_RESPONSE | ERROR_ACCESS_DENIED);
|
|
|
|
Result = SendResponseHeader(PipeHandle, &ResponseHeader);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
RcDbgPrint("Error sending response, error = %d\n", Result);
|
|
}
|
|
|
|
RcDbgPrint("Client has insufficient access\n");
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
continue; // client failure - return to connect loop
|
|
|
|
} else {
|
|
|
|
//
|
|
// Client does have sufficient access - determine level
|
|
// of functionality that will be supported and send response.
|
|
//
|
|
// Currently, only BASIC level is supported (so no determination
|
|
// is made - Requested level is ignored, BASIC always returned);
|
|
//
|
|
|
|
ResponseHeader.SupportedLevel = (RC_LEVEL_RESPONSE | RC_LEVEL_BASIC);
|
|
|
|
Result = SendResponseHeader(PipeHandle, &ResponseHeader);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
RcDbgPrint("Error response send failed, error = %d\n", Result);
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
continue; // client failure - return to connect loop
|
|
}
|
|
}
|
|
|
|
RcDbgPrint("Client connected\n");
|
|
|
|
//
|
|
// Create a new session
|
|
//
|
|
|
|
SessionHandle = CreateSession(
|
|
TokenToUse,
|
|
&CommandHeader);
|
|
|
|
if (SessionHandle == NULL) {
|
|
RcDbgPrint("Failed to create session\n");
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical error - exit connect loop
|
|
}
|
|
|
|
//
|
|
// Connect the pipe to our session. Connect session will start
|
|
// and run the session on it's own thread. The session thread
|
|
// will clean up the session state and close the connected pipe
|
|
// before exitting. The connect handle is the session thread
|
|
// handle, signalled when the session thread exits.
|
|
//
|
|
|
|
ConnectHandle = ConnectSession(SessionHandle, PipeHandle);
|
|
if (ConnectHandle == NULL) {
|
|
RcDbgPrint("Failed to connect session\n");
|
|
RcCloseHandle(PipeHandle, "client pipe");
|
|
break; // critical error - exit connect loop
|
|
}
|
|
|
|
//
|
|
// Set session thread handle (signalled on session thread exit)
|
|
//
|
|
|
|
SessionThreadHandles[SessionNumber] = ConnectHandle;
|
|
|
|
|
|
} // End loop - go back and wait for next client to connect
|
|
|
|
//
|
|
// SHUTDOWN
|
|
//
|
|
// Signal shutdown event (will be set if from service stop - set it
|
|
// anyway to cover arrival here due to critical error). Wait for
|
|
// all threads to wind down. After completion, set stop-complete
|
|
// event to signal that service is stopped.
|
|
//
|
|
|
|
if (!SetEvent(RcmdStopEvent)) {
|
|
RcDbgPrint ("Failure setting stop-event, %d\n", GetLastError());
|
|
}
|
|
|
|
for (SessionNumber = 1; SessionNumber <= MAX_SESSIONS; SessionNumber++) {
|
|
if (SessionThreadHandles[SessionNumber] != NULL) {
|
|
|
|
WaitResult = WaitForSingleObject (
|
|
SessionThreadHandles[SessionNumber],
|
|
2000
|
|
);
|
|
|
|
if (WaitResult == WAIT_OBJECT_0) {
|
|
CloseHandle(SessionThreadHandles[SessionNumber]);
|
|
|
|
} else if (WaitResult == WAIT_TIMEOUT) {
|
|
RcDbgPrint ("Shutdown failure - timeout\n");
|
|
|
|
} else {
|
|
RcDbgPrint ("Shutdown wait failure, error %d\n", GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!SetEvent(RcmdStopCompleteEvent)) {
|
|
RcDbgPrint ("Failure setting stop-complete event, %d\n", GetLastError());
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: GetCommandHeader
|
|
*
|
|
* PURPOSE: Reads the command header from the specified pipe. Returns
|
|
* ERROR_SUCCESS on success or an error code on failure.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-01-92 DaveTh Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD
|
|
GetCommandHeader (
|
|
HANDLE PipeHandle,
|
|
PCOMMAND_HEADER LpCommandHeader
|
|
)
|
|
{
|
|
|
|
#define CMD_READ_TIMEOUT 10000
|
|
|
|
DWORD BytesRead;
|
|
DWORD Result;
|
|
|
|
//
|
|
// Read header - check for signature, and get command if there
|
|
// is one.
|
|
//
|
|
|
|
Result = ReadPipe (PipeHandle,
|
|
&(LpCommandHeader->CommandFixedHeader),
|
|
sizeof(COMMAND_FIXED_HEADER),
|
|
&BytesRead,
|
|
CMD_READ_TIMEOUT);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
RcDbgPrint("Header fixed part read failed, error = %d\n", Result);
|
|
return(Result);
|
|
}
|
|
|
|
if (LpCommandHeader->CommandFixedHeader.Signature != RCMD_SIGNATURE) {
|
|
RcDbgPrint("Header signature incorrect\n");
|
|
return (1);
|
|
}
|
|
|
|
if ((LpCommandHeader->CommandFixedHeader.CommandLength != 0)
|
|
& (LpCommandHeader->CommandFixedHeader.CommandLength <= MAX_CMD_LENGTH)) {
|
|
|
|
Result = ReadPipe (PipeHandle,
|
|
LpCommandHeader->Command,
|
|
LpCommandHeader->CommandFixedHeader.CommandLength,
|
|
&BytesRead,
|
|
CMD_READ_TIMEOUT);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
RcDbgPrint("Command part read failed, error = %d\n", Result);
|
|
return(1);
|
|
}
|
|
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: SendResponseHeader
|
|
*
|
|
* PURPOSE: Builds the rest of the header (inserts the signature) and sends
|
|
* a response header on the specified pipe. Returns
|
|
* ERROR_SUCCESS on success or an error code on failure.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-22-92 DaveTh Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD
|
|
SendResponseHeader (
|
|
HANDLE PipeHandle,
|
|
PRESPONSE_HEADER LpResponseHeader
|
|
)
|
|
{
|
|
|
|
#define RSP_WRITE_TIMEOUT 10000
|
|
|
|
DWORD BytesWritten;
|
|
DWORD Result;
|
|
|
|
//
|
|
// Set signature
|
|
//
|
|
|
|
LpResponseHeader->Signature = RCMD_SIGNATURE;
|
|
|
|
//
|
|
// Read header - check for signature, and get command if there
|
|
// is one.
|
|
//
|
|
|
|
Result = WritePipe (
|
|
PipeHandle,
|
|
LpResponseHeader,
|
|
sizeof (RESPONSE_HEADER),
|
|
&BytesWritten,
|
|
RSP_WRITE_TIMEOUT);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
RcDbgPrint("Response header write failed, error = %d\n", Result);
|
|
}
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: GetClientToken
|
|
*
|
|
* PURPOSE: Returns a handle to a copy of the client's token to be
|
|
* used for the spawned command process. Returns NULL on failure.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-01-92 DaveTh Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
HANDLE
|
|
GetClientToken (
|
|
HANDLE PipeHandle
|
|
)
|
|
|
|
{
|
|
BOOL Result;
|
|
NTSTATUS NtStatus;
|
|
HANDLE ClientToken, TokenToUse;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
if (!ImpersonateNamedPipeClient (PipeHandle)) {
|
|
RcDbgPrint("Impersonate named pipe failed, error = %d\n", GetLastError());
|
|
return(NULL);
|
|
|
|
} else {
|
|
|
|
if (!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_DUPLICATE |
|
|
TOKEN_ASSIGN_PRIMARY |
|
|
TOKEN_IMPERSONATE |
|
|
TOKEN_QUERY |
|
|
WRITE_DAC, // if fails, may need not open as self
|
|
TRUE,
|
|
&ClientToken)) {
|
|
RcDbgPrint("Open thread token failed, error = %d\n", GetLastError());
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
//
|
|
// Revert to service process context. Duplicate and save token
|
|
// for spawned command process
|
|
//
|
|
|
|
Result = RevertToSelf ();
|
|
if (!Result) {
|
|
RcDbgPrint("Reversion to service context failed, error = %d\n", GetLastError());
|
|
return(NULL);
|
|
}
|
|
|
|
NtStatus = NtDuplicateToken (
|
|
ClientToken,
|
|
0, //keep same access
|
|
NULL,
|
|
FALSE, //want all, not just effective
|
|
TokenPrimary,
|
|
&TokenToUse);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
RcDbgPrint("Duplicate token failed, error = %d\n", Result);
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Don't need client token anymore
|
|
//
|
|
|
|
if (!CloseHandle(ClientToken)) {
|
|
RcDbgPrint("Close client token failed, error %d\n", GetLastError());
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Set DACL on token to use to make it accessible by
|
|
// client being impersonated.
|
|
// BUGBUG - WORLD access for now
|
|
//
|
|
|
|
Result = InitializeSecurityDescriptor(
|
|
&SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
if (!Result) {
|
|
RcDbgPrint("Init token DACL security descriptor failed, error = %d\n", GetLastError());
|
|
return(NULL);
|
|
}
|
|
|
|
Result = SetSecurityDescriptorDacl(
|
|
&SecurityDescriptor,
|
|
TRUE,
|
|
NULL,
|
|
FALSE);
|
|
|
|
if (!Result) {
|
|
RcDbgPrint("Set token DACL security descriptor failed, error = %d\n", GetLastError());
|
|
return(NULL);
|
|
}
|
|
|
|
if (!SetKernelObjectSecurity(
|
|
TokenToUse,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SecurityDescriptor )) {
|
|
RcDbgPrint("Failed to set DACL on client token, error = %lx.\n", NtStatus);
|
|
return(NULL);
|
|
}
|
|
|
|
}
|
|
|
|
return(TokenToUse);
|
|
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: RcDbgPrint
|
|
*
|
|
* PURPOSE: DbgPrint enabled at runtime by setting RcDbgPrintEnable
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-17-92 DaveTh Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
int RcDbgPrint (
|
|
const char *format,
|
|
...
|
|
)
|
|
{
|
|
CHAR Buffer[MAX_PATH];
|
|
va_list argpointer;
|
|
|
|
if (RcDbgPrintEnable) {
|
|
|
|
va_start(argpointer, format);
|
|
assert (vsprintf(Buffer, format, argpointer) >= 0);
|
|
va_end(argpointer);
|
|
OutputDebugString(Buffer);
|
|
|
|
}
|
|
|
|
|
|
return(0);
|
|
}
|