windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/lib/msdinst/addsvc.c
2020-09-26 16:20:57 +08:00

522 lines
20 KiB
C

/****************************************************************************\
SYSPREP.C / Mass Storage Service Installer (MSDINST.LIB)
Microsoft Confidential
Copyright (c) Microsoft Corporation 2001
All rights reserved
Source file the MSD Installation library which contains the sysprep
releated code taken from the published sysprep code.
07/2001 - Brian Ku (BRIANK)
Added this new source file for the new MSD Isntallation project.
\****************************************************************************/
//
// Include File(s):
//
#include "pch.h"
//
// Used by SetupDiInstallDevice to specify the service parameters passed
// to the Service Control Manager to create/modify a service.
//
#define INFSTR_KEY_DISPLAYNAME TEXT("DisplayName")
#define INFSTR_KEY_SERVICETYPE TEXT("ServiceType") // Type
#define INFSTR_KEY_STARTTYPE TEXT("StartType") // Start
#define INFSTR_KEY_ERRORCONTROL TEXT("ErrorControl")
#define INFSTR_KEY_SERVICEBINARY TEXT("ServiceBinary") // ImagePath
#define INFSTR_KEY_LOADORDERGROUP TEXT("LoadOrderGroup")
#define INFSTR_KEY_DEPENDENCIES TEXT("Dependencies")
#define INFSTR_KEY_STARTNAME TEXT("StartName")
#define INFSTR_KEY_SECURITY TEXT("Security")
#define INFSTR_KEY_DESCRIPTION TEXT("Description")
#define INFSTR_KEY_TAG TEXT("Tag")
CONST TCHAR pszDisplayName[] = INFSTR_KEY_DISPLAYNAME,
pszServiceType[] = INFSTR_KEY_SERVICETYPE,
pszStartType[] = INFSTR_KEY_STARTTYPE,
pszErrorControl[] = INFSTR_KEY_ERRORCONTROL,
pszServiceBinary[] = INFSTR_KEY_SERVICEBINARY,
pszLoadOrderGroup[] = INFSTR_KEY_LOADORDERGROUP,
pszDependencies[] = INFSTR_KEY_DEPENDENCIES,
pszStartName[] = INFSTR_KEY_STARTNAME,
pszSystemRoot[] = TEXT("%SystemRoot%\\"),
pszSecurity[] = INFSTR_KEY_SECURITY,
pszDescription[] = INFSTR_KEY_DESCRIPTION,
pszTag[] = INFSTR_KEY_TAG;
BOOL IsAddServiceInSection(HINF hInf, LPTSTR pszServiceName, LPTSTR pszServiceSection, LPTSTR pszServiceInstallSection)
{
INFCONTEXT context;
BOOL fReturn = FALSE;
TCHAR szService[MAX_PATH],
szServiceSection[MAX_PATH];
if (!hInf || !pszServiceName || !pszServiceSection || !pszServiceInstallSection)
return FALSE;
//
// Get the xxxx_Service_Inst from the xxxx_.Service section.
//
if ( SetupFindFirstLine(hInf, pszServiceSection, _T("AddService"), &context) ) {
if( SetupGetStringField(&context,1,szService,MAX_PATH,NULL) && !lstrcmpi(szService, pszServiceName) ) {
if( SetupGetStringField(&context,3,szServiceSection,MAX_PATH,NULL) ) {
lstrcpy(pszServiceInstallSection, szServiceSection);
return (fReturn = TRUE);
}
}
}
return fReturn;
}
BOOL LocateServiceInstallSection(HINF hInf, LPTSTR pszServiceName, LPTSTR pszServiceSection)
{
BOOL fFound = FALSE,
fReturn = FALSE;
if (hInf && pszServiceName && pszServiceSection)
{
#if 1
INFCONTEXT ctxManufacturer;
//
// Walk [Manufacturer], for each manufacturer, get the install-section-name.
// Check if install-section-name.Services first field is our ServiceName. If
// so then get the third field which is the Service install section.
// NOTE: The first device install that uses a service will be found.
//
if ( !SetupFindFirstLine(hInf, _T("Manufacturer"), NULL, &ctxManufacturer) )
return (fReturn = FALSE);
//
// Walk each [Manufacturer] to get the model.
//
do {
INFCONTEXT ctxModel;
TCHAR szModel[MAX_PATH];
if(!SetupGetStringField(&ctxManufacturer,1,szModel,MAX_PATH,NULL) || !szModel[0]) {
continue;
}
if ( !SetupFindFirstLine(hInf, szModel, NULL, &ctxModel) )
return (fReturn = FALSE);
//
// Walk each Model to get the install sections.
//
do {
TCHAR szInstallSection[MAX_PATH],
szServicesSection[MAX_PATH],
szServiceInstallSection[MAX_PATH];
if(!SetupGetStringField(&ctxModel,1,szInstallSection,MAX_PATH,NULL) || !szInstallSection[0]) {
continue;
}
//
// For each install section check if they have/use any services.
//
lstrcpy(szServicesSection, szInstallSection);
lstrcat(szServicesSection, _T(".Services"));
if ( IsAddServiceInSection(hInf, pszServiceName, szServicesSection, szServiceInstallSection) ) {
//
// Found the a device which uses this service and we found the service install
// section. Everyone using this service should be using the same service install
// section.
//
lstrcpy(pszServiceSection, szServiceInstallSection);
fReturn = fFound = TRUE;
}
} while(SetupFindNextLine(&ctxModel,&ctxModel) && !fFound);
} while(SetupFindNextLine(&ctxManufacturer,&ctxManufacturer) && !fFound);
#else
//
// Quick hack to get the service install section. All infs MS builds should be in this standard
// anyways.
//
lstrcpy(pszServiceSection, pszServiceName);
lstrcat(pszServiceSection, _T("_Service_Inst"));
fReturn = TRUE;
#endif
}
return fReturn;
}
BOOL FixupServiceBinaryPath(LPTSTR pszServiceBinary, DWORD ServiceType)
{
TCHAR szWindowsPath[MAX_PATH] = _T(""),
szTempPath[MAX_PATH] = _T("");
int len;
BOOL fReturn = FALSE;
//
// Check for the C:\WINDOWS path if so remove it.
//
if ( GetWindowsDirectory(szWindowsPath, AS(szWindowsPath)) && *szWindowsPath )
{
len = lstrlen(szWindowsPath);
if ( pszServiceBinary && (0 == _tcsncmp(szWindowsPath, pszServiceBinary, len)) )
{
//
// Service type use %systemroot% so service can start
//
if (ServiceType & SERVICE_WIN32)
{
lstrcpy(szTempPath, pszSystemRoot);
lstrcat(szTempPath, pszServiceBinary + len + 1); // + 1 for the backslash
}
else
{
lstrcpy(szTempPath, pszServiceBinary + len + 1); // + 1 for the backslash
}
lstrcpy(pszServiceBinary, szTempPath);
fReturn = TRUE;
}
else
{
//
// We should never end up here. If we do then the INF has an incorrect ServiceBinary.
//
}
}
else
{
//
// We should never end up here. If we do then GetWindowsDirectory failed.
//
}
return fReturn;
}
DWORD PopulateServiceKeys(
HINF hInf, // Handle to the inf the service section will be in.
LPTSTR lpszServiceSection, // Section in the inf that has the info about the service.
LPTSTR lpszServiceName, // Name of the service (as it appears under HKLM,System\CCS\Services).
HKEY hkeyService, // Handle to the offline service key.
BOOL bServiceExists // TRUE if the service already exists in the registry
)
/*++
Routine Description:
This function adds the service and registry settings to offline hive.
Arguments:
hInf - Handle to the inf the service section will be in.
lpszServiceSection - Section in the inf that has the info about the service.
lpszServiceName - Name of the service (as it appears under HKLM,System\CCS\Services).
hkeyService - Handle to the offline hive key to use as the service key.
bServiceExists - TRUE if the service already exists in the registry. FALSE if we need to add the service.
Return Value:
ERROR_SUCCESS - Successfully populated the service keys.
--*/
{
PCTSTR ServiceName;
DWORD ServiceType,
StartType,
ErrorControl,
TagId;
TCHAR szDisplayName[MAX_PATH] = _T(""),
szLoadOrderGroup[MAX_PATH] = _T(""),
szSecurity[MAX_PATH] = _T(""),
szDescription[MAX_PATH] = _T(""),
szServiceBinary[MAX_PATH] = _T(""),
szStartName[MAX_PATH] = _T("");
INFCONTEXT InstallSectionContext;
DWORD dwLength,
dwReturn = ERROR_SUCCESS;
BOOL fServiceHasTag = FALSE;
//
// Check valid arguments.
//
if (!hInf || !lpszServiceSection || !lpszServiceName || !hkeyService)
return ERROR_INVALID_PARAMETER;
//
// Retrieve the required values from this section.
//
if(!SetupFindFirstLine(hInf, lpszServiceSection, pszServiceType, &InstallSectionContext) ||
!SetupGetIntField(&InstallSectionContext, 1, (PINT)&ServiceType)) {
return ERROR_BAD_SERVICE_INSTALLSECT;
}
if(!SetupFindFirstLine(hInf, lpszServiceSection, pszStartType, &InstallSectionContext) ||
!SetupGetIntField(&InstallSectionContext, 1, (PINT)&StartType)) {
return ERROR_BAD_SERVICE_INSTALLSECT;
}
if(!SetupFindFirstLine(hInf, lpszServiceSection, pszErrorControl, &InstallSectionContext) ||
!SetupGetIntField(&InstallSectionContext, 1, (PINT)&ErrorControl)) {
return ERROR_BAD_SERVICE_INSTALLSECT;
}
if(SetupFindFirstLine(hInf, lpszServiceSection, pszServiceBinary, &InstallSectionContext)) {
if ( !(SetupGetStringField(&InstallSectionContext, 1, szServiceBinary, sizeof(szServiceBinary)/sizeof(szServiceBinary[0]), &dwLength)) ) {
return ERROR_BAD_SERVICE_INSTALLSECT;
}
}
//
// Fixup the ServiceBinary path, if driver use relative path or if service use %systemroot% so service can load.
//
if ( !FixupServiceBinaryPath(szServiceBinary, ServiceType) )
return ERROR_BAD_SERVICE_INSTALLSECT;
//
// Now check for the other, optional, parameters.
//
if(SetupFindFirstLine(hInf, lpszServiceSection, pszDisplayName, &InstallSectionContext)) {
if( !(SetupGetStringField(&InstallSectionContext, 1, szDisplayName, sizeof(szDisplayName)/sizeof(szDisplayName[0]), &dwLength)) ) {
lstrcpy(szDisplayName, _T(""));
}
}
if(SetupFindFirstLine(hInf, lpszServiceSection, pszLoadOrderGroup, &InstallSectionContext)) {
if( !(SetupGetStringField(&InstallSectionContext, 1, szLoadOrderGroup, sizeof(szLoadOrderGroup)/sizeof(szLoadOrderGroup[0]), &dwLength)) ) {
lstrcpy(szLoadOrderGroup, _T(""));
}
}
if(SetupFindFirstLine(hInf, lpszServiceSection, pszSecurity, &InstallSectionContext)) {
if( !(SetupGetStringField(&InstallSectionContext, 1, szSecurity, sizeof(szSecurity)/sizeof(szSecurity[0]), &dwLength)) ) {
lstrcpy(szSecurity, _T(""));
}
}
if(SetupFindFirstLine(hInf, lpszServiceSection, pszDescription, &InstallSectionContext)) {
if( !(SetupGetStringField(&InstallSectionContext, 1, szDescription, sizeof(szDescription)/sizeof(szDescription[0]), &dwLength)) ) {
lstrcpy(szDescription, _T(""));
}
}
//
// Only retrieve the StartName parameter for kernel-mode drivers and win32 services. The StartName is only used for CreateService, we may
// not use it but I'm getting it anyways.
//
if(ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_WIN32)) {
if(SetupFindFirstLine(hInf, lpszServiceSection, pszStartName, &InstallSectionContext)) {
if( !(SetupGetStringField(&InstallSectionContext, 1, szStartName, sizeof(szStartName)/sizeof(szStartName[0]), &dwLength)) ) {
lstrcpy(szStartName, _T(""));
}
}
}
//
// Unique tag value for this service in the group. A value of 0 indicates that the service has not been assigned a tag.
// A tag can be used for ordering service startup within a load order group by specifying a tag order vector in the registry
// located at: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList. Tags are only evaluated for Kernel Driver
// and File System Driver start type services that have Boot or System start modes.
//
if ( fServiceHasTag = (lstrlen(szLoadOrderGroup) &&
(ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))) )
TagId = 0;
if ( !bServiceExists )
{
//
// Now write the required service key entries.
//
if ( (ERROR_SUCCESS != RegSetValueEx(hkeyService, _T("Type"), 0, REG_DWORD, (LPBYTE)&ServiceType, sizeof(ServiceType))) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, _T("Start"), 0, REG_DWORD, (LPBYTE)&StartType, sizeof(StartType))) ||
(fServiceHasTag ? (ERROR_SUCCESS != RegSetValueEx(hkeyService, pszTag, 0, REG_DWORD, (CONST LPBYTE)&TagId, sizeof(TagId))) : TRUE) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, pszErrorControl, 0, REG_DWORD, (CONST LPBYTE)&ErrorControl, sizeof(ErrorControl)))
)
return ERROR_CANTWRITE;
//
// Now write the optional service key entries.
//
if ( (ERROR_SUCCESS != RegSetValueEx(hkeyService, pszDisplayName, 0, REG_SZ, (CONST LPBYTE)szDisplayName, sizeof(szDisplayName)/sizeof(szDisplayName[0]) + sizeof(TCHAR))) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, pszLoadOrderGroup, 0, REG_SZ, (CONST LPBYTE)szLoadOrderGroup, sizeof(szLoadOrderGroup)/sizeof(szLoadOrderGroup[0]) + sizeof(TCHAR))) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, pszSecurity, 0, REG_SZ, (CONST LPBYTE)szSecurity, sizeof(szSecurity)/sizeof(szSecurity[0]) + sizeof(TCHAR))) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, pszDescription, 0, REG_SZ, (CONST LPBYTE)szDescription, sizeof(szDescription)/sizeof(szDescription[0]) + sizeof(TCHAR))) ||
(ERROR_SUCCESS != RegSetValueEx(hkeyService, _T("ImagePath"), 0, REG_SZ, (CONST LPBYTE)szServiceBinary, sizeof(szServiceBinary)/sizeof(szServiceBinary[0]) + sizeof(TCHAR)))
)
return ERROR_CANTWRITE;
}
else // Service is already installed.
{
//
// Set the service's start type to what is in the INF.
//
if ( ERROR_SUCCESS != RegSetValueEx(hkeyService, _T("Start"), 0, REG_DWORD, (LPBYTE)&StartType, sizeof(StartType)) )
return ERROR_CANTWRITE;
}
return dwReturn;
}
DWORD AddService(
LPTSTR lpszServiceName, // Name of the service (as it appears under HKLM\System\CCS\Services).
LPTSTR lpszServiceSection, // Name of the .Service section.
LPTSTR lpszServiceInfInstallFile, // Name of the service inf file.
HKEY hkeyRoot // Handle to the offline hive key to use as HKLM when checking for and installing the service.
)
/*++
Routine Description:
This function checks if service exists, if not adds the service and registry settings to offline hive.
Arguments:
hServiceInf - Handle to the inf the service section will be in.
lpszServiceName - Name of the service (as it appears under HKLM,System\CCS\Services).
lpszServiceSection - xxxx.Service section in the inf that has the AddService.
lpszServiceInfInstallFile - Name of the service inf file.
hkeyRoot - Handle to the offline hive key to use as HKLM\System when checking for and installing the service.
Return Value:
ERROR_SUCCESS - Successfully added the service keys or service already exists.
--*/
{
HKEY hKeyServices = NULL;
TCHAR szServicesKeyPath[MAX_PATH] = _T("ControlSet001\\Services\\");
DWORD dwAction,
dwReturn = ERROR_SUCCESS;
BOOL bServiceExists = FALSE;
//
// Check valid arguments.
//
if (!lpszServiceName || !lpszServiceSection || !lpszServiceInfInstallFile || !hkeyRoot)
return ERROR_INVALID_PARAMETER;
//
// Build the path to the specific service key.
//
lstrcat(szServicesKeyPath, lpszServiceName);
//
// Check if lpszServiceName already exists.
//
if ( ERROR_SUCCESS == ( dwReturn = RegOpenKeyEx(hkeyRoot, szServicesKeyPath, 0l, KEY_READ | KEY_WRITE, &hKeyServices) ) )
{
// We need to figure out the service start type and put change that.
// This is to fix the case where the service is already installed and it is disabled. We need to enable it.
//
bServiceExists = TRUE;
}
else if ( ERROR_SUCCESS == (dwReturn = RegCreateKeyEx(hkeyRoot,
szServicesKeyPath,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKeyServices,
&dwAction) ) )
{
bServiceExists = FALSE;
}
//
// If we opened or created the services key try to add the service, or modify the start type of the currently installed service.
//
if ( hKeyServices )
{
HINF hInf = NULL;
UINT uError = 0;
//
// Reinitialize this in case it was set to something else above.
//
dwReturn = ERROR_SUCCESS;
if ( INVALID_HANDLE_VALUE != ( hInf = SetupOpenInfFile(lpszServiceInfInstallFile, NULL, INF_STYLE_WIN4|INF_STYLE_OLDNT, &uError) ) )
{
BOOL bRet;
BOOL bFound = FALSE;
INFCONTEXT InfContext;
TCHAR szServiceBuffer[MAX_PATH];
//
// Find the section appropriate to the passed in service name.
//
bRet = SetupFindFirstLine(hInf, lpszServiceSection, _T("AddService"), &InfContext);
while (bRet && !bFound)
{
//
// Initialize the buffer that gets the service name so we can see if it's the one we want
//
ZeroMemory(szServiceBuffer, sizeof(szServiceBuffer));
//
// Call SetupGetStringField to get the service name for this AddService entry.
// May have more than one AddService.
//
bRet = SetupGetStringField(&InfContext, 1, szServiceBuffer, sizeof(szServiceBuffer)/sizeof(szServiceBuffer[0]), NULL);
if ( bRet && *szServiceBuffer && !lstrcmpi(szServiceBuffer, lpszServiceName) )
{
//
// Initialize the buffer that gets the real service section for this service
//
ZeroMemory(szServiceBuffer, sizeof(szServiceBuffer));
//
// Call SetupGetStringField to get the real service section for our service
//
bRet = SetupGetStringField(&InfContext, 3, szServiceBuffer, sizeof(szServiceBuffer)/sizeof(szServiceBuffer[0]), NULL);
if (bRet && *szServiceBuffer)
{
//
// Populate this service's registry keys.
//
dwReturn = PopulateServiceKeys(hInf, szServiceBuffer, lpszServiceName, hKeyServices, bServiceExists);
}
bFound = TRUE;
}
//
// We didn't find it, so keep looking!
//
if (!bFound)
{
bRet = SetupFindNextLine(&InfContext, &InfContext);
}
}
SetupCloseInfFile(hInf);
}
else
{
dwReturn = GetLastError();
}
// Close the key we created/opened.
//
RegCloseKey(hKeyServices);
}
return dwReturn;
}