SERVER.H


/******************************************************************************\
* 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:

Server.h

Abstract:

The server component of Remote, rewritten using
ReadFileEx/WriteFileEx completion routines.

Author:

Dave Hart 30 May 1997

Environment:

Console App. User mode.

Revision History:

--*/

#include <lm.h> // needed for NET_API_STATUS below

#if !defined(SERVER_H_NOEXTERN)
#define SRVEXTERN extern
#else
#define SRVEXTERN
#endif


#if DBG
DWORD Trace; // bits set in here trigger trace printfs

#define TR_SESSION (0x01)
#define TR_CHILD (0x02)
#define TR_SHAKE (0x04)
#define TR_CONNECT (0x08)
#define TR_QUERY (0x10)
#define TR_COPYPIPE (0x20)
#endif


#if DBG
#define TRACE(tracebit, printfargs) \
((Trace & (TR_##tracebit) \
? (printf printfargs, fflush(stdout), 0) \
: 0))
#else
#define TRACE(tracebit, printfargs) (0)
#endif

#if defined(ASSERT)
#undef ASSERT
#endif

#if DBG
#define ASSERT(exp) ((exp) || (ErrorExit("Assertion failed in " __FILE__ ": " #exp ),0))
#else
#define ASSERT(exp) (0)
#endif


//
// Size of transfer buffers
//

#define BUFFSIZE (4 * 1024)

//
// ServerFlags bit values in REMOTE_CLIENT below
//

#define SFLG_CLOSING 0x01
#define SFLG_HANDSHAKING 0x02
#define SFLG_READINGCOMMAND 0x04
#define SFLG_LOCAL 0x08

#define SFLG_VALID \
(SFLG_CLOSING | \
SFLG_HANDSHAKING | \
SFLG_READINGCOMMAND | \
SFLG_LOCAL)


//
// Per-client state
//

typedef struct tagREMOTE_CLIENT {
LIST_ENTRY Links;
DWORD dwID; // 1, 2, ...
DWORD ServerFlags;
DWORD Flag; //from Client's ClientToServerFlag
DWORD cbWrite; //zero if no read temp/write client ops pending
HANDLE PipeReadH; //Client sends its StdIn through this
HANDLE PipeWriteH; //Client gets its StdOut through this
DWORD dwFilePos; //offset of temp file where next read begins
OVERLAPPED ReadOverlapped;
OVERLAPPED WriteOverlapped;
HANDLE rSaveFile; //Sessions read handle to SaveFile
DWORD cbReadTempBuffer;
DWORD cbWriteBuffer;
DWORD cbCommandBuffer;
char HexAsciiId[8]; // dwID as 8 hex chars -- no terminator
char Name[HOSTNAMELEN]; //Name of client Machine;
char UserName[16]; //Name of user on client machine.
BYTE ReadBuffer[BUFFSIZE];
BYTE ReadTempBuffer[BUFFSIZE];
BYTE WriteBuffer[BUFFSIZE];
BYTE CommandBuffer[BUFFSIZE];
} REMOTE_CLIENT, *PREMOTE_CLIENT;

//
// Client lists, see srvlist.c
//

SRVEXTERN LIST_ENTRY HandshakingListHead;
SRVEXTERN CRITICAL_SECTION csHandshakingList;

SRVEXTERN LIST_ENTRY ClientListHead;
SRVEXTERN CRITICAL_SECTION csClientList;

SRVEXTERN LIST_ENTRY ClosingClientListHead;
SRVEXTERN CRITICAL_SECTION csClosingClientList;


SRVEXTERN DWORD dwNextClientID;
SRVEXTERN LPSTR pszPipeName;
SRVEXTERN HANDLE ChldProc;
SRVEXTERN DWORD pidChild;
SRVEXTERN HANDLE hWriteChildStdIn;
SRVEXTERN BOOL bShuttingDownServer;
SRVEXTERN HANDLE hHeap;

SRVEXTERN volatile DWORD cPendingCtrlCEvents;

SRVEXTERN OSVERSIONINFO OsVersionInfo;

// File containing all that was output by child process.
// Each connection opens a handle to this file
// and sends its contents through PipeWriteH.

SRVEXTERN HANDLE hWriteTempFile;

SRVEXTERN char SaveFileName[64]; //Name of above file - all new sessions need


//
// Generic "wide-open" security descriptor as well
// as the possibly-restricted pipe SD.
//

SRVEXTERN SECURITY_DESCRIPTOR sdPublic;
SRVEXTERN SECURITY_ATTRIBUTES saPublic;
SRVEXTERN SECURITY_ATTRIBUTES saPipe;


//
// To minimize client "all pipe instances are busy" errors,
// we wait on connection to several instances of the IN pipe,
// the sole pipe used by single-pipe clients. Because of the
// requirement to support two-pipe clients (old software as
// well as new software on Win95), we cannot easily create
// and wait for connection on several instances of the OUT pipe.
// This is because two-pipe clients connect to both pipes before
// handshaking commences, and they connect to OUT first. If we
// had several OUT pipe instances waiting, when an IN pipe was
// connected by the two-pipe client, we wouldn't know which of
// the possibly several connected OUT pipe instances to pair
// it with. With only one OUT pipe, at IN connect time we need
// to distinguish two-pipe from one-pipe clients so a one-pipe
// client doesn't sneak in between the OUT and IN connects of
// a two-pipe client and wrongly be paired with the OUT pipe.
// To do so we look at the first byte of the initial write
// from the client (of the computername and magic value), if
// it's a question mark we know we have a new client and won't
// accidentally link it to a connected OUT instance.
//

#define CONNECT_COUNT 3

SRVEXTERN DWORD cConnectIns;
SRVEXTERN OVERLAPPED rgolConnectIn[CONNECT_COUNT];
SRVEXTERN HANDLE rghPipeIn[CONNECT_COUNT];

SRVEXTERN OVERLAPPED olConnectOut;
SRVEXTERN BOOL bOutPipeConnected;
SRVEXTERN HANDLE hPipeOut;
SRVEXTERN HANDLE hConnectOutTimer;

//
// Indexes into rghWait array for multiple-wait
//

#define WAITIDX_CHILD_PROCESS 0
#define WAITIDX_READ_STDIN_DONE 1
#define WAITIDX_QUERYSRV_WAIT 2
#define WAITIDX_PER_PIPE_EVENT 3
#define WAITIDX_CONNECT_OUT 4
#define WAITIDX_CONNECT_IN_BASE 5
#define MAX_WAIT_HANDLES (WAITIDX_CONNECT_IN_BASE + CONNECT_COUNT)

SRVEXTERN HANDLE rghWait[MAX_WAIT_HANDLES];

SRVEXTERN OVERLAPPED ReadChildOverlapped;
SRVEXTERN HANDLE hReadChildOutput;
SRVEXTERN BYTE ReadChildBuffer[BUFFSIZE];

SRVEXTERN PREMOTE_CLIENT pLocalClient;

typedef struct tagCOPYPIPE {
HANDLE hRead;
HANDLE hWrite;
} COPYPIPE, *PCOPYPIPE;

SRVEXTERN COPYPIPE rgCopyPipe[2];

SRVEXTERN volatile DWORD dwWriteFilePointer; // used by SrvCtrlHand (thread)

SRVEXTERN OVERLAPPED QueryOverlapped;
SRVEXTERN HANDLE hQPipe;

SRVEXTERN OVERLAPPED olMainThread;


BOOL
APIENTRY
MyCreatePipeEx(
OUT LPHANDLE lpReadPipe,
OUT LPHANDLE lpWritePipe,
IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
IN DWORD nSize,
DWORD dwReadMode,
DWORD dwWriteMode
);

DWORD
WINAPI
CopyPipeToPipe(
LPVOID lpCopyPipeData
);

DWORD
WINAPI
CopyStdInToPipe(
LPVOID lpCopyPipeData
);

VOID
FASTCALL
StartSession(
PREMOTE_CLIENT pClient
);

VOID
FASTCALL
StartLocalSession(
VOID
);

VOID
FASTCALL
StartReadClientInput(
PREMOTE_CLIENT pClient
);

VOID
WINAPI
ReadClientInputCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

VOID
WINAPI
WriteChildStdInCompleted(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

#define OUT_PIPE -1

VOID
FASTCALL
CreatePipeAndIssueConnect(
int nIndex // IN pipe index or OUT_PIPE
);

VOID
FASTCALL
HandleOutPipeConnected(
VOID
);

VOID
APIENTRY
ConnectOutTimerFired(
LPVOID pArg,
DWORD dwTimerLo,
DWORD dwTimerHi
);

VOID
FASTCALL
HandleInPipeConnected(
int nIndex
);

VOID
FASTCALL
HandshakeWithRemoteClient(
PREMOTE_CLIENT pClient
);

VOID
FASTCALL
StartChildOutPipeRead(
VOID
);

VOID
WINAPI
ReadChildOutputCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

VOID
WINAPI
WriteTempFileCompleted(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

VOID
FASTCALL
StartServerToClientFlow(
VOID
);

VOID
FASTCALL
StartReadTempFile(
PREMOTE_CLIENT pClient
);

VOID
WINAPI
ReadTempFileCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

VOID
FASTCALL
StartWriteSessionOutput(
PREMOTE_CLIENT pClient
);

BOOL
FASTCALL
WriteSessionOutputCompletedCommon(
PREMOTE_CLIENT pClient,
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

VOID
WINAPI
WriteSessionOutputCompletedWriteNext(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

VOID
WINAPI
WriteSessionOutputCompletedReadNext(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

VOID
FASTCALL
HandshakeWithRemoteClient(
PREMOTE_CLIENT pClient
);


VOID
WINAPI
ReadClientNameCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

VOID
WINAPI
WriteServerReplyCompleted(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

VOID
WINAPI
ReadClientStartupInfoSizeCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

VOID
WINAPI
ReadClientStartupInfoCompleted(
DWORD dwError,
DWORD cbRead,
LPOVERLAPPED lpO
);

PCHAR
GetFormattedTime(
BOOL bDate
);

HANDLE
ForkChildProcess( // Creates a new process
char *cmd, // Redirects its stdin,stdout
PHANDLE in, // and stderr - returns the
PHANDLE out // corresponding pipe ends.
);

BOOL
FilterCommand( //Filters input from client
REMOTE_CLIENT *cl, //for commands intended for REMOTE
char *buff,
int dread
);

BOOL
WINAPI
SrvCtrlHand(
DWORD event
);

DWORD
WINAPI
SendStatus(
LPVOID lpSendStatusParm
);

DWORD
WINAPI
ShowPopup(
void *vpArg
);

VOID
RemoveInpMark(
char* Buff,
DWORD Size
);

VOID
CloseClient(
REMOTE_CLIENT *Client
);

PSECURITY_DESCRIPTOR
FormatSecurityDescriptor(
CHAR * * DenyNames,
DWORD DenyCount,
CHAR * * Names,
DWORD Count
);

BOOL
FASTCALL
HandleSessionError(
PREMOTE_CLIENT pClient,
DWORD dwError
);

VOID
FASTCALL
CleanupTempFiles(
PSZ pszTempDir
);

VOID
FASTCALL
SetupSecurityDescriptors(
VOID
);

VOID
FASTCALL
RuntimeLinkAPIs(
VOID
);

VOID
FASTCALL
InitializeClientLists(
VOID
);

VOID
FASTCALL
AddClientToHandshakingList(
PREMOTE_CLIENT pClient
);

VOID
FASTCALL
MoveClientToNormalList(
PREMOTE_CLIENT pClient
);

VOID
FASTCALL
MoveClientToClosingList(
PREMOTE_CLIENT pClient
);

PREMOTE_CLIENT
FASTCALL
RemoveFirstClientFromClosingList(
VOID
);


VOID
InitAd(
BOOL IsAdvertise
);

VOID
ShutAd(
BOOL IsAdvertise
);

VOID
APIENTRY
AdvertiseTimerFired(
LPVOID pArg,
DWORD dwTimerLo,
DWORD dwTimerHi
);

VOID
WINAPI
WriteMailslotCompleted(
DWORD dwError,
DWORD cbWritten,
LPOVERLAPPED lpO
);

VOID
FASTCALL
InitializeQueryServer(
VOID
);

VOID
FASTCALL
QueryWaitCompleted(
VOID
);

VOID
FASTCALL
StartServingQueryPipe(
VOID
);

DWORD
WINAPI
QueryHandlerThread(
LPVOID lpUnused
);

BOOL
CALLBACK
EnumWindowProc(
HWND hWnd,
LPARAM lParam
);

//
// Declare pointers to runtime-linked functions
//

HANDLE
(WINAPI *pfnCreateWaitableTimer)(
LPSECURITY_ATTRIBUTES lpTimerAttributes,
BOOL bManualReset,
LPCSTR lpTimerName
);

BOOL
(WINAPI *pfnSetWaitableTimer)(
HANDLE hTimer,
const LARGE_INTEGER *lpDueTime,
LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine,
LPVOID lpArgToCompletionRoutine,
BOOL fResume
);

BOOL
(WINAPI *pfnCancelWaitableTimer)(
HANDLE hTimer
);

BOOL
(WINAPI *pfnCancelIo)(
HANDLE hFile
);

#define CANCELIO(hFile) (pfnCancelIo) ? ( pfnCancelIo(hFile) ) : 0;

NET_API_STATUS
(NET_API_FUNCTION *pfnNetWkstaGetInfo)(
IN LPTSTR servername OPTIONAL,
IN DWORD level,
OUT LPBYTE *bufptr
);

NET_API_STATUS
(NET_API_FUNCTION *pfnNetApiBufferFree)(
IN LPVOID Buffer
);