mirror of https://github.com/tongzx/nt5src
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.
276 lines
7.6 KiB
276 lines
7.6 KiB
/*++
|
|
|
|
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);
|
|
}
|