Windows-Server-2003/sdktools/remote/srvutil.c

1256 lines
36 KiB
C
Raw Permalink Normal View History

2024-08-04 01:28:15 +02:00
/******************************************************************************\
* 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)