|
|
/******************************************************************************\
* This is a part of the Microsoft Source Code Samples. * Copyright 1995 - 1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
SrvUtil.c
Abstract:
The server component of Remote. It spawns a child process and redirects the stdin/stdout/stderr of child to itself. Waits for connections from clients - passing the output of child process to client and the input from clients to child process.
Author:
Rajivendra Nath 2-Jan-1992 Dave Hart 30 May 1997 split from Server.c
Environment:
Console App. User mode.
Revision History:
--*/
#include <precomp.h>
#include "Remote.h"
#include "Server.h"
#include <sddl.h>
#define DEFAULT_SECURITY_DESCRIPTOR L"D:(A;;FA;;;BA)(A;;FA;;;CO)(A;;0x1301bf;;;WD)"
#define REGISTRY_PATH L"Software\\Microsoft\\Remote"
#define REGISTRY_VALUE L"DefaultSecurity"
#define COMMANDFORMAT "%c%-20s [%-12s %s]\n%08x%c"
#define CMDSTRING(OutBuff,OutSize,InpBuff,Client,szTime,ForceShow) \
{ \ char *pch; \ \ for (pch = InpBuff; \ *pch; \ pch++) { \ \ if (ENDMARK == *pch || \ BEGINMARK == *pch) { \ \ *pch = '`'; \ } \ } \ \ OutSize = \ sprintf( \ (OutBuff), \ COMMANDFORMAT, \ BEGINMARK, \ (InpBuff), \ (Client)->Name, \ (szTime), \ (ForceShow) ? 0 : (Client)->dwID, \ ENDMARK \ ); \ }
/*************************************************************/ // GetFormattedTime -- returns pointer to formatted time
//
// returns pointer to static buffer, only the main thread
// should use this.
//
PCHAR GetFormattedTime( BOOL bDateToo ) { static char szTime[64]; int cch = 0;
if (bDateToo) {
cch = GetDateFormat( LOCALE_USER_DEFAULT, 0, NULL, // current date
"ddd", // short day of week
szTime, sizeof szTime );
// cch includes null terminator, change it to
// a space to separate from time.
szTime[ cch - 1 ] = ' '; }
//
// Get time and format to characters
//
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, // use current time
NULL, // use default format
szTime + cch, (sizeof szTime) - cch );
return szTime; }
/*************************************************************/
BOOL FilterCommand( REMOTE_CLIENT *cl, char *buff, int dread ) { char tmpchar; DWORD tmp; int len, i; DWORD ThreadID; char inp_buff[2048]; char ch[3];
if (dread==0) return(FALSE);
buff[dread]=0;
if (buff[0]==COMMANDCHAR) {
switch(buff[1]) { case 'k': case 'K':
if (INVALID_HANDLE_VALUE != hWriteChildStdIn) {
printf("Remote: killing child softly, @K again to be more convincing.\n");
CancelIo( hWriteChildStdIn ); CloseHandle( hWriteChildStdIn ); hWriteChildStdIn = INVALID_HANDLE_VALUE;
GenerateConsoleCtrlEvent(CTRL_CLOSE_EVENT, 0); SleepEx(200, TRUE); cPendingCtrlCEvents++; GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); SleepEx(20, TRUE); GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
} else {
printf("Remote: Resorting to TerminateProcess.\n");
TerminateProcess(ChldProc, ERROR_PROCESS_ABORTED); }
break; case 's': case 'S': CloseHandle( (HANDLE) _beginthreadex( NULL, // security
0, // default stack size
SendStatus, (void *) cl->PipeWriteH, 0, // not suspended
&ThreadID )); break;
case 'p': case 'P': { char *msg;
msg = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 4096 ); if ( ! msg) { break; }
sprintf(msg,"From %s %s [%s]\n\n%s\n",cl->Name,cl->UserName,GetFormattedTime(TRUE),&buff[2]);
if (WriteFileSynch(hWriteTempFile,msg,strlen(msg),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); }
CloseHandle( (HANDLE) CreateThread( // no CRT for ShowPopup
NULL, // security
0, // default stack size
ShowPopup, (void *) msg, 0, // not suspended
&ThreadID ));
break; }
case 'm': case 'M': buff[dread-2]=0; CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(TRUE),TRUE);
if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); } break;
case '@': buff[dread-2]=0; CMDSTRING(inp_buff,len,&buff[1],cl,GetFormattedTime(FALSE),FALSE); if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); } //
// Remove the first @ sign
//
MoveMemory(buff,&buff[1],dread-1); buff[dread-1]=' '; return(FALSE); //Send it it to the chile process
default : ZeroMemory(inp_buff, sizeof(inp_buff)); strncpy(inp_buff, "** Unknown Command **\n", sizeof(inp_buff)-1); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; // we do this below // StartServerToClientFlow();
} case 'h': case 'H': _snprintf(inp_buff,sizeof(inp_buff), "%cM: To Send Message\n",COMMANDCHAR); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; } _snprintf(inp_buff,sizeof(inp_buff), "%cP: To Generate popup\n",COMMANDCHAR); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; } _snprintf(inp_buff,sizeof(inp_buff), "%cK: To kill the server\n",COMMANDCHAR); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; } _snprintf(inp_buff,sizeof(inp_buff), "%cQ: To Quit client\n",COMMANDCHAR); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; } _snprintf(inp_buff,sizeof(inp_buff), "%cH: This Help\n",COMMANDCHAR); if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; } StartServerToClientFlow(); break; } return(TRUE); }
if ((buff[0]<26)) { BOOL ret=FALSE;
_snprintf(ch, sizeof(ch), "^%c", buff[0] + 'A' - 1);
if (buff[0]==CTRLC) { // show this even to this client
CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),TRUE);
cPendingCtrlCEvents++; GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); ret = TRUE; // Already sent to child
} else { CMDSTRING(inp_buff,len,ch,cl,GetFormattedTime(FALSE),FALSE); }
if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); } return(ret); //FALSE:send it to child StdIn
}
// options here are CRLF(\r\n) or just LF(\n)
if (buff[dread-2] == 13) { i = 2; // 13 is CR
} else { i = 1; }
tmpchar=buff[dread-i]; buff[dread-i]=0; CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(FALSE),FALSE); buff[dread-i]=tmpchar; if (WriteFileSynch(hWriteTempFile,inp_buff,len,&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); } return(FALSE); }
/*************************************************************/ HANDLE ForkChildProcess( // Creates a new process
char *cmd, // Redirects its stdin,stdout
PHANDLE inH, // and stderr - returns the
PHANDLE outH // corresponding pipe ends.
) { SECURITY_ATTRIBUTES lsa; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE ChildIn; HANDLE ChildOut, ChildOutDup; HANDLE hWriteChild; HANDLE hReadChild; BOOL Success;
BOOL // pipeex.c
APIENTRY MyCreatePipeEx( OUT LPHANDLE lpReadPipe, OUT LPHANDLE lpWritePipe, IN LPSECURITY_ATTRIBUTES lpPipeAttributes, IN DWORD nSize, DWORD dwReadMode, DWORD dwWriteMode );
lsa.nLength=sizeof(SECURITY_ATTRIBUTES); lsa.lpSecurityDescriptor=NULL; lsa.bInheritHandle=TRUE;
//
// Create Parent_Write to ChildStdIn Pipe. Then
// duplicate the parent copy to a noninheritable
// handle and close the inheritable one so that
// the child won't be holding open a handle to
// the server end of its stdin pipe when we try
// to nuke that pipe to close the child.
//
Success = MyCreatePipeEx( &ChildIn, &hWriteChild, &lsa, 0, 0, FILE_FLAG_OVERLAPPED) &&
DuplicateHandle( GetCurrentProcess(), hWriteChild, GetCurrentProcess(), inH, 0, // ignored b/c SAME_ACCESS
FALSE, // not inheritable
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
if (!Success) { ErrorExit("Could Not Create Parent-->Child Pipe"); }
//
//Create ChildStdOut/stderr to Parent_Read pipe
//
Success = MyCreatePipeEx( &hReadChild, &ChildOut, &lsa, 0, FILE_FLAG_OVERLAPPED, 0) &&
DuplicateHandle( GetCurrentProcess(), hReadChild, GetCurrentProcess(), outH, 0, // ignored b/c SAME_ACCESS
FALSE, // not inheritable
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ) &&
DuplicateHandle( GetCurrentProcess(), ChildOut, GetCurrentProcess(), &ChildOutDup, 0, // ignored b/c SAME_ACCESS
TRUE, // inheritable
DUPLICATE_SAME_ACCESS );
if (!Success) { ErrorExit("Could Not Create Child-->Parent Pipe"); }
ZeroMemory(&si, sizeof(si)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = ChildIn; si.hStdOutput = ChildOut; si.hStdError = ChildOutDup; si.wShowWindow = SW_SHOW;
//
// Create Child Process
//
if ( ! CreateProcess( NULL, cmd, NULL, NULL, TRUE, GetPriorityClass( GetCurrentProcess() ), NULL, NULL, &si, &pi)) {
if (GetLastError()==2) { printf("Executable %s not found\n",cmd); } else { printf("CreateProcess(%s) failed, error %d.\n", cmd, GetLastError()); } ErrorExit("Could Not Create Child Process"); }
//
// Close unneccesary Handles
//
CloseHandle(ChildIn); CloseHandle(ChildOut); CloseHandle(ChildOutDup); CloseHandle(pi.hThread);
pidChild = pi.dwProcessId;
return(pi.hProcess); }
//
// SendStatus runs as its own thread, with C runtime available.
//
DWORD WINAPI SendStatus( LPVOID lpSendStatusParm ) { HANDLE hClientPipe = (HANDLE) lpSendStatusParm; char *pch; DWORD tmp; PREMOTE_CLIENT pClient; OVERLAPPED ol; char buff[2048]; char szSep[] = " ------------------------------\n";
//
// Since we're in our own thread we need our own
// overlapped structure for our client pipe writes.
//
ZeroMemory(&ol, sizeof(ol));
ol.hEvent = CreateEvent( NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
//
// Dump the closing client list
//
pch = buff;
EnterCriticalSection(&csClosingClientList);
for (pClient = (PREMOTE_CLIENT) ClosingClientListHead.Flink; pClient != (PREMOTE_CLIENT) &ClosingClientListHead; pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
if (pch + 60 > buff + sizeof(buff)) {
break; }
pch += sprintf(pch, "%d: %s %s (Disconnected)\n", pClient->dwID, pClient->Name, pClient->UserName); }
LeaveCriticalSection(&csClosingClientList);
WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
//
// Dump the normal client list
//
pch = buff;
EnterCriticalSection(&csClientList);
for (pClient = (PREMOTE_CLIENT) ClientListHead.Flink; pClient != (PREMOTE_CLIENT) &ClientListHead; pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
if (pch + 60 > buff + sizeof(buff)) {
break; }
pch += sprintf(pch, "%d: %s %s\n", pClient->dwID, pClient->Name, pClient->UserName); }
LeaveCriticalSection(&csClientList);
WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
//
// Dump the handshaking client list
//
pch = buff;
EnterCriticalSection(&csHandshakingList);
for (pClient = (PREMOTE_CLIENT) HandshakingListHead.Flink; pClient != (PREMOTE_CLIENT) &HandshakingListHead; pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
if (pch + 60 > buff + sizeof(buff)) {
break; }
pch += sprintf(pch, "%d: %s %s (Connecting)\n", pClient->dwID, pClient->Name, pClient->UserName); }
LeaveCriticalSection(&csHandshakingList);
WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
//
// Dump summary information.
//
pch = buff;
pch += sprintf(pch, "REMOTE /C %s \"%s\"\n", HostName, PipeName); pch += sprintf(pch, "Command: %s\n", ChildCmd); pch += sprintf(pch, "Windows NT %d.%d build %d \n", OsVersionInfo.dwMajorVersion, OsVersionInfo.dwMinorVersion, OsVersionInfo.dwBuildNumber);
WriteFileSynch(hClientPipe, buff, (DWORD)(pch - buff), &tmp, 0, &ol);
WriteFileSynch(hClientPipe, szSep, sizeof(szSep) - 1, &tmp, 0, &ol);
CloseHandle(ol.hEvent);
return 0; }
/*************************************************************/
DWORD // NO CRT for ShowPopup
WINAPI ShowPopup( void *vpArg ) { char *msg = (char *) vpArg;
MessageBox(GetActiveWindow(),msg,"** REMOTE.EXE **",MB_OK|MB_SETFOREGROUND); HeapFree(hHeap, 0, msg); return(0); }
/*************************************************************/
//
// SrvCtrlHand is the console event handler for the server side
// of remote. If our stdin is a console handle, we've disabled
// generation of ^C events by the console code. Therefore
// any we see are either generated by us for the benefit of
// our child processes sharing the console, or generated by
// some other process. We want to ignore the ones we generate
// (since we're already done with everything that needs to be
// done at that point), and also ignore ^C's generated by
// other processes since we don't need to do anything with those.
// For example if someone runs:
//
// remote /s "remote /s cmd inner" outer
//
// Then local keyboard ^C's will be read by the outer remote.exe
// from its stdin handle, then it will generate a CTRL_C_EVENT that
// all processes in the console will see, including both remote.exe's
// and the child cmd.exe. So the handler needs do nothing but indicate
// the event was handled by returning TRUE so the default handler
// won't kill us. For ^BREAK we want to specifically kill our child
// process so that cmd.exe and others that ignore ^BREAK will go away.
// Of course this won't kill our grandchildren and so on. Oh well.
//
// For all other events we return FALSE and let the default handler
// have it.
//
BOOL WINAPI SrvCtrlHand( DWORD event ) { BOOL bRet = FALSE; DWORD cb; DWORD dwTempFileOffset; OVERLAPPED ol; char szTime[64]; char szCmd[128];
if (event == CTRL_BREAK_EVENT) { TerminateProcess(ChldProc, 3); bRet = TRUE; } else if (event == CTRL_C_EVENT) { if ( ! cPendingCtrlCEvents ) {
//
// This came from the local keyboard or
// was generated by another process in
// this console. Echo it as a local
// command. We have use GetTimeFormat
// here not our GetFormattedTime since
// the latter is for the use of the
// main thread only.
//
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, // use current time
NULL, // use default format
szTime, sizeof(szTime) );
CMDSTRING(szCmd, cb, "^C", pLocalClient, szTime, TRUE);
ZeroMemory(&ol, sizeof(ol)); ol.hEvent = CreateEvent( NULL, // security
TRUE, // auto-reset
FALSE, // initially nonsignaled
NULL // unnamed
);
//
// Practically all writes to the tempfile are happening on
// the primary server thread. We're on a Ctrl-C thread.
// We can't start the server to client I/O going after
// writing because we're on the wrong thread, so we
// punt. To fix this we need an event we can signal
// that causes the main thread to call StartServerToClientFlow.
//
dwTempFileOffset = dwWriteFilePointer; dwWriteFilePointer += cb; WriteFileSynch(hWriteTempFile, szCmd, cb, &cb, dwTempFileOffset, &ol); // wrong thread // StartServerToClientFlow();
CloseHandle(ol.hEvent);
} else {
//
// We generated this event in response to a ^C received from
// a client, it's already been displayed to all clients.
//
cPendingCtrlCEvents--; }
bRet = TRUE; }
return bRet; }
/*************************************************************/
typedef BOOL (STRINGSDTOSDW)( LPWSTR String, DWORD Version, PSECURITY_DESCRIPTOR * pSD, PULONG SDSize ); typedef STRINGSDTOSDW * PSTRINGSDTOSDW ;
typedef BOOL (SDTOSTRINGSDW)( PSECURITY_DESCRIPTOR SD, DWORD StringVersion, SECURITY_INFORMATION SecInfo, LPWSTR * StringDescriptor, PULONG Size ); typedef SDTOSTRINGSDW * PSDTOSTRINGSDW ;
BOOL SddlToSecurityDescriptor( LPWSTR String, DWORD Version, PSECURITY_DESCRIPTOR * pSD, PULONG SDSize ) { HMODULE hModule ; PSTRINGSDTOSDW pStringSecurityDescriptorToSecurityDescriptor ; BOOL Success = FALSE ; PSECURITY_DESCRIPTOR sd ;
hModule = GetModuleHandle( "advapi32.dll" );
if ( hModule ) { pStringSecurityDescriptorToSecurityDescriptor = (PSTRINGSDTOSDW) GetProcAddress( hModule, "ConvertStringSecurityDescriptorToSecurityDescriptorW" );
if ( pStringSecurityDescriptorToSecurityDescriptor ) { Success = pStringSecurityDescriptorToSecurityDescriptor( String, Version, pSD, SDSize); return Success ; } }
sd = LocalAlloc( LMEM_FIXED, sizeof( SECURITY_DESCRIPTOR ) );
if ( sd ) { InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION );
SetSecurityDescriptorDacl( sd, TRUE, NULL, FALSE );
*pSD = sd ; if ( SDSize ) { *SDSize = sizeof( SECURITY_DESCRIPTOR ); }
return TRUE ; }
return FALSE ; }
/*************************************************************/
BOOL SDtoStringSD( PSECURITY_DESCRIPTOR pSD, DWORD Version, SECURITY_INFORMATION SecInfo, LPWSTR * StringSD, PULONG StringSize ) { HMODULE hModule ; PSDTOSTRINGSDW pSDtoStringSD ; BOOL Success = FALSE ;
hModule = GetModuleHandle( "advapi32.dll" );
if ( hModule ) { pSDtoStringSD = (PSDTOSTRINGSDW) GetProcAddress( hModule, "ConvertSecurityDescriptorToStringSecurityDescriptorW" );
if ( pSDtoStringSD ) { Success = pSDtoStringSD(pSD, Version, SecInfo, StringSD, StringSize ); FreeLibrary( hModule );
return Success ; } }
return FALSE ; }
/*************************************************************/
PSECURITY_DESCRIPTOR FormatSecurityDescriptor( CHAR * * DenyNames, DWORD DenyCount, CHAR * * Names, DWORD Count) { PSECURITY_DESCRIPTOR Sd; PACL Acl; DWORD i; PSID Sids; DWORD SidLength ; CHAR ReferencedDomain[ MAX_PATH ]; UCHAR SidBuffer[ 8 * sizeof(DWORD) + 8 ]; DWORD DomainLen ; SID_NAME_USE Use; DWORD SdLen;
SdLen = sizeof(SECURITY_DESCRIPTOR) + DenyCount * (sizeof( ACCESS_DENIED_ACE ) ) + DenyCount * GetSidLengthRequired( 8 ) + Count * (sizeof( ACCESS_ALLOWED_ACE ) ) + sizeof(ACL) + (Count * GetSidLengthRequired( 8 ) );
Sd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SdLen ); if ( !Sd ) { ErrorExit("Could not allocate SD"); }
InitializeSecurityDescriptor( Sd, SECURITY_DESCRIPTOR_REVISION );
Acl = (PACL)( (PUCHAR) Sd + sizeof( SECURITY_DESCRIPTOR) );
InitializeAcl( Acl, SdLen - sizeof( SECURITY_DESCRIPTOR) , ACL_REVISION );
Sids = SidBuffer; for (i = 0 ; i < DenyCount ; i ++ ) { SidLength = sizeof( SidBuffer );
DomainLen = MAX_PATH ;
if (! LookupAccountName(NULL, DenyNames[ i ], Sids, &SidLength, ReferencedDomain, &DomainLen, &Use ) ) { _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", DenyNames[ i ]); ErrorExit( ReferencedDomain ); }
//
// Got the sid. Now, add it as an access denied ace:
//
AddAccessDeniedAce( Acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_CREATE_PIPE_INSTANCE, Sids );
}
for (i = 0 ; i < Count ; i ++ ) { SidLength = sizeof( SidBuffer );
DomainLen = MAX_PATH ;
if (! LookupAccountName(NULL, Names[ i ], Sids, &SidLength, ReferencedDomain, &DomainLen, &Use ) ) { _snprintf( ReferencedDomain, MAX_PATH, "Unable to find account %s", Names[ i ]); ErrorExit( ReferencedDomain ); }
//
// Got the sid. Now, add it as an access allowed ace:
//
AddAccessAllowedAce(Acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_CREATE_PIPE_INSTANCE, Sids ); }
//
// Now the ACL should be complete, so set it into the SD and return:
//
SetSecurityDescriptorDacl( Sd, TRUE, Acl, FALSE );
return Sd ; }
/*************************************************************/
VOID CloseClient( REMOTE_CLIENT *pClient ) { DWORD tmp; char Buf[200];
#if DBG
if (pClient->ServerFlags & ~SFLG_VALID) {
printf("pClient %p looks nasty in CloseClient.\n", pClient); ErrorExit("REMOTE_CLIENT structure corrupt."); } #endif
//
// If we're still active (on the normal client list)
// start tearing things down and move to the closing
// list.
//
if (pClient->ServerFlags & SFLG_CLOSING) { return; }
if (pClient->ServerFlags & SFLG_HANDSHAKING) { MoveClientToNormalList(pClient); }
MoveClientToClosingList(pClient);
pClient->ServerFlags |= SFLG_CLOSING;
if (pClient->PipeWriteH != INVALID_HANDLE_VALUE) { TRACE(CONNECT, ("Disconnecting %d PipeWriteH (%p).\n", pClient->dwID, pClient->PipeWriteH)); CancelIo(pClient->PipeWriteH); DisconnectNamedPipe(pClient->PipeWriteH); CloseHandle(pClient->PipeWriteH); }
if (pClient->PipeReadH != INVALID_HANDLE_VALUE && pClient->PipeReadH != pClient->PipeWriteH) {
TRACE(CONNECT, ("Disconnecting %d PipeReadH (%p).\n", pClient->dwID, pClient->PipeReadH)); CancelIo(pClient->PipeReadH); DisconnectNamedPipe(pClient->PipeReadH); CloseHandle(pClient->PipeReadH); }
if (pClient->rSaveFile != INVALID_HANDLE_VALUE) { CancelIo(pClient->rSaveFile); CloseHandle(pClient->rSaveFile); }
pClient->rSaveFile = pClient->PipeWriteH = pClient->PipeReadH = INVALID_HANDLE_VALUE;
if ( ! bShuttingDownServer ) { ZeroMemory(Buf, sizeof(Buf)); _snprintf(Buf, sizeof(Buf)-1, "\n**Remote: Disconnected from %s %s [%s]\n", pClient->Name, pClient->UserName, GetFormattedTime(TRUE));
if (WriteFileSynch(hWriteTempFile,Buf,strlen(Buf),&tmp,dwWriteFilePointer,&olMainThread)) { dwWriteFilePointer += tmp; StartServerToClientFlow(); } }
return; }
BOOL FASTCALL HandleSessionError( PREMOTE_CLIENT pClient, DWORD dwError ) { if (pClient->ServerFlags & SFLG_CLOSING) { return TRUE; }
if (dwError) { if (ERROR_BROKEN_PIPE == dwError || ERROR_OPERATION_ABORTED == dwError || ERROR_NO_DATA == dwError ) { CloseClient(pClient); return TRUE; }
SetLastError(dwError); ErrorExit("Unhandled session error."); }
return FALSE; }
VOID FASTCALL CleanupTempFiles( PSZ pszTempDir ) { HANDLE hSearch; WIN32_FIND_DATA FindData; char szPath[MAX_PATH + 1] = {0}; char szFile[MAX_PATH + 1];
//
// pszTempDir, from GetTempPath, has a trailing backslash.
//
_snprintf(szPath, sizeof(szPath)-1, "%sREM*.tmp", pszTempDir);
hSearch = FindFirstFile(szPath, &FindData);
if (INVALID_HANDLE_VALUE != hSearch) { do { ZeroMemory(szFile, sizeof(szFile)); _snprintf(szFile, sizeof(szFile)-1, "%s%s", pszTempDir, FindData.cFileName);
DeleteFile(szFile); } while (FindNextFile(hSearch, &FindData));
FindClose(hSearch); } }
VOID SaveDacl( PSECURITY_DESCRIPTOR psd ) { HKEY hKey ; int err ; DWORD disp ; LPWSTR StringSD ; DWORD StringLen;
err = RegCreateKeyExW( HKEY_LOCAL_MACHINE, REGISTRY_PATH, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &disp );
if ( err == 0 ) { if ( SDtoStringSD(sdPublic, 1, DACL_SECURITY_INFORMATION, &StringSD, &StringLen ) ) { err = RegSetValueExW( hKey, REGISTRY_VALUE, 0, REG_SZ, (LPBYTE) StringSD, StringLen * sizeof(WCHAR) ); } RegCloseKey( hKey ); } }
#pragma prefast(push)
#pragma prefast(disable: 248) // NULL dacl is by design here, really
VOID FASTCALL SetupSecurityDescriptors( VOID ) { int i; int err ; HKEY hKey ; PWSTR TextSD ; DWORD Type ; DWORD Size ; PSID Everyone ; PACL pDacl ; SID_IDENTIFIER_AUTHORITY World = SECURITY_WORLD_SID_AUTHORITY ; PSECURITY_DESCRIPTOR psd ;
pDacl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 12 + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL )); psd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( SECURITY_DESCRIPTOR ));
//
// initialize the struct
//
saLocalNamedObjects.nLength = sizeof( SECURITY_ATTRIBUTES );
if ( (pDacl != NULL) && (psd != NULL ) ) { if ( AllocateAndInitializeSid(&World, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &Everyone) ) { InitializeAcl(pDacl, 12 + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ), ACL_REVISION);
AddAccessAllowedAce(pDacl, ACL_REVISION, EVENT_ALL_ACCESS | MUTEX_ALL_ACCESS | SYNCHRONIZE, Everyone );
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION );
SetSecurityDescriptorDacl( psd, TRUE, pDacl, FALSE );
saLocalNamedObjects.bInheritHandle = FALSE ; saLocalNamedObjects.lpSecurityDescriptor = psd ;
HeapFree(GetProcessHeap(), 0, Everyone ); } }
//
// Initialize the wide-open security descriptor.
//
if ( !SddlToSecurityDescriptor(DEFAULT_SECURITY_DESCRIPTOR, 1, &sdPublic, NULL ) ) { sdPublic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( SECURITY_DESCRIPTOR ) );
if ( sdPublic ) { InitializeSecurityDescriptor( sdPublic, SECURITY_DESCRIPTOR_REVISION ); SetSecurityDescriptorDacl( sdPublic, TRUE, NULL, FALSE ); } }
saPublic.nLength = sizeof(saPublic); saPublic.lpSecurityDescriptor = sdPublic;
//
// if /u was specified once or more, build the security descriptor to
// enforce it.
//
saPipe.nLength = sizeof(saPipe);
if ( DaclNameCount || DaclDenyNameCount ) { saPipe.lpSecurityDescriptor = FormatSecurityDescriptor( DaclDenyNames, DaclDenyNameCount, DaclNames, DaclNameCount );
if ( SaveDaclToRegistry ) { SaveDacl( saPipe.lpSecurityDescriptor ); }
if (DaclNameCount) { fputs( "\nProtected Server! Only the following users or groups can connect:\n", stdout );
for (i = 0 ; i < (int) DaclNameCount ; i++) { printf( " %s\n", DaclNames[i] ); } }
if (DaclDenyNameCount) { fputs("The following users or groups explicitly cannot connect:\n", stdout );
for (i = 0 ; i < (int) DaclDenyNameCount ; i++) { printf(" %s\n", DaclDenyNames[i] ); } } } else {
saPipe.lpSecurityDescriptor = sdPublic;
err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, REGISTRY_PATH, 0, KEY_READ, &hKey );
if ( err == 0 ) { err = RegQueryValueExW( hKey, REGISTRY_VALUE, 0, &Type, NULL, &Size );
if ( err != ERROR_FILE_NOT_FOUND ) { TextSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size );
if ( TextSD ) { err = RegQueryValueExW( hKey, REGISTRY_VALUE, 0, &Type, (LPBYTE) TextSD, &Size );
if ( err == 0 ) { SddlToSecurityDescriptor( TextSD, 1, &saPipe.lpSecurityDescriptor, NULL ); } } }
RegCloseKey( hKey ); } } } #pragma prefast(pop)
|