605 lines
17 KiB
C
605 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
SvcStub.c (was scstub.c)
|
||
|
||
Abstract:
|
||
|
||
These are the Service Controller API RPC client stubs.
|
||
|
||
These stubs contain RPC work-around code due to the fact that RPC
|
||
does not support unions yet. Therefore, a remote entry point must be
|
||
created for every info-level. This results in messy looking switch
|
||
statements that are used to determine which entry point to call.
|
||
|
||
These switch statements include default paths that can currently cause
|
||
an error. When unions are available, the case statements will be
|
||
removed, and this side of the API will not make any assumptions as to
|
||
what a valid info level is for a given API.
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 06-Feb-1991
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
06-Feb-1991 Danl
|
||
Created
|
||
12-Sep-1991 JohnRo
|
||
Downlevel NetService APIs.
|
||
06-Nov-1991 JohnRo
|
||
RAID 4186: Fix assert in RxNetShareAdd and other MIPS problems.
|
||
Use NetpRpcStatusToApiStatus, not NetpNtStatusToApiStatus.
|
||
Make sure API name is in every debug message.
|
||
08-Nov-1991 JohnRo
|
||
RAID 4186: assert in RxNetShareAdd and other DLL stub problems.
|
||
30-Mar-1992 JohnRo
|
||
Extracted DanL's code from /nt/private project back to NET project.
|
||
29-Apr-1992 JohnRo
|
||
Use FORMAT_ equates where possible.
|
||
08-May-1992 JohnRo
|
||
Translate service names on the fly.
|
||
14-May-1992 JohnRo
|
||
winsvc.h and related file cleanup.
|
||
06-Aug-1992 JohnRo
|
||
RAID 3021: NetService APIs don't always translate svc names.
|
||
09-Sep-1992 JohnRo
|
||
RAID 1090: net start/stop "" causes assertion.
|
||
Oops, NetServiceControl forgot to translate one more svc name.
|
||
05-Nov-1992 JohnRo
|
||
RAID 7780: Corrected error code for invalid level.
|
||
Also fixed overactive assert in NetServiceEnum with no services.
|
||
Also fixed rare memory leaks.
|
||
|
||
--*/
|
||
|
||
//
|
||
// INCLUDES
|
||
//
|
||
|
||
#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
|
||
#include <windows.h> // DWORD, etc.
|
||
|
||
#include <lmcons.h> // NET_API_STATUS
|
||
#include <rpcutil.h> // NetRpc utils, GENERIC_ENUM_STRUC, etc.
|
||
|
||
#include <netdebug.h> // Needed by NetRpc.h; FORMAT_ equates.
|
||
#include <lmapibuf.h> // NetApiBufferAllocate(), etc.
|
||
#include <lmerr.h> // NetError codes
|
||
#include <lmremutl.h> // NetRemoteComputerSupports(), SUPPORTS_RPC
|
||
#include <lmsvc.h>
|
||
#include <rxsvc.h> // RxNetService routines.
|
||
|
||
#include <netlib.h> // NetpTranslateServiceName().
|
||
#include <svcdebug.h> // SCC_LOG
|
||
#include <svcmap.h> // MapService() routines.
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
#ifdef SC_DEBUG
|
||
DWORD SvcctrlDebugLevel = DEBUG_ALL;
|
||
#else
|
||
DWORD SvcctrlDebugLevel = DEBUG_ERROR;
|
||
#endif
|
||
|
||
|
||
DBGSTATIC BOOL
|
||
MachineSupportsNt(
|
||
IN LPWSTR UncServerName OPTIONAL
|
||
);
|
||
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetServiceControl (
|
||
IN LPCWSTR servername OPTIONAL,
|
||
IN LPCWSTR service,
|
||
IN DWORD opcode,
|
||
IN DWORD arg,
|
||
OUT LPBYTE *bufptr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the DLL entrypoint for NetServiceControl.
|
||
|
||
Arguments:
|
||
|
||
servername - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
service - Pointer to a string containing the name of the service
|
||
that is to receive the control request.
|
||
|
||
opcode - The control request code.
|
||
|
||
arg - An additional (user defined) code that will be passed to the
|
||
service.
|
||
|
||
bufptr - pointer to a location where the service status is to
|
||
be returned. If this pointer is invalid, it will be set to NULL
|
||
upon return.
|
||
|
||
Return Value:
|
||
|
||
The returned InfoStruct2 structure is valid as long as the returned
|
||
error is NOT NERR_ServiceNotInstalled or NERR_ServiceBadServiceName.
|
||
|
||
NERR_Success - The operation was successful.
|
||
|
||
NERR_InternalError - LocalAlloc or TransactNamedPipe failed, or
|
||
TransactNamedPipe returned fewer bytes than expected.
|
||
|
||
NERR_ServiceNotInstalled - The service record was not found in the
|
||
installed list.
|
||
|
||
NERR_BadServiceName - The service name pointer was NULL.
|
||
|
||
NERR_ServiceCtlTimeout - The service did not respond with a status
|
||
message within the fixed timeout limit (RESPONSE_WAIT_TIMEOUT).
|
||
|
||
NERR_ServiceKillProcess - The service process had to be killed because
|
||
it wouldn't terminate when requested.
|
||
|
||
NERR_ServiceNotCtrl - The service cannot accept control messages.
|
||
The install state indicates that start-up or shut-down is pending.
|
||
|
||
NERR_ServiceCtrlNotValid - The request is not valid for this service.
|
||
For instance, a PAUSE request is not valid for a service that
|
||
lists itself as NOT_PAUSABLE.
|
||
|
||
ERROR_ACCESS_DENIED - This is a status response from the service
|
||
security check.
|
||
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS apiStatus;
|
||
LPWSTR translatedServiceName;
|
||
LPBYTE untranslatedBuffer = NULL;
|
||
|
||
if (MachineSupportsNt( (LPWSTR) servername )) {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
TRUE, // yes, we want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
apiStatus = MapServiceControl (
|
||
(LPWSTR) servername,
|
||
(LPWSTR) service,
|
||
opcode,
|
||
arg,
|
||
& untranslatedBuffer);
|
||
|
||
} else {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
FALSE, // no, we don't want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
//
|
||
// Call downlevel...
|
||
//
|
||
apiStatus = RxNetServiceControl(
|
||
(LPWSTR) servername,
|
||
translatedServiceName,
|
||
opcode,
|
||
arg,
|
||
& untranslatedBuffer);
|
||
|
||
}
|
||
|
||
//
|
||
// Translate service name in returned buffer.
|
||
//
|
||
if (apiStatus == NO_ERROR) {
|
||
|
||
NetpAssert( untranslatedBuffer != NULL );
|
||
apiStatus = NetpTranslateNamesInServiceArray(
|
||
2, // level 2 by definition
|
||
untranslatedBuffer,
|
||
1, // only one entry
|
||
TRUE, // yes, caller wants new style names
|
||
(LPVOID *) (LPVOID) bufptr);
|
||
|
||
}
|
||
|
||
if (untranslatedBuffer != NULL) {
|
||
(VOID) NetApiBufferFree( untranslatedBuffer );
|
||
}
|
||
|
||
return(apiStatus);
|
||
}
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetServiceEnum (
|
||
IN LPCWSTR servername OPTIONAL,
|
||
IN DWORD level,
|
||
OUT LPBYTE *bufptr,
|
||
IN DWORD prefmaxlen,
|
||
OUT LPDWORD entriesread,
|
||
OUT LPDWORD totalentries,
|
||
IN OUT LPDWORD resume_handle OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the DLL entrypoint for NetSeviceEnum.
|
||
|
||
Arguments:
|
||
|
||
servername - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
level - This indicates the level of information that is desired.
|
||
|
||
bufptr - A pointer to the location where the pointer to the returned
|
||
array of info structures is to be placed.
|
||
|
||
prefmaxlen - Indicates a maximum size limit that the caller will allow
|
||
for the return buffer.
|
||
|
||
entriesread - A pointer to the location where the number of entries
|
||
(data structures)read is to be returned.
|
||
|
||
totalentries - A pointer to the location which upon return indicates
|
||
the total number of entries in the "active" database.
|
||
|
||
resumehandle - Pointer to a value that indicates where to resume
|
||
enumerating data.
|
||
|
||
Return Value:
|
||
|
||
Nerr_Success - The operation was successful.
|
||
|
||
ERROR_MORE_DATA - Not all of the data in the active database could be
|
||
returned.
|
||
|
||
ERROR_INVALID_LEVEL - An illegal info Level was passed in.
|
||
|
||
Note:
|
||
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS apiStatus;
|
||
LPBYTE untranslatedBuffer = NULL;
|
||
|
||
|
||
if (MachineSupportsNt( (LPWSTR) servername )) {
|
||
|
||
apiStatus = MapServiceEnum (
|
||
(LPWSTR) servername,
|
||
level,
|
||
& untranslatedBuffer,
|
||
prefmaxlen,
|
||
entriesread,
|
||
totalentries,
|
||
resume_handle);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Call downlevel...
|
||
//
|
||
apiStatus = RxNetServiceEnum(
|
||
(LPWSTR) servername,
|
||
level,
|
||
& untranslatedBuffer,
|
||
prefmaxlen,
|
||
entriesread,
|
||
totalentries,
|
||
resume_handle);
|
||
|
||
}
|
||
|
||
//
|
||
// Translate service names in returned buffer.
|
||
//
|
||
if ( (apiStatus == NO_ERROR) || (apiStatus == ERROR_MORE_DATA) ) {
|
||
|
||
if ( (*entriesread) > 0 ) { // One or more services returned.
|
||
NetpAssert( untranslatedBuffer != NULL );
|
||
NetpAssert( (*totalentries) > 0 );
|
||
|
||
apiStatus = NetpTranslateNamesInServiceArray(
|
||
level,
|
||
untranslatedBuffer,
|
||
*entriesread,
|
||
TRUE, // yes, caller wants new style names
|
||
(LPVOID *) (LPVOID) bufptr);
|
||
|
||
} else { // Zero services returned.
|
||
NetpAssert( untranslatedBuffer == NULL );
|
||
// Note: total entries may be > 0, if this is ERROR_MORE_DATA...
|
||
*bufptr = NULL;
|
||
}
|
||
}
|
||
|
||
if (untranslatedBuffer != NULL) {
|
||
(VOID) NetApiBufferFree( untranslatedBuffer );
|
||
}
|
||
|
||
return(apiStatus);
|
||
|
||
} // NetServiceEnum
|
||
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetServiceGetInfo (
|
||
IN LPCWSTR servername OPTIONAL,
|
||
IN LPCWSTR service,
|
||
IN DWORD level,
|
||
OUT LPBYTE *bufptr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the DLL entrypoint for NetServiceGetInfo.
|
||
|
||
Arguments:
|
||
|
||
servername - Pointer to a string containing the name of the computer
|
||
that is to execute the API function. Since this function is
|
||
executing on that computer, this information is not useful
|
||
by the time it gets here. It is really only useful on the RPC
|
||
client side.
|
||
|
||
service - Pointer to a string containing the name of the service
|
||
for which information is desired.
|
||
|
||
level - This indicates the level of information that is desired.
|
||
|
||
bufptr - Pointer to a Location where the pointer to the returned
|
||
information structure is to be placed.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful.
|
||
|
||
NERR_ServiceNotInstalled - if the service record was not found in
|
||
either the installed or uninstalled lists.
|
||
|
||
NERR_BadServiceName - The service name pointer was NULL.
|
||
|
||
ERROR_INVALID_LEVEL - An illegal info level was passed in.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - The memory allocation for the returned
|
||
Info Record failed.
|
||
|
||
other - Any error returned by the following base API:
|
||
RPC Runtime API
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS apiStatus;
|
||
LPWSTR translatedServiceName;
|
||
LPBYTE untranslatedBuffer = NULL;
|
||
|
||
if (MachineSupportsNt( (LPWSTR) servername )) {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
TRUE, // yes, we want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
apiStatus = MapServiceGetInfo (
|
||
(LPWSTR) servername,
|
||
(LPWSTR) service,
|
||
level,
|
||
& untranslatedBuffer);
|
||
|
||
} else {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
FALSE, // no, we don't want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
//
|
||
// Call downlevel...
|
||
//
|
||
apiStatus = RxNetServiceGetInfo(
|
||
(LPWSTR) servername,
|
||
translatedServiceName,
|
||
level,
|
||
& untranslatedBuffer);
|
||
|
||
}
|
||
|
||
//
|
||
// Translate service name in returned buffer.
|
||
//
|
||
if (apiStatus == NO_ERROR) {
|
||
|
||
NetpAssert( untranslatedBuffer != NULL );
|
||
apiStatus = NetpTranslateNamesInServiceArray(
|
||
level,
|
||
untranslatedBuffer,
|
||
1, // only one entry
|
||
TRUE, // yes, caller wants new style names
|
||
(LPVOID *) (LPVOID) bufptr);
|
||
|
||
}
|
||
|
||
if (untranslatedBuffer != NULL) {
|
||
(VOID) NetApiBufferFree( untranslatedBuffer );
|
||
}
|
||
|
||
return(apiStatus);
|
||
}
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetServiceInstall (
|
||
IN LPCWSTR servername OPTIONAL,
|
||
IN LPCWSTR service,
|
||
IN DWORD argc,
|
||
IN LPCWSTR argv[],
|
||
OUT LPBYTE *bufptr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the DLL entrypoint for NetServiceInstall.
|
||
|
||
Arguments:
|
||
|
||
servername - Points to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
service- Points to a string containing the name of the service
|
||
that is to be started.
|
||
|
||
argc - Indicates the number or argument vectors in argv.
|
||
|
||
argv - A pointer to an array of pointers to strings. These
|
||
are command line arguments that are to be passed to the service.
|
||
|
||
bufptr - This is the address where a pointer to the service's
|
||
information buffer (SERVICE_INFO_2) is to be placed.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful
|
||
|
||
NERR_InternalError - There is a bug in this program somewhere.
|
||
|
||
NERR_ServiceInstalled - The service is already running - we do not
|
||
yet allow multiple instances of the same service.
|
||
|
||
NERR_CfgCompNotFound - The configuration component could not be found.
|
||
The Image File could not be found for this service.
|
||
|
||
NERR_ServiceTableFull - The maximum number of running services has
|
||
already been reached.
|
||
|
||
NERR_ServiceCtlTimeout - The service program did not respond to the
|
||
start-up request within the timeout period. If this was the
|
||
only service in the service process, the service process was
|
||
killed.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - If this error occurs early in the
|
||
start-up procedure, the start-up will fail. If it occurs at the
|
||
end (allocating the return status buffer), the service will still
|
||
be started and allowed to run.
|
||
|
||
other - Any error returned by the following base API:
|
||
CreateNamedPipe
|
||
ConnectNamedPipe
|
||
CreateProcess
|
||
TransactNamedPipe
|
||
RPC Runtime API
|
||
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS apiStatus;
|
||
LPWSTR translatedServiceName;
|
||
LPBYTE untranslatedBuffer = NULL;
|
||
|
||
|
||
if (MachineSupportsNt( (LPWSTR) servername )) {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
TRUE, // yes, we want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
apiStatus = MapServiceInstall (
|
||
(LPWSTR) servername,
|
||
(LPWSTR) service,
|
||
argc,
|
||
(LPWSTR *) argv,
|
||
& untranslatedBuffer);
|
||
|
||
} else {
|
||
|
||
apiStatus = NetpTranslateServiceName(
|
||
(LPWSTR) service, // untranslated.
|
||
FALSE, // no, we don't want new style name
|
||
& translatedServiceName );
|
||
NetpAssert( apiStatus == NO_ERROR );
|
||
|
||
//
|
||
// Call downlevel....
|
||
//
|
||
apiStatus = RxNetServiceInstall(
|
||
(LPWSTR) servername,
|
||
translatedServiceName,
|
||
argc,
|
||
(LPWSTR *) argv,
|
||
& untranslatedBuffer);
|
||
|
||
}
|
||
|
||
//
|
||
// Translate service name in returned buffer.
|
||
//
|
||
if (apiStatus == NO_ERROR) {
|
||
|
||
NetpAssert( untranslatedBuffer != NULL );
|
||
apiStatus = NetpTranslateNamesInServiceArray(
|
||
2, // level 2 by definition
|
||
untranslatedBuffer,
|
||
1, // only one entry
|
||
TRUE, // yes, caller wants new style names
|
||
(LPVOID *) (LPVOID) bufptr);
|
||
|
||
}
|
||
|
||
if (untranslatedBuffer != NULL) {
|
||
(VOID) NetApiBufferFree( untranslatedBuffer );
|
||
}
|
||
|
||
return(apiStatus);
|
||
}
|
||
|
||
|
||
DBGSTATIC BOOL
|
||
MachineSupportsNt(
|
||
IN LPWSTR UncServerName OPTIONAL
|
||
)
|
||
{
|
||
NET_API_STATUS ApiStatus;
|
||
DWORD ActualSupports;
|
||
|
||
ApiStatus = NetRemoteComputerSupports(
|
||
UncServerName,
|
||
SUPPORTS_RPC, // Set SUPPORT_ bits wanted.
|
||
& ActualSupports );
|
||
|
||
if (ApiStatus != NO_ERROR) {
|
||
return (FALSE); // Error; say it doesn't support NT, and someone else
|
||
// will set the correct error code.
|
||
}
|
||
if (ActualSupports & SUPPORTS_RPC) {
|
||
return (TRUE);
|
||
}
|
||
return (FALSE);
|
||
|
||
} // MachineSupportsNt
|