/******************************************************************************\
* 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 <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <io.h>
#include <string.h>
#include "Remote.h"
#include "Server.h"
#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;
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( // freed by ShowPopup
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 :
sprintf(inp_buff,"%s","** Unknown Command **\n");
if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
dwWriteFilePointer += tmp;
// we do this below // StartServerToClientFlow();
}
case 'h':
case 'H':
sprintf(inp_buff,"%cM: To Send Message\n",COMMANDCHAR);
if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
dwWriteFilePointer += tmp;
}
sprintf(inp_buff,"%cP: To Generate popup\n",COMMANDCHAR);
if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
dwWriteFilePointer += tmp;
}
sprintf(inp_buff,"%cK: To kill the server\n",COMMANDCHAR);
if (WriteFileSynch(hWriteTempFile,inp_buff,strlen(inp_buff),&tmp,dwWriteFilePointer,&olMainThread)) {
dwWriteFilePointer += tmp;
}
sprintf(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;
sprintf(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
}
tmpchar=buff[dread-2]; //must be 13;but just incase
buff[dread-2]=0;
CMDSTRING(inp_buff,len,buff,cl,GetFormattedTime(FALSE),FALSE);
buff[dread-2]=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, 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, 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, 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, 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;
}
/*************************************************************/
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 = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, 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 %x 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 (%x).\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 (%x).\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 ) {
sprintf(Buf, "\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];
char szFile[MAX_PATH + 1];
//
// pszTempDir, from GetTempPath, has a trailing backslash.
//
sprintf(szPath, "%sREM*.tmp", pszTempDir);
hSearch = FindFirstFile(
szPath,
&FindData
);
if (INVALID_HANDLE_VALUE != hSearch) {
do {
sprintf(szFile, "%s%s", pszTempDir, FindData.cFileName);
DeleteFile(szFile);
} while (FindNextFile(hSearch, &FindData));
FindClose(hSearch);
}
}
VOID
FASTCALL
SetupSecurityDescriptors(
VOID
)
{
int i;
//
// Initialize the wide-open security descriptor.
//
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 (DaclNameCount) {
printf( "\nProtected Server! Only the following users or groups can connect:\n" );
for (i = 0 ; i < (int) DaclNameCount ; i++) {
printf( " %s\n", DaclNames[i] );
}
}
if (DaclDenyNameCount) {
printf( "The following users or groups explicitly cannot connect:\n" );
for (i = 0 ; i < (int) DaclDenyNameCount ; i++) {
printf(" %s\n", DaclDenyNames[i] );
}
}
} else {
saPipe.lpSecurityDescriptor = &sdPublic;
}
}
VOID
FASTCALL
RuntimeLinkAPIs(
VOID
)
{
HANDLE hmodKernel32;
HANDLE hmodNetApi32;
hmodKernel32 = LoadLibrary("kernel32");
hmodNetApi32 = LoadLibrary("netapi32");
pfnCreateWaitableTimer = (void *)
GetProcAddress(
hmodKernel32,
"CreateWaitableTimerA"
);
pfnSetWaitableTimer = (void *)
GetProcAddress(
hmodKernel32,
"SetWaitableTimer"
);
pfnCancelWaitableTimer = (void *)
GetProcAddress(
hmodKernel32,
"CancelWaitableTimer"
);
pfnCancelIo = (void *)
GetProcAddress(
hmodKernel32,
"CancelIo"
);
pfnNetWkstaGetInfo = (void *)
GetProcAddress(
hmodNetApi32,
"NetWkstaGetInfo"
);
pfnNetApiBufferFree = (void *)
GetProcAddress(
hmodNetApi32,
"NetApiBufferFree"
);
//
// We do without Waitable Timers and CancelIo on 3.51
//
if (!pfnNetWkstaGetInfo ||
!pfnNetApiBufferFree) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
ErrorExit("Remote server requires Windows NT.");
}
}