614 lines
16 KiB
C++
614 lines
16 KiB
C++
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dataman.h
|
|
|
|
Abstract:
|
|
|
|
Contains data structures and function prototypes for the Service
|
|
Controller Database Manager and the Group List Database Manager.
|
|
(Dataman.c & Groupman.c)
|
|
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 22-Oct-1993
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
04-Dec-1996 AnirudhS
|
|
Added CCrashRecord.
|
|
|
|
17-Aug-1995 AnirudhS
|
|
Removed State field from LOAD_ORDER_GROUP, since it is recomputed
|
|
every time it is read.
|
|
|
|
26-Jun-1995 AnirudhS
|
|
Added ScNotifyServiceObject.
|
|
|
|
12-Apr-1995 AnirudhS
|
|
Added AccountName field to image record.
|
|
|
|
06-Oct-1993 danl
|
|
Re-arranged comments so that structures are easier to read.
|
|
|
|
19-Jan-1992 danl
|
|
Modified for use with the "real" service controller
|
|
|
|
20-Mar-1991 danl
|
|
created
|
|
--*/
|
|
|
|
#ifndef SCDATAMAN_INCLUDED
|
|
#define SCDATAMAN_INCLUDED
|
|
|
|
#define USE_GROUPS
|
|
|
|
//
|
|
// ImageFlag definitions
|
|
//
|
|
#define CANSHARE_FLAG 0x00000001 // service can run in a shared process
|
|
#define IS_SYSTEM_SERVICE 0x00000002 // service runs in this exe or the security process
|
|
|
|
//
|
|
// StatusFlag definitions
|
|
//
|
|
#define DELETE_FLAG 0x00000001 // service is marked for delete
|
|
#define UPDATE_FLAG 0x00000002 //
|
|
#define CURRENTSTART_FLAG 0x00000004 //
|
|
|
|
//
|
|
// StatusFlag Macros. SR = ServiceRecord
|
|
//
|
|
|
|
#define SET_DELETE_FLAG(SR) (((SR)->StatusFlag) |= DELETE_FLAG)
|
|
#define CLEAR_DELETE_FLAG(SR) (((SR)->StatusFlag) &= (~DELETE_FLAG))
|
|
#define DELETE_FLAG_IS_SET(SR) (((SR)->StatusFlag) & DELETE_FLAG)
|
|
|
|
#define SET_UPDATE_FLAG(SR) (((SR)->StatusFlag) |= UPDATE_FLAG)
|
|
#define CLEAR_UPDATE_FLAG(SR) (((SR)->StatusFlag) &= (~UPDATE_FLAG))
|
|
#define UPDATE_FLAG_IS_SET(SR) (((SR)->StatusFlag) & UPDATE_FLAG)
|
|
|
|
//
|
|
// To get a demand start service to be started correctly in group
|
|
// order specified by the ServiceGroupOrder list, we need an additional
|
|
// flag to indicate that this service must be included in the same start
|
|
// request.
|
|
//
|
|
#define SET_CURRENTSTART_FLAG(SR) (((SR)->StatusFlag) |= CURRENTSTART_FLAG)
|
|
#define CLEAR_CURRENTSTART_FLAG(SR) (((SR)->StatusFlag) &= (~CURRENTSTART_FLAG))
|
|
#define CURRENTSTART_FLAG_IS_SET(SR) (((SR)->StatusFlag) & CURRENTSTART_FLAG)
|
|
|
|
|
|
//
|
|
// Data Structures
|
|
//
|
|
|
|
//
|
|
//==================
|
|
// LOAD_ORDER_GROUP
|
|
//==================
|
|
// NOTE: This is an ordered linked list. The Next group is loaded after
|
|
// this group.
|
|
//
|
|
// Reference count which indicates the number of members in this
|
|
// group plus any dependency pointer that points to this group.
|
|
// This field is only used for standalone groups so that we know
|
|
// when to delete the group entry. This value is always set to
|
|
// 0xffffffff if this entry represents an order group.
|
|
//
|
|
typedef struct _LOAD_ORDER_GROUP {
|
|
struct _LOAD_ORDER_GROUP *Next;
|
|
struct _LOAD_ORDER_GROUP *Prev;
|
|
LPWSTR GroupName;
|
|
DWORD RefCount;
|
|
|
|
} LOAD_ORDER_GROUP, *PLOAD_ORDER_GROUP, *LPLOAD_ORDER_GROUP;
|
|
|
|
|
|
|
|
//================
|
|
// IMAGE_RECORD
|
|
//================
|
|
typedef struct _IMAGE_RECORD {
|
|
struct _IMAGE_RECORD *Prev; // linked list
|
|
struct _IMAGE_RECORD *Next; // linked list
|
|
LPWSTR ImageName; // fully qualified .exe name
|
|
DWORD Pid; // Process ID
|
|
DWORD ServiceCount; // Num services running in process
|
|
HANDLE PipeHandle; // Handle to Service
|
|
HANDLE ProcessHandle; // Handle for process
|
|
HANDLE ObjectWaitHandle; // Handle for waiting on the process
|
|
HANDLE TokenHandle; // Logon token handle
|
|
LUID AccountLuid; // Unique LUID for this logon session
|
|
HANDLE ProfileHandle; // User profile handle
|
|
LPWSTR AccountName; // Account process was started under
|
|
DWORD ImageFlags; // Flags for the IMAGE_RECORD
|
|
}IMAGE_RECORD, *PIMAGE_RECORD, *LPIMAGE_RECORD;
|
|
|
|
typedef enum _DEPEND_TYPE {
|
|
TypeNone = 0,
|
|
TypeDependOnService = 128,
|
|
TypeDependOnGroup,
|
|
TypeDependOnUnresolved // only for service
|
|
} DEPEND_TYPE, *PDEPEND_TYPE, *LPDEPEND_TYPE;
|
|
|
|
//================
|
|
// DEPEND_RECORD
|
|
//================
|
|
// A service record has a pointer to this structure if the service
|
|
// must be started after some services, or must be stopped after some
|
|
// services.
|
|
// NOTE: This is an ordered linked list. This service depends on the
|
|
// "Next" service. Question: Does this service depend on all the services
|
|
// in the Next chain?
|
|
//
|
|
// Depend union:
|
|
// Based on the DependType field, this pointer may point to a
|
|
// service or a group which the service depends on, or an
|
|
// unresolved dependency structure.
|
|
//
|
|
typedef struct _DEPEND_RECORD {
|
|
struct _DEPEND_RECORD *Next;
|
|
DEPEND_TYPE DependType;
|
|
union {
|
|
struct _SERVICE_RECORD * DependService;
|
|
struct _LOAD_ORDER_GROUP * DependGroup;
|
|
struct _UNRESOLVED_DEPEND * DependUnresolved;
|
|
LPVOID Depend; // used when type doesn't matter
|
|
};
|
|
} DEPEND_RECORD, *PDEPEND_RECORD, *LPDEPEND_RECORD;
|
|
|
|
|
|
//================
|
|
// CCrashRecord
|
|
//================
|
|
// This structure counts a service's crashes and remembers the time of the
|
|
// last crash. It is allocated only for services that crash.
|
|
//
|
|
class CCrashRecord
|
|
{
|
|
public:
|
|
CCrashRecord() :
|
|
_LastCrashTime(0),
|
|
_Count(0)
|
|
{ }
|
|
|
|
DWORD IncrementCount(DWORD ResetSeconds);
|
|
|
|
private:
|
|
|
|
__int64 _LastCrashTime; // FILETIME = __int64
|
|
DWORD _Count;
|
|
};
|
|
|
|
|
|
|
|
//================
|
|
// SERVICE_RECORD
|
|
//================
|
|
// Dependency information:
|
|
// StartDepend is a linked list of services and groups that must be
|
|
// started first before this service can start.
|
|
// StopDepend is a linked list of services and groups that must be
|
|
// stopped first before this service can stop.
|
|
// Dependencies is a string read in from the registry. Deleted when
|
|
// the info has been converted to a StartDepend list.
|
|
//
|
|
// StartError:
|
|
// Error encountered by service controller when starting a service.
|
|
// This is distinguished from error posted by the service itself in
|
|
// the exitcode field.
|
|
//
|
|
// StartState:
|
|
// SC managed service state which is distinguished from the service
|
|
// current state to enable correct handling of start dependencies.
|
|
//
|
|
// Load order group information:
|
|
//
|
|
// MemberOfGroup is a pointer to a load order group which this service
|
|
// is currently a member of. This value is set to NULL if this
|
|
// service does not belong to a group. A non-NULL pointer could
|
|
// point to a group entry in either the order group or standalone
|
|
// group list.
|
|
//
|
|
// RegistryGroup is a pointer to a group which we have recorded in the
|
|
// registry as the group this service belongs to. This is not the
|
|
// same as MemberOfGroup whenever the service is running and the
|
|
// load order group of the service has been changed
|
|
//
|
|
typedef struct _SERVICE_RECORD {
|
|
struct _SERVICE_RECORD *Prev; // linked list
|
|
struct _SERVICE_RECORD *Next; // linked list
|
|
LPWSTR ServiceName; // points to service name
|
|
LPWSTR DisplayName; // points to display name
|
|
DWORD ResumeNum; // Ordered number for this rec
|
|
DWORD ServerAnnounce; // Server announcement bit flags
|
|
DWORD Signature; // Identifies this as a service record.
|
|
DWORD UseCount; // How many open handles to service
|
|
DWORD StatusFlag; // status(delete,update...)
|
|
union {
|
|
LPIMAGE_RECORD ImageRecord; // Points to image record
|
|
LPWSTR ObjectName; // Points to driver object name
|
|
};
|
|
SERVICE_STATUS ServiceStatus; // see winsvc.h
|
|
DWORD StartType; // AUTO, DEMAND, etc.
|
|
DWORD ErrorControl; // NORMAL, SEVERE, etc.
|
|
DWORD Tag; // DWORD Id for the service,0=none.
|
|
LPDEPEND_RECORD StartDepend;
|
|
LPDEPEND_RECORD StopDepend;
|
|
LPWSTR Dependencies;
|
|
PSECURITY_DESCRIPTOR ServiceSd;
|
|
DWORD StartError;
|
|
DWORD StartState;
|
|
LPLOAD_ORDER_GROUP MemberOfGroup;
|
|
LPLOAD_ORDER_GROUP RegistryGroup;
|
|
CCrashRecord * CrashRecord;
|
|
}
|
|
SERVICE_RECORD, *PSERVICE_RECORD, *LPSERVICE_RECORD;
|
|
|
|
|
|
//===================
|
|
// UNRESOLVED_DEPEND
|
|
//===================
|
|
// Unresolved dependency record structure
|
|
//
|
|
// Unresolved dependency entries are linked together so that when a
|
|
// new service or group is created (installed) we can look it up in this
|
|
// list to see if the service or group is already depended on by some
|
|
// other service.
|
|
//
|
|
typedef struct _UNRESOLVED_DEPEND {
|
|
struct _UNRESOLVED_DEPEND *Next;
|
|
struct _UNRESOLVED_DEPEND *Prev;
|
|
LPWSTR Name; // Service or group name
|
|
DWORD RefCount;
|
|
} UNRESOLVED_DEPEND, *PUNRESOLVED_DEPEND, *LPUNRESOLVED_DEPEND;
|
|
|
|
|
|
//
|
|
// Macros & Constants
|
|
//
|
|
|
|
//
|
|
// for every service record in the database...
|
|
//
|
|
#define FOR_ALL_SERVICES(SR) \
|
|
SC_ASSERT(ScServiceListLock.Have()); \
|
|
for (LPSERVICE_RECORD SR = ScGetServiceDatabase(); \
|
|
SR != NULL; \
|
|
SR = SR->Next)
|
|
|
|
//
|
|
// for every service record in the database that meets this condition...
|
|
//
|
|
#define FOR_SERVICES_THAT(SR, condition) \
|
|
FOR_ALL_SERVICES(SR) \
|
|
if (!(condition)) \
|
|
continue; \
|
|
else
|
|
|
|
#define FIND_END_OF_LIST(record) while((record)->Next != NULL) { \
|
|
(record)=(record)->Next; \
|
|
}
|
|
|
|
#define REMOVE_FROM_LIST(record) (record)->Prev->Next = (record)->Next; \
|
|
if ((record)->Next != NULL) { \
|
|
(record)->Next->Prev = (record)->Prev; \
|
|
}
|
|
|
|
#define ADD_TO_LIST(record, newRec) FIND_END_OF_LIST((record)) \
|
|
(record)->Next = (newRec); \
|
|
(newRec)->Prev = (record); \
|
|
(newRec)->Next = NULL;
|
|
|
|
|
|
//
|
|
// Service controller maintains the state of a service when
|
|
// starting up a service and its dependencies in the StartState
|
|
// field of the service record.
|
|
//
|
|
#define SC_NEVER_STARTED 0x00000000
|
|
#define SC_START_NOW 0x00000001
|
|
#define SC_START_PENDING 0x00000002
|
|
#define SC_START_SUCCESS 0x00000003
|
|
#define SC_START_FAIL 0x00000004
|
|
|
|
|
|
#define TERMINATE_TIMEOUT 20000 // wait response to terminate req.
|
|
|
|
|
|
//
|
|
// External Globals
|
|
//
|
|
|
|
extern LPLOAD_ORDER_GROUP ScGlobalTDIGroup;
|
|
extern LPLOAD_ORDER_GROUP ScGlobalPNP_TDIGroup;
|
|
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
|
|
LPLOAD_ORDER_GROUP
|
|
ScGetOrderGroupList(
|
|
VOID
|
|
);
|
|
|
|
LPLOAD_ORDER_GROUP
|
|
ScGetStandaloneGroupList(
|
|
VOID
|
|
);
|
|
|
|
LPSERVICE_RECORD
|
|
ScGetServiceDatabase(
|
|
VOID
|
|
);
|
|
|
|
LPUNRESOLVED_DEPEND
|
|
ScGetUnresolvedDependList(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ScInitDatabase(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ScInitGroupDatabase(VOID);
|
|
|
|
VOID
|
|
ScEndGroupDatabase(VOID);
|
|
|
|
DWORD
|
|
ScCreateDependRecord(
|
|
IN BOOL IsStartList,
|
|
IN OUT PSERVICE_RECORD ServiceRecord,
|
|
OUT PDEPEND_RECORD *DependRecord
|
|
);
|
|
|
|
DWORD
|
|
ScCreateImageRecord (
|
|
OUT LPIMAGE_RECORD *ImageRecordPtr,
|
|
IN LPWSTR ImageName,
|
|
IN LPWSTR AccountName,
|
|
IN DWORD Pid,
|
|
IN HANDLE PipeHandle,
|
|
IN HANDLE ProcessHandle,
|
|
IN HANDLE TokenHandle,
|
|
IN HANDLE ProfileHandle,
|
|
IN DWORD ImageFlags
|
|
);
|
|
|
|
DWORD
|
|
ScCreateServiceRecord(
|
|
IN LPWSTR ServiceName,
|
|
OUT LPSERVICE_RECORD *ServiceRecord
|
|
);
|
|
|
|
VOID
|
|
ScFreeServiceRecord(
|
|
IN LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
VOID
|
|
ScDecrementUseCountAndDelete(
|
|
LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
BOOL
|
|
ScFindEnumStart(
|
|
IN DWORD ResumeIndex,
|
|
OUT LPSERVICE_RECORD *ServiceRecordPtr
|
|
);
|
|
|
|
BOOL
|
|
ScGetNamedImageRecord (
|
|
IN LPWSTR ImageName,
|
|
OUT LPIMAGE_RECORD *ImageRecordPtr
|
|
);
|
|
|
|
DWORD
|
|
ScGetNamedServiceRecord (
|
|
IN LPWSTR ServiceName,
|
|
OUT LPSERVICE_RECORD *ServiceRecordPtr
|
|
);
|
|
|
|
LPLOAD_ORDER_GROUP
|
|
ScGetNamedGroupRecord(
|
|
IN LPCWSTR GroupName
|
|
);
|
|
|
|
DWORD
|
|
ScGetDisplayNamedServiceRecord (
|
|
IN LPWSTR ServiceDisplayName,
|
|
OUT LPSERVICE_RECORD *ServiceRecordPtr
|
|
);
|
|
|
|
DWORD
|
|
ScGetTotalNumberOfRecords(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ScProcessCleanup(
|
|
HANDLE ProcessHandle
|
|
);
|
|
|
|
VOID
|
|
ScQueueRecoveryAction(
|
|
IN LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
VOID
|
|
ScDeleteMarkedServices(
|
|
VOID
|
|
);
|
|
|
|
DWORD
|
|
ScUpdateServiceRecord (
|
|
IN LPSERVICE_STATUS ServiceStatus,
|
|
IN LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
DWORD
|
|
ScRemoveService (
|
|
IN LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
DWORD
|
|
ScTerminateServiceProcess (
|
|
IN PIMAGE_RECORD ImageRecord
|
|
);
|
|
|
|
VOID
|
|
ScDeleteImageRecord (
|
|
IN LPIMAGE_RECORD ImageRecord
|
|
);
|
|
|
|
VOID
|
|
ScActivateServiceRecord (
|
|
IN LPSERVICE_RECORD ServiceRecord,
|
|
IN LPIMAGE_RECORD ImageRecord
|
|
);
|
|
|
|
DWORD
|
|
ScDeactivateServiceRecord (
|
|
IN LPSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
DWORD
|
|
ScCreateOrderGroupEntry(
|
|
IN LPWSTR GroupName
|
|
);
|
|
|
|
DWORD
|
|
ScAddConfigInfoServiceRecord(
|
|
IN LPSERVICE_RECORD ServiceRecord,
|
|
IN DWORD ServiceType,
|
|
IN DWORD StartType,
|
|
IN DWORD ErrorControl,
|
|
IN LPWSTR Group OPTIONAL,
|
|
IN DWORD Tag,
|
|
IN LPWSTR Dependencies OPTIONAL,
|
|
IN LPWSTR DisplayName OPTIONAL,
|
|
IN PSECURITY_DESCRIPTOR Sd OPTIONAL
|
|
);
|
|
|
|
|
|
VOID
|
|
ScGenerateDependencies(
|
|
VOID
|
|
);
|
|
|
|
DWORD
|
|
ScSetDependencyPointers(
|
|
LPSERVICE_RECORD Service
|
|
);
|
|
|
|
DWORD
|
|
ScResolveDependencyToService(
|
|
LPSERVICE_RECORD Service
|
|
);
|
|
|
|
VOID
|
|
ScUnresolveDependencyToService(
|
|
LPSERVICE_RECORD Service
|
|
);
|
|
|
|
DWORD
|
|
ScCreateDependencies(
|
|
OUT PSERVICE_RECORD ServiceRecord,
|
|
IN LPWSTR Dependencies OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
ScDeleteStartDependencies(
|
|
IN PSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
VOID
|
|
ScDeleteStopDependencies(
|
|
IN PSERVICE_RECORD ServiceToBeDeleted
|
|
);
|
|
|
|
DWORD
|
|
ScCreateGroupMembership(
|
|
OUT PSERVICE_RECORD ServiceRecord,
|
|
IN LPWSTR Group OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
ScDeleteGroupMembership(
|
|
IN OUT PSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
DWORD
|
|
ScCreateRegistryGroupPointer(
|
|
OUT PSERVICE_RECORD ServiceRecord,
|
|
IN LPWSTR Group OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
ScDeleteRegistryGroupPointer(
|
|
IN OUT PSERVICE_RECORD ServiceRecord
|
|
);
|
|
|
|
VOID
|
|
ScGetUniqueTag(
|
|
IN LPWSTR GroupName,
|
|
OUT LPDWORD Tag
|
|
);
|
|
|
|
DWORD
|
|
ScUpdateServiceRecordConfig(
|
|
LPSERVICE_RECORD ServiceRecord,
|
|
DWORD dwServiceType,
|
|
DWORD dwStartType,
|
|
DWORD dwErrorControl,
|
|
LPWSTR lpLoadOrderGroup,
|
|
LPBYTE lpDependencies
|
|
);
|
|
|
|
VOID
|
|
ScGetDependencySize(
|
|
LPSERVICE_RECORD ServiceRecord,
|
|
LPDWORD DependSize,
|
|
LPDWORD MaxDependSize
|
|
);
|
|
|
|
DWORD
|
|
ScGetDependencyString(
|
|
LPSERVICE_RECORD ServiceRecord,
|
|
DWORD MaxDependSize,
|
|
DWORD DependSize,
|
|
LPWSTR lpDependencies
|
|
);
|
|
|
|
BOOL
|
|
ScAllocateSRHeap(
|
|
DWORD HeapSize
|
|
);
|
|
|
|
#if DBG
|
|
VOID
|
|
ScDumpGroups(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ScDumpServiceDependencies(
|
|
VOID
|
|
);
|
|
#endif // if DBG
|
|
|
|
#endif // ifndef SCDATAMAN_INCLUDED
|