277 lines
7.6 KiB
C++
277 lines
7.6 KiB
C++
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ConfParm.c
|
||
|
||
Abstract:
|
||
|
||
This file contains:
|
||
ScCheckServiceConfigParms
|
||
|
||
|
||
Author:
|
||
|
||
John Rogers (JohnRo) 14-Apr-1992
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
14-Apr-1992 JohnRo
|
||
Created.
|
||
20-May-1992 JohnRo
|
||
Use CONST where possible.
|
||
09-Dec-1996 AnirudhS
|
||
Added SC_LOG printouts to help diagnose the annoying
|
||
ERROR_INVALID_PARAMETER and ERROR_INVALID_SERVICE_ACCOUNT return codes.
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// INCLUDES
|
||
//
|
||
|
||
#include <scpragma.h>
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h> // Needed by <scdebug.h>
|
||
#include <nturtl.h>
|
||
#include <stdlib.h> // wcsicmp
|
||
|
||
#include <windef.h>
|
||
#include <winbase.h> // GetCurrentThreadId, for SC_LOG
|
||
|
||
#include <scdebug.h> // SC_ASSERT().
|
||
#include <sclib.h> // My prototype.
|
||
#include <valid.h> // ERROR_CONTROL_INVALID(), SERVICE_TYPE_INVALID(), etc.
|
||
#include <winerror.h> // NO_ERROR and ERROR_ equates.
|
||
#include <winsvc.h> // SERVICE_ equates.
|
||
|
||
|
||
|
||
DWORD
|
||
ScCheckServiceConfigParms(
|
||
IN BOOL Change,
|
||
IN LPCWSTR lpServiceName,
|
||
IN DWORD dwActualServiceType,
|
||
IN DWORD dwNewServiceType,
|
||
IN DWORD dwStartType,
|
||
IN DWORD dwErrorControl,
|
||
IN LPCWSTR lpBinaryPathName OPTIONAL,
|
||
IN LPCWSTR lpLoadOrderGroup OPTIONAL,
|
||
IN LPCWSTR lpDependencies OPTIONAL,
|
||
IN DWORD dwDependSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks parameters for a CreateService() or a
|
||
ChangeServiceConfig() API.
|
||
|
||
Arguments:
|
||
|
||
Change - TRUE if this is the result of a ChangeServiceConfig API.
|
||
(This flag is used to determine whether other parameters may be
|
||
SERVICE_NO_CHANGE or NULL pointers.)
|
||
|
||
dwActualServiceType - For ChangeServiceConfig, contains the current
|
||
service type associated with this service. Otherwise, this is
|
||
the same value as dwNewServiceType.
|
||
|
||
dwNewServiceType - SERVICE_NO_CHANGE or the service type given by app.
|
||
|
||
(Other parameters same as CreateService and ChangeServiceConfig APIs.)
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwFinalServiceType;
|
||
|
||
#define PARM_MISSING( ws ) ( ((ws)==NULL) || ((*(ws)) == L'\0') )
|
||
|
||
if ( !Change ) {
|
||
|
||
//
|
||
// Almost all fields must be present for creating a service.
|
||
// (Exceptions are dependencies and password.)
|
||
//
|
||
if ( (dwNewServiceType == SERVICE_NO_CHANGE) ||
|
||
(dwStartType == SERVICE_NO_CHANGE) ||
|
||
(dwErrorControl == SERVICE_NO_CHANGE) ||
|
||
PARM_MISSING(lpBinaryPathName) ) {
|
||
|
||
SC_LOG0(ERROR, "ServiceType, StartType, ErrorControl or BinPath missing\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Validate actual and desired service types.
|
||
//
|
||
if (dwNewServiceType != SERVICE_NO_CHANGE) {
|
||
if ( SERVICE_TYPE_INVALID( dwNewServiceType ) ) {
|
||
SC_LOG0(ERROR, "ServiceType invalid\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// Not allowed to change the service type from Win32 to Driver
|
||
// or Driver to Win32.
|
||
//
|
||
if ( ((dwNewServiceType & SERVICE_DRIVER) &&
|
||
(dwActualServiceType & SERVICE_WIN32)) ||
|
||
((dwNewServiceType & SERVICE_WIN32) &&
|
||
(dwActualServiceType & SERVICE_DRIVER)) ) {
|
||
SC_LOG0(ERROR, "Can't change service type between Win32 and Driver\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
if (dwActualServiceType == SERVICE_NO_CHANGE) {
|
||
SC_LOG0(ERROR, "Current ServiceType missing\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// Validate start type (if that was given).
|
||
//
|
||
if (dwStartType != SERVICE_NO_CHANGE) {
|
||
|
||
if ( START_TYPE_INVALID( dwStartType ) ) {
|
||
SC_LOG0(ERROR, "StartType invalid\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// A boot-start or system-start service must be a driver
|
||
//
|
||
if (dwStartType == SERVICE_BOOT_START ||
|
||
dwStartType == SERVICE_SYSTEM_START) {
|
||
|
||
if (dwNewServiceType == SERVICE_NO_CHANGE) {
|
||
|
||
if (dwActualServiceType != SERVICE_KERNEL_DRIVER &&
|
||
dwActualServiceType != SERVICE_FILE_SYSTEM_DRIVER) {
|
||
|
||
SC_LOG0(ERROR, "StartType is boot or system but service is not a driver\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
else {
|
||
if (dwNewServiceType != SERVICE_KERNEL_DRIVER &&
|
||
dwNewServiceType != SERVICE_FILE_SYSTEM_DRIVER) {
|
||
|
||
SC_LOG0(ERROR, "StartType is boot or system but ServiceType is not driver\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Validate error control...
|
||
//
|
||
if (dwErrorControl != SERVICE_NO_CHANGE) {
|
||
if ( ERROR_CONTROL_INVALID( dwErrorControl ) ) {
|
||
SC_LOG0(ERROR, "ErrorControl invalid\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Path type depends on final service type.
|
||
//
|
||
if (dwNewServiceType == SERVICE_NO_CHANGE) {
|
||
dwFinalServiceType = dwActualServiceType;
|
||
} else {
|
||
dwFinalServiceType = dwNewServiceType;
|
||
}
|
||
SC_ASSERT( dwFinalServiceType != SERVICE_NO_CHANGE );
|
||
|
||
//
|
||
// Validate binary path name.
|
||
//
|
||
if (lpBinaryPathName != NULL) {
|
||
|
||
// Check path name syntax and make sure it matches service type.
|
||
// Path type depends on final service type.
|
||
if ( !ScIsValidImagePath( lpBinaryPathName, dwFinalServiceType ) ) {
|
||
SC_LOG0(ERROR, "ImagePath invalid for this service type\n");
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check for trivial cases of circular dependencies:
|
||
// 1) Service is dependent on itself
|
||
// 2) Service is dependent on a group it is a member of
|
||
//
|
||
LPWSTR DependPtr = (LPWSTR) lpDependencies;
|
||
|
||
if (DependPtr != NULL && (*DependPtr != L'\0'))
|
||
{
|
||
DWORD dwError = ScValidateMultiSZ(DependPtr, dwDependSize);
|
||
|
||
if (dwError != NO_ERROR)
|
||
{
|
||
SC_LOG(ERROR,
|
||
"ScCheckServiceConfigParms: Invalid dependencies %d\n",
|
||
dwError);
|
||
|
||
return dwError;
|
||
}
|
||
|
||
while (*DependPtr != 0) {
|
||
|
||
if (*DependPtr == SC_GROUP_IDENTIFIERW) {
|
||
|
||
if ((lpLoadOrderGroup != NULL) && (*lpLoadOrderGroup != 0)) {
|
||
|
||
if (_wcsicmp(DependPtr + 1, lpLoadOrderGroup) == 0) {
|
||
|
||
//
|
||
// Service depends on the group it is in
|
||
//
|
||
SC_LOG0(ERROR, "Service depends on the group it is in\n");
|
||
return (ERROR_CIRCULAR_DEPENDENCY);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
|
||
if (_wcsicmp(DependPtr, lpServiceName) == 0) {
|
||
|
||
//
|
||
// Service depends on itself
|
||
//
|
||
SC_LOG0(ERROR, "Service depends on itself\n");
|
||
return (ERROR_CIRCULAR_DEPENDENCY);
|
||
}
|
||
}
|
||
|
||
DependPtr += (wcslen(DependPtr) + 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Start name is checked and canonicalized in ScValidateAndSaveAccount
|
||
// if service type is Win32. If service type is driver, it's up to
|
||
// the I/O system to validate the driver name (it can be NULL and the
|
||
// I/O system will use the default driver name).
|
||
//
|
||
|
||
return (NO_ERROR);
|
||
}
|