361 lines
9.3 KiB
C
361 lines
9.3 KiB
C
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "Remote.h"
|
|
#include "Server.h"
|
|
|
|
//
|
|
// This module uses mailslots to broadcast the existence of
|
|
// this remote server to allow a form of browsing for
|
|
// remote server instances. This is disabled in the
|
|
// customer version of remote.exe, and can be disabled
|
|
// in the internal version using the /v- switch to
|
|
// remote /s.
|
|
//
|
|
// remoteds.c implements a listener that allows searching.
|
|
//
|
|
|
|
#define INITIAL_SLEEP_PERIOD (35 * 1000) // 35 seconds before first
|
|
#define INITIAL_AD_RATE (10 * 60 * 1000) // 10 minutes between 1 & 2,
|
|
#define MAXIMUM_AD_RATE (120 * 60 * 1000) // doubling until 120 minutes max
|
|
|
|
|
|
OVERLAPPED olMailslot;
|
|
HANDLE hAdTimer = INVALID_HANDLE_VALUE;
|
|
HANDLE hMailslot = INVALID_HANDLE_VALUE;
|
|
DWORD dwTimerInterval; // milliseconds
|
|
BOOL bSynchAdOnly;
|
|
BOOL bSendingToMailslot;
|
|
char szMailslotName[64]; // netbios names are short
|
|
char szSend[1024];
|
|
|
|
|
|
#define MAX_MAILSLOT_SPEWS 2
|
|
DWORD dwMailslotErrors;
|
|
|
|
|
|
VOID
|
|
InitAd(
|
|
BOOL IsAdvertise
|
|
)
|
|
{
|
|
DWORD cb;
|
|
PWKSTA_INFO_101 pwki101;
|
|
LARGE_INTEGER DueTime;
|
|
|
|
if (IsAdvertise) {
|
|
|
|
// Unless Win32s or Win9x support named pipe servers...
|
|
|
|
ASSERT(OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
|
|
|
// Problems with overlapped writes to a mailslot sometimes
|
|
// cause remote.exe to zombie on exit on NT4, undebuggable
|
|
// and unkillable because of an abandoned RDR1 IRP which
|
|
// never completes.
|
|
//
|
|
// So on NT4 we only send messages at startup and shutdown
|
|
// and send them synchronously using a nonoverlapped handle.
|
|
//
|
|
|
|
bSynchAdOnly = (OsVersionInfo.dwMajorVersion <= 4);
|
|
|
|
//
|
|
// Get currently active computername and browser/mailslot
|
|
// domain/workgroup using one call to NetWkstaGetInfo.
|
|
// This is unicode-only, we'll use wsprintf's %ls to
|
|
// convert to 8-bit characters.
|
|
//
|
|
// remoteds.exe needs to be run on a workstation that is
|
|
// part of the domain or workgroup of the same name,
|
|
// and be in broadcast range, to receive our sends.
|
|
//
|
|
|
|
if (pfnNetWkstaGetInfo(NULL, 101, (LPBYTE *) &pwki101)) {
|
|
printf("REMOTE: unable to get computer/domain name, not advertising.\n");
|
|
return;
|
|
}
|
|
|
|
wsprintf(
|
|
szMailslotName,
|
|
"\\\\%ls\\MAILSLOT\\REMOTE\\DEBUGGERS",
|
|
pwki101->wki101_langroup
|
|
);
|
|
|
|
wsprintf(
|
|
szSend,
|
|
"%ls\t%d\t%s\t%s",
|
|
pwki101->wki101_computername,
|
|
GetCurrentProcessId(),
|
|
PipeName,
|
|
ChildCmd
|
|
);
|
|
|
|
pfnNetApiBufferFree(pwki101);
|
|
pwki101 = NULL;
|
|
|
|
//
|
|
// Broadcast mailslots are limited to 400 message bytes
|
|
//
|
|
|
|
szSend[399] = 0;
|
|
|
|
if (bSynchAdOnly) {
|
|
|
|
hMailslot =
|
|
CreateFile(
|
|
szMailslotName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (hMailslot != INVALID_HANDLE_VALUE) {
|
|
if ( ! WriteFile(
|
|
hMailslot,
|
|
szSend,
|
|
strlen(szSend) + 1,
|
|
&cb,
|
|
NULL
|
|
)) {
|
|
|
|
printf("REMOTE: WriteFile Failed on mailslot, error %d\n", GetLastError());
|
|
}
|
|
} else {
|
|
printf("REMOTE: Failed to create mailslot, error %d\n", GetLastError());
|
|
}
|
|
|
|
|
|
} else { // we can do async mailslot I/O
|
|
|
|
//
|
|
// Create a waitable timer and set it to fire first in
|
|
// INITIAL_SLEEP_PERIOD milliseconds by calling the
|
|
// completion routine AdvertiseTimerFired. It will
|
|
// be given an inital period of INITIAL_AD_RATE ms.
|
|
//
|
|
|
|
hAdTimer =
|
|
pfnCreateWaitableTimer(
|
|
NULL, // security
|
|
FALSE, // bManualReset, we want auto-reset
|
|
NULL // unnamed
|
|
);
|
|
|
|
DueTime.QuadPart = Int32x32To64(INITIAL_SLEEP_PERIOD, -10000);
|
|
dwTimerInterval = INITIAL_AD_RATE;
|
|
|
|
pfnSetWaitableTimer(
|
|
hAdTimer,
|
|
&DueTime,
|
|
dwTimerInterval,
|
|
AdvertiseTimerFired,
|
|
0, // arg to compl. rtn
|
|
TRUE
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ShutAd(
|
|
BOOL IsAdvertise
|
|
)
|
|
{
|
|
DWORD cb;
|
|
BOOL b;
|
|
|
|
if (IsAdvertise) {
|
|
|
|
if (INVALID_HANDLE_VALUE != hAdTimer) {
|
|
|
|
pfnCancelWaitableTimer(hAdTimer);
|
|
CloseHandle(hAdTimer);
|
|
hAdTimer = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE != hMailslot &&
|
|
! bSendingToMailslot) {
|
|
|
|
//
|
|
// Tell any listening remoteds's we're
|
|
// outta here. Do this by tacking on
|
|
// a ^B at the end of the string (as
|
|
// in Bye).
|
|
//
|
|
|
|
strcat(szSend, "\x2");
|
|
|
|
|
|
if (bSynchAdOnly) { // overlapped handle or not?
|
|
b = WriteFile(
|
|
hMailslot,
|
|
szSend,
|
|
strlen(szSend) + 1,
|
|
&cb,
|
|
NULL
|
|
);
|
|
} else {
|
|
b = WriteFileSynch(
|
|
hMailslot,
|
|
szSend,
|
|
strlen(szSend) + 1,
|
|
&cb,
|
|
0,
|
|
&olMainThread
|
|
);
|
|
}
|
|
|
|
if ( ! b ) {
|
|
|
|
printf("REMOTE: WriteFile Failed on mailslot, error %d\n", GetLastError());
|
|
}
|
|
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE != hMailslot) {
|
|
|
|
printf("\rREMOTE: closing mailslot... ");
|
|
fflush(stdout);
|
|
CloseHandle(hMailslot);
|
|
hMailslot = INVALID_HANDLE_VALUE;
|
|
printf("\r \r");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
APIENTRY
|
|
AdvertiseTimerFired(
|
|
LPVOID pArg,
|
|
DWORD dwTimerLo,
|
|
DWORD dwTimerHi
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( pArg );
|
|
UNREFERENCED_PARAMETER( dwTimerLo );
|
|
UNREFERENCED_PARAMETER( dwTimerHi );
|
|
|
|
|
|
if (INVALID_HANDLE_VALUE == hMailslot) {
|
|
|
|
hMailslot =
|
|
CreateFile(
|
|
szMailslotName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE != hMailslot) {
|
|
|
|
ZeroMemory(&olMailslot, sizeof(olMailslot));
|
|
|
|
bSendingToMailslot = TRUE;
|
|
|
|
if ( ! WriteFileEx(
|
|
hMailslot,
|
|
szSend,
|
|
strlen(szSend) + 1,
|
|
&olMailslot,
|
|
WriteMailslotCompleted
|
|
)) {
|
|
|
|
bSendingToMailslot = FALSE;
|
|
|
|
if (++dwMailslotErrors <= MAX_MAILSLOT_SPEWS) {
|
|
|
|
DWORD dwError;
|
|
char szErrorText[512];
|
|
|
|
dwError = GetLastError();
|
|
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
dwError,
|
|
0,
|
|
szErrorText,
|
|
sizeof szErrorText,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// FormatMessage has put a newline at the end of szErrorText
|
|
//
|
|
|
|
printf(
|
|
"REMOTE: Advertisement failed, mailslot error %d:\n%s",
|
|
dwError,
|
|
szErrorText
|
|
);
|
|
}
|
|
|
|
//
|
|
// Try reopening the mailslot next time, can't hurt.
|
|
//
|
|
|
|
CloseHandle(hMailslot);
|
|
hMailslot = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
WriteMailslotCompleted(
|
|
DWORD dwError,
|
|
DWORD cbWritten,
|
|
LPOVERLAPPED lpO
|
|
)
|
|
{
|
|
LARGE_INTEGER DueTime;
|
|
|
|
bSendingToMailslot = FALSE;
|
|
|
|
if (dwError ||
|
|
(strlen(szSend) + 1) != cbWritten) {
|
|
|
|
if (++dwMailslotErrors <= MAX_MAILSLOT_SPEWS) {
|
|
printf("REMOTE: write failed on mailslot, error %d cb %d (s/b %d)\n",
|
|
dwError, cbWritten, (strlen(szSend) + 1));
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If we succeeded in writing the mailslot, double the timer interval
|
|
// up to the limit.
|
|
//
|
|
|
|
if (dwTimerInterval < MAXIMUM_AD_RATE) {
|
|
|
|
dwTimerInterval = max(dwTimerInterval * 2, MAXIMUM_AD_RATE);
|
|
|
|
DueTime.QuadPart = Int32x32To64(dwTimerInterval, -10000);
|
|
|
|
if (INVALID_HANDLE_VALUE != hAdTimer) {
|
|
|
|
pfnSetWaitableTimer(
|
|
hAdTimer,
|
|
&DueTime,
|
|
dwTimerInterval,
|
|
AdvertiseTimerFired,
|
|
0, // arg to compl. rtn
|
|
TRUE
|
|
);
|
|
}
|
|
}
|
|
}
|