Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

581 lines
14 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
rcmdsvc.c
Abstract:
This is the remote command service. It serves multiple remote clients
running standard i/o character based programs.
Author:
Dave Thompson, basically incorporating the remote command shell written
by David Chalmers.
Environment:
User Mode -Win32
Revision History:
5/1/94 DaveTh Created.
7/30/96 MarkHar Fixed bug 40834 - "doesn't work on NT4.0"
Removed function calls within asserts.
1/31/99 MarkHar bug about install not working
6/22/99 MarkHar added usage message
--*/
//
// Includes
//
#include <nt.h>
#include <ntrtl.h>
#include <windef.h>
#include <nturtl.h>
#include <winbase.h>
#include <winsvc.h>
#include "rcmdsrv.h"
//
// Defines
//
#define INFINITE_WAIT_TIME 0xFFFFFFFF
#define NULL_STRING TEXT("");
//
// Globals
//
SERVICE_STATUS RcmdStatus;
SERVICE_STATUS_HANDLE RcmdStatusHandle;
//
// Events for syncrhonizing service shutdown
//
HANDLE RcmdStopEvent = NULL;
HANDLE RcmdStopCompleteEvent = NULL;
HANDLE SessionThreadHandles[MAX_SESSIONS+1] = {NULL,};
//
// Flag to enable debug print
//
// BOOLEAN RcDbgPrintEnable = FALSE;
//
// Function Prototypes
//
VOID
RcmdStart (
DWORD argc,
LPTSTR *argv
);
VOID
RcmdCtrlHandler (
IN DWORD opcode
);
DWORD
RcmdInitialization(
DWORD argc,
LPTSTR *argv,
DWORD *specificError
);
void CmdInstallService(void);
void CmdRemoveService();
void Usage(void);
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
/****************************************************************************/
VOID __cdecl
main(int argc, char ** argv)
/*++
Routine Description:
This is the main routine for the service RCMD process.
This thread calls StartServiceCtrlDispatcher which connects to the
service controller and then waits in a loop for control requests.
When all the services in the service process have terminated, the
service controller will send a control request to the dispatcher
telling it to shut down. This thread with then return from the
StartServiceCtrlDispatcher call so that the process can terminate.
Arguments:
Return Value:
--*/
{
DWORD status;
char *szArgument = NULL;
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ TEXT("Remote Command"), RcmdStart },
{ NULL, NULL }
};
if (argc > 1)
{
if ((*argv[1] == '-') || (*argv[1] == '/'))
{
szArgument = argv[1]+1;
if (_stricmp("install", szArgument) == 0)
{
CmdInstallService();
}
else if (_stricmp("uninstall", szArgument) == 0)
{
CmdRemoveService();
}
else
{
Usage();
}
}
}
else
{
status = StartServiceCtrlDispatcher( DispatchTable);
}
ExitProcess(0);
}
void Usage(void)
{
char *szUsage = "usage: rcmdsvc\n"
"rcmdsvc [[-/] [install | uninstall | H]]\n"
"\tinstall - registers the service with the service controller\n"
"\tuninstall - unregisters the service with the service controller\n"
"\tHh? - prints this usage message\n";
fprintf(stdout, szUsage);
}
void CmdInstallService()
/*++
Routine Description:
Arguments:
None
Return Value:
None
--*/
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szErr[256];
TCHAR szPath[512];
if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
{
printf(TEXT("Unable to install %s - %s\n"),
TEXT("Remote Command"),
GetLastErrorText(szErr, 256));
return;
}
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if ( schSCManager )
{
schService = CreateService(
schSCManager, // SCManager database
TEXT("rcmdsvc"), // name of service
TEXT("Remote Command Service"), // name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // dependencies
NULL, // LocalSystem account
NULL); // no password
if ( schService )
{
printf(TEXT("%s installed.\n"), TEXT("Remote Command Service") );
CloseServiceHandle(schService);
}
else
{
printf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
}
CloseServiceHandle(schSCManager);
}
else
printf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
}
void CmdRemoveService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szErr[256];
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if ( schSCManager )
{
schService = OpenService(schSCManager,
TEXT("rcmdsvc"),
SERVICE_ALL_ACCESS);
if (schService)
{
// try to stop the service
if ( ControlService( schService,
SERVICE_CONTROL_STOP,
&RcmdStatus ) )
{
printf(TEXT("Stopping %s."), TEXT("Remote Command Service"));
Sleep( 1000 );
while( QueryServiceStatus( schService, &RcmdStatus ) )
{
if ( RcmdStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
printf(TEXT("."));
Sleep( 1000 );
}
else {
break;
}
}
if ( RcmdStatus.dwCurrentState == SERVICE_STOPPED ) {
printf(TEXT("\n%s stopped.\n"),
TEXT("Remote Command Service") );
}
else {
printf(TEXT("\n%s failed to stop.\n"),
TEXT("Remote Command Service") );
}
}
// now remove the service
if( DeleteService(schService) ) {
printf(TEXT("%s removed.\n"),
TEXT("Remote Command Service") );
}
else {
printf(TEXT("DeleteService failed - %s\n"),
GetLastErrorText(szErr,256));
}
CloseServiceHandle(schService);
}
else {
printf(TEXT("OpenService failed -\n%s\n"),
GetLastErrorText(szErr,256));
printf(TEXT("The service must be installed before removing it."));
}
CloseServiceHandle(schSCManager);
}
else {
printf(TEXT("OpenSCManager failed - %s\n"),
GetLastErrorText(szErr,256));
}
}
/****************************************************************************/
void
RcmdStart (
DWORD argc,
LPTSTR *argv
)
/*++
Routine Description:
This is the entry point for the service. When the control dispatcher
is told to start a service, it creates a thread that will begin
executing at this point. The function has access to command line
arguments in the same manner as a main() routine.
Rather than return from this function, it is more appropriate to
call ExitThread().
Arguments:
Return Value:
--*/
{
DWORD status;
DWORD specificError;
//
// Initialize the services status structure
//
RcmdStatus.dwServiceType = SERVICE_WIN32;
RcmdStatus.dwCurrentState = SERVICE_START_PENDING;
RcmdStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; // stop only
RcmdStatus.dwWin32ExitCode = 0;
RcmdStatus.dwServiceSpecificExitCode = 0;
RcmdStatus.dwCheckPoint = 0;
RcmdStatus.dwWaitHint = 0;
//
// Register the Control Handler routine.
//
RcmdStatusHandle = RegisterServiceCtrlHandler(
TEXT("Remote Command"),
RcmdCtrlHandler);
if (RcmdStatusHandle == (SERVICE_STATUS_HANDLE)0) {
RcDbgPrint(" [Rcmd] RegisterServiceCtrlHandler failed %d\n",
GetLastError());
}
//
// Initialize service global structures
//
status = RcmdInitialization(argc,argv, &specificError);
if (status != NO_ERROR) {
RcmdStatus.dwCurrentState = SERVICE_RUNNING;
RcmdStatus.dwCheckPoint = 0;
RcmdStatus.dwWaitHint = 0;
RcmdStatus.dwWin32ExitCode = status;
RcmdStatus.dwServiceSpecificExitCode = specificError;
SetServiceStatus (RcmdStatusHandle, &RcmdStatus);
ExitThread(NO_ERROR);
return;
}
//
// Return the status to indicate we are done with intialization.
//
RcmdStatus.dwCurrentState = SERVICE_RUNNING;
RcmdStatus.dwCheckPoint = 0;
RcmdStatus.dwWaitHint = 0;
if (!SetServiceStatus (RcmdStatusHandle, &RcmdStatus)) {
status = GetLastError();
RcDbgPrint(" [Rcmd] SetServiceStatus error %ld\n",status);
}
//
// Run remote command processor - return when shutdown
//
if (0 != (status = Rcmd()))
{
RcDbgPrint(" [Rcmd]: problem occurred in Rcmd()\n");
RcmdStatus.dwCurrentState = SERVICE_STOPPED;
RcmdStatus.dwCheckPoint = 0;
RcmdStatus.dwWaitHint = 0;
RcmdStatus.dwWin32ExitCode = status;
SetServiceStatus(RcmdStatusHandle, &RcmdStatus);
ExitThread(status);
}
else
{
RcDbgPrint(" [Rcmd] Leaving My Service \n");
ExitThread(NO_ERROR);
}
}
/****************************************************************************/
VOID
RcmdCtrlHandler (
IN DWORD Opcode
)
/*++
Routine Description:
This function executes in the context of the Control Dispatcher's
thread. Therefore, it it not desirable to perform time-consuming
operations in this function.
If an operation such as a stop is going to take a long time, then
this routine should send the STOP_PENDING status, and then
signal the other service thread(s) that a shut-down is in progress.
Then it should return so that the Control Dispatcher can service
more requests. One of the other service threads is then responsible
for sending further wait hints, and the final SERVICE_STOPPED.
Arguments:
Return Value:
--*/
{
DWORD status;
//
// Find and operate on the request.
//
switch(Opcode) {
case SERVICE_CONTROL_PAUSE:
RcDbgPrint(" [Rcmd] Pause - Unsupported opcode\n");
break;
case SERVICE_CONTROL_CONTINUE:
RcDbgPrint(" [Rcmd] Continue - Unsupported opcode\n");
break;
case SERVICE_CONTROL_STOP:
RcmdStatus.dwCurrentState = SERVICE_STOPPED;
RcmdStatus.dwWin32ExitCode = RcmdStop();
break;
case SERVICE_CONTROL_INTERROGATE:
//
// All that needs to be done in this case is to send the
// current status.
//
break;
default:
RcDbgPrint(" [Rcmd] Unrecognized opcode %ld\n", Opcode);
}
//
// Send a status response.
//
if (!SetServiceStatus (RcmdStatusHandle, &RcmdStatus)) {
status = GetLastError();
RcDbgPrint(" [Rcmd] SetServiceStatus error %ld\n",status);
}
}
DWORD
RcmdInitialization(
DWORD argc,
LPTSTR *argv,
DWORD *specificError)
{
UNREFERENCED_PARAMETER(argv);
UNREFERENCED_PARAMETER(argc);
//
// Initialize global stop event (signals running threads) and session
// thread handle array (for threads to signal back on exit).
//
if (!(RcmdStopEvent = CreateEvent ( NULL, TRUE, FALSE, NULL ))) {
*specificError = GetLastError();
return(*specificError);
}
if (!(RcmdStopCompleteEvent = CreateEvent ( NULL, TRUE, FALSE, NULL ))) {
*specificError = GetLastError();
return(*specificError);
}
return(NO_ERROR);
}
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
{
DWORD dwRet;
LPTSTR lpszTemp = NULL;
dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&lpszTemp,
0,
NULL );
// supplied buffer is not long enough
if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
lpszBuf[0] = TEXT('\0');
else
{
lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
sprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
}
if ( lpszTemp )
LocalFree((HLOCAL) lpszTemp );
return lpszBuf;
}