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.
1071 lines
30 KiB
1071 lines
30 KiB
/*++
|
|
|
|
Microsoft Windows
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
File: WMIInst.C
|
|
|
|
Contents: co-installer hook to setup security on wmi guids
|
|
|
|
The assumption is that the INF is setup to have an install
|
|
section decorated with a "WMI" keyword. Then there should
|
|
be a section defining a WMIInterface that has 3 fields: a
|
|
GUID, flags, and WMIInterfaceSection.
|
|
WMIINterface = <GUID>, flags, <SectionName>
|
|
A security field should then be defined under that
|
|
SectionName, that contains the SDDL need to setup WMI
|
|
security.
|
|
[WMIInterfaceSectionName]
|
|
security = <SDDL>
|
|
|
|
This example shows both a way to install INF's for a
|
|
multi-function device for Windows 2000, and also how
|
|
to add to the INF syntax for other purposes.
|
|
|
|
Notes: For a complete description of CoInstallers, please see the
|
|
Microsoft Windows 2000 DDK Documentation
|
|
|
|
@@BEGIN_DDKSPLIT
|
|
|
|
Author: AlanWar 03/29/02
|
|
Revision History:
|
|
|
|
@@END_DDKSPLIT
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <setupapi.h>
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <sddl.h>
|
|
#include <aclapi.h>
|
|
#include <strsafe.h>
|
|
|
|
#define AllocMemory malloc
|
|
#define FreeMemory free
|
|
|
|
DWORD
|
|
__inline
|
|
pSetupGetLastError(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This inline routine retrieves a Win32 error, and guarantees that the error
|
|
isn't NO_ERROR. This routine should not be called unless the preceding
|
|
call failed, and GetLastError() is supposed to contain the problem's cause.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Win32 error code retrieved via GetLastError(), or ERROR_UNIDENTIFIED_ERROR
|
|
if GetLastError() returned NO_ERROR.
|
|
|
|
--*/
|
|
{
|
|
DWORD Err = GetLastError();
|
|
|
|
return ((Err == NO_ERROR) ? ERROR_INVALID_DATA : Err);
|
|
}
|
|
|
|
|
|
//
|
|
// Macro to simplify calling of a function that reports error status via
|
|
// GetLastError(). This macro allows the caller to specify what Win32 error
|
|
// code should be returned if the function reports success. (If the default of
|
|
// NO_ERROR is desired, use the GLE_FN_CALL macro instead.)
|
|
//
|
|
// The "prototype" of this macro is as follows:
|
|
//
|
|
// DWORD
|
|
// GLE_FN_CALL_WITH_SUCCESS(
|
|
// SuccessfulStatus, // Win32 error code to return if function succeeded
|
|
// FailureIndicator, // value returned by function to indicate failure (e.g., FALSE, NULL, INVALID_HANDLE_VALUE)
|
|
// FunctionCall // actual call to the function
|
|
// );
|
|
//
|
|
|
|
#define GLE_FN_CALL_WITH_SUCCESS(SuccessfulStatus, \
|
|
FailureIndicator, \
|
|
FunctionCall) \
|
|
\
|
|
(SetLastError(NO_ERROR), \
|
|
(((FunctionCall) != (FailureIndicator)) \
|
|
? (SuccessfulStatus) \
|
|
: pSetupGetLastError()))
|
|
|
|
//
|
|
// Macro to simplify calling of a function that reports error status via
|
|
// GetLastError(). If the function call is successful, NO_ERROR is returned.
|
|
// (To specify an alternate value returned upon success, use the
|
|
// GLE_FN_CALL_WITH_SUCCESS macro instead.)
|
|
//
|
|
// The "prototype" of this macro is as follows:
|
|
//
|
|
// DWORD
|
|
// GLE_FN_CALL(
|
|
// FailureIndicator, // value returned by function to indicate failure (e.g., FALSE, NULL, INVALID_HANDLE_VALUE)
|
|
// FunctionCall // actual call to the function
|
|
// );
|
|
//
|
|
|
|
#define GLE_FN_CALL(FailureIndicator, FunctionCall) \
|
|
GLE_FN_CALL_WITH_SUCCESS(NO_ERROR, FailureIndicator, FunctionCall)
|
|
|
|
|
|
|
|
//
|
|
// ** Function Prototypes **
|
|
//
|
|
|
|
ULONG
|
|
ParseSection(
|
|
IN INFCONTEXT InfLineContext,
|
|
IN OUT PTCHAR *GuidString,
|
|
IN OUT ULONG *GuidStringLen,
|
|
OUT PDWORD Flags,
|
|
IN OUT PTCHAR *SectionNameString,
|
|
IN OUT ULONG *SectionNameStringLen
|
|
);
|
|
|
|
ULONG
|
|
EstablishGuidSecurity(
|
|
IN PTCHAR GuidString,
|
|
IN PTCHAR SDDLString,
|
|
IN DWORD Flags
|
|
);
|
|
|
|
|
|
ULONG
|
|
GetSecurityKeyword(
|
|
IN HINF InfFile,
|
|
IN LPCTSTR WMIINterfaceSection,
|
|
IN OUT PTCHAR *SDDLString,
|
|
IN OUT ULONG *SDDLStringLen
|
|
);
|
|
|
|
ULONG
|
|
ParseSecurityDescriptor(
|
|
IN PSECURITY_DESCRIPTOR SD,
|
|
OUT PSECURITY_INFORMATION SecurityInformation,
|
|
OUT PSID *Owner,
|
|
OUT PSID *Group,
|
|
OUT PACL *Dacl,
|
|
OUT PACL *Sacl
|
|
);
|
|
|
|
|
|
//+-----------------------------------------------------------------------------
|
|
//
|
|
// WARNING!
|
|
//
|
|
// A Coinstaller must not generate any popup to the user when called with
|
|
// DI_QUIETINSTALL. However, it's generally never a good idea to generate
|
|
// popups.
|
|
//
|
|
// OutputDebugString is a fine way to output information for debugging
|
|
//
|
|
#if DBG
|
|
VOID
|
|
DebugPrintX(
|
|
PCHAR DebugMessage,
|
|
...
|
|
);
|
|
|
|
#define DbgOut(x) DebugPrintX x
|
|
#define DEBUG_BUFFER_LENGTH 1024
|
|
#else
|
|
#define DbgOut(Text)
|
|
#endif
|
|
|
|
//
|
|
// these are keywords introduced by this co-installer
|
|
// note that the names are not case sensitive
|
|
//
|
|
#define WMI_KEY TEXT(".WMI")
|
|
#define WMIINTERFACE_KEY TEXT("WmiInterface")
|
|
#define WMIGUIDSECURITYSECTION_KEY TEXT("security")
|
|
|
|
#define MAX_GUID_STRING_LEN 39 // 38 chars + terminator null
|
|
|
|
|
|
|
|
DWORD
|
|
ProcessWMIInstallation(
|
|
IN HINF InfFile,
|
|
IN LPCTSTR CompSectionName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process all WmiInterface lines from the WMI install sections, by parsing
|
|
the directives to obatins the GUID and SDDL strings. For each corresponding
|
|
SDDL for GUID, then establish the appropriate security descriptors.
|
|
|
|
Arguments:
|
|
|
|
InfFile - handle to INF file
|
|
CompSectionName - name of the WMI install section
|
|
|
|
Return Value:
|
|
|
|
Status, normally NO_ERROR
|
|
|
|
--*/
|
|
{
|
|
PTCHAR GuidString, SDDLString, SectionNameString;
|
|
ULONG GuidStringLen, SDDLStringLen, SectionNameStringLen;
|
|
DWORD Flags;
|
|
INFCONTEXT InfLineContext;
|
|
DWORD Status;
|
|
|
|
Status = NO_ERROR;
|
|
|
|
//
|
|
// we look for keyword "WmiInterface" in the CompSectionName section
|
|
//
|
|
GuidString = NULL;
|
|
GuidStringLen = 0;
|
|
SectionNameString = NULL;
|
|
SectionNameStringLen = 0;
|
|
SDDLString = NULL;
|
|
SDDLStringLen = 0;
|
|
Flags = 0;
|
|
|
|
if(SetupFindFirstLine(InfFile,
|
|
CompSectionName,
|
|
WMIINTERFACE_KEY,
|
|
&InfLineContext)) {
|
|
|
|
do {
|
|
//
|
|
// WMIInterface = GUID, flags, SectionName
|
|
// The GIUD should be at index 1, flags at index 2, and section
|
|
// name at index 3
|
|
//
|
|
Status = ParseSection(InfLineContext,
|
|
&GuidString,
|
|
&GuidStringLen,
|
|
&Flags,
|
|
&SectionNameString,
|
|
&SectionNameStringLen
|
|
);
|
|
|
|
if(Status != NO_ERROR) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get SDDL string from the section specified by the interface
|
|
//
|
|
Status = GetSecurityKeyword(InfFile,
|
|
SectionNameString,
|
|
&SDDLString,
|
|
&SDDLStringLen
|
|
);
|
|
if(Status != NO_ERROR) {
|
|
break;
|
|
}
|
|
|
|
Status = EstablishGuidSecurity(GuidString, SDDLString, Flags);
|
|
|
|
if(Status != NO_ERROR) {
|
|
break;
|
|
}
|
|
|
|
|
|
} while(SetupFindNextMatchLine(&InfLineContext,
|
|
WMIINTERFACE_KEY,
|
|
&InfLineContext));
|
|
|
|
//
|
|
// Cleanup any strings allocated
|
|
//
|
|
if(GuidString != NULL) {
|
|
FreeMemory(GuidString);
|
|
}
|
|
|
|
if(SectionNameString != NULL) {
|
|
FreeMemory(SectionNameString);
|
|
}
|
|
|
|
if(SDDLString != NULL) {
|
|
FreeMemory(SDDLString);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PreProcessInstallDevice (
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN OUT PCOINSTALLER_CONTEXT_DATA Context
|
|
)
|
|
/*++
|
|
|
|
Function:
|
|
|
|
PreProcessInstallDevice
|
|
|
|
Purpose:
|
|
|
|
Handle DIF_INSTALLDEVICE PostProcessing
|
|
Opens the INF file, locates the install section with the decoration
|
|
".WMI" (as defined by WMI_KEY above). Then performs the WMI installation.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfoSet [in]
|
|
DeviceInfoData [in]
|
|
Context [in,out]
|
|
|
|
Returns:
|
|
|
|
NO_ERROR or an error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = NO_ERROR;
|
|
DWORD FinalStatus;
|
|
HINF InfFile = INVALID_HANDLE_VALUE;
|
|
SP_DRVINFO_DATA DriverInfoData;
|
|
SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
|
|
TCHAR InstallSectionName[255]; //MAX_SECT_NAME_LEN
|
|
TCHAR CompSectionName[255]; //MAX_SECT_NAME_LEN
|
|
|
|
INFCONTEXT CompLine;
|
|
DWORD FieldCount, FieldIndex;
|
|
|
|
FinalStatus = NO_ERROR;
|
|
|
|
//
|
|
// Find name of INF and name of install section
|
|
//
|
|
|
|
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupDiGetSelectedDriver(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&DriverInfoData)
|
|
);
|
|
if(Status != NO_ERROR) {
|
|
DbgOut(("Fail: SetupDiGetSelectedDriver %d\n", Status));
|
|
goto clean;
|
|
}
|
|
|
|
DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupDiGetDriverInfoDetail(
|
|
DeviceInfoSet,
|
|
DeviceInfoData,
|
|
&DriverInfoData,
|
|
&DriverInfoDetailData,
|
|
sizeof(SP_DRVINFO_DETAIL_DATA),
|
|
NULL)
|
|
);
|
|
if(Status != NO_ERROR) {
|
|
if(Status == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// We don't need the extended information. Ignore.
|
|
//
|
|
} else {
|
|
DbgOut(("Fail: SetupDiGetDriverInfoDetail %d\n", Status));
|
|
goto clean;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have InfFileName, open the INF
|
|
//
|
|
InfFile = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
if(InfFile == INVALID_HANDLE_VALUE) {
|
|
Status = GetLastError();
|
|
DbgOut(("Fail: SetupOpenInfFile %d", Status));
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// determine section used for the install which might be different
|
|
// from the section name specified in DriverInfoDetailData.
|
|
//
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupDiGetActualSectionToInstall(
|
|
InfFile,
|
|
DriverInfoDetailData.SectionName,
|
|
InstallSectionName,
|
|
(sizeof(InstallSectionName)/sizeof(InstallSectionName[0])),
|
|
NULL,
|
|
NULL)
|
|
);
|
|
if(Status != NO_ERROR) {
|
|
DbgOut(("Fail: SetupDiGetActualSectionToInstall %d\n", Status));
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// We need to append the WMI_KEY to find the correct decorated section
|
|
//
|
|
if(FAILED(StringCchCat(InstallSectionName,
|
|
(sizeof(InstallSectionName)/sizeof(InstallSectionName[0])),
|
|
WMI_KEY))) {
|
|
DbgOut(("WMICoInstaller: Fail - StringCchCat\n"));
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// we have a listed section
|
|
//
|
|
|
|
Status = ProcessWMIInstallation(InfFile,
|
|
InstallSectionName);
|
|
if(Status != NO_ERROR) {
|
|
FinalStatus = Status;
|
|
goto clean;
|
|
}
|
|
|
|
|
|
clean:
|
|
|
|
if(InfFile) {
|
|
SetupCloseInfFile(InfFile);
|
|
}
|
|
|
|
//
|
|
// since what we are doing does not affect primary device installation
|
|
// always return success
|
|
//
|
|
return FinalStatus;
|
|
}
|
|
|
|
ULONG
|
|
ParseSecurityDescriptor(
|
|
IN PSECURITY_DESCRIPTOR SD,
|
|
OUT PSECURITY_INFORMATION SecurityInformation,
|
|
OUT PSID *Owner,
|
|
OUT PSID *Group,
|
|
OUT PACL *Dacl,
|
|
OUT PACL *Sacl
|
|
)
|
|
/*++
|
|
|
|
Function:
|
|
|
|
ParseSecurityDescriptor
|
|
|
|
Purpose:
|
|
|
|
Checks information provided in the security descriptor to make sure that
|
|
at least the dacl, sacl, owner or group security was specified. Otherwise
|
|
it will return an error.
|
|
|
|
|
|
Arguments:
|
|
|
|
SD [in]
|
|
SecurityInformation [out]
|
|
Owner [out]
|
|
Group [out]
|
|
Dacl [out]
|
|
Sacl [out]
|
|
|
|
Returns:
|
|
|
|
NO_ERROR or an error code.
|
|
|
|
--*/
|
|
{
|
|
BOOL Ok, Present, Defaulted;
|
|
|
|
*SecurityInformation = 0;
|
|
|
|
*Dacl = NULL;
|
|
*Sacl = NULL;
|
|
*Owner = NULL;
|
|
*Group = NULL;
|
|
|
|
Ok = GetSecurityDescriptorOwner(SD,
|
|
Owner,
|
|
&Defaulted);
|
|
if(Ok && (Owner != NULL)) {
|
|
*SecurityInformation |= OWNER_SECURITY_INFORMATION;
|
|
}
|
|
|
|
Ok = GetSecurityDescriptorGroup(SD,
|
|
Group,
|
|
&Defaulted);
|
|
if(Ok && (Group != NULL)) {
|
|
*SecurityInformation |= GROUP_SECURITY_INFORMATION;
|
|
}
|
|
|
|
Ok = GetSecurityDescriptorDacl(SD,
|
|
&Present,
|
|
Dacl,
|
|
&Defaulted);
|
|
|
|
if(Ok && Present) {
|
|
*SecurityInformation |= DACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
|
|
Ok = GetSecurityDescriptorSacl(SD,
|
|
&Present,
|
|
Sacl,
|
|
&Defaulted);
|
|
|
|
if(Ok && Present) {
|
|
*SecurityInformation |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
|
|
//
|
|
// If no security info in the security descriptor then it is an
|
|
// error
|
|
//
|
|
return((*SecurityInformation == 0) ?
|
|
ERROR_INVALID_PARAMETER :
|
|
NO_ERROR);
|
|
}
|
|
|
|
#define WMIGUIDSECURITYKEY TEXT("System\\CurrentControlSet\\Control\\Wmi\\Security")
|
|
// path should be moved to regstr.h, nt\base\published\regstr.w
|
|
|
|
ULONG
|
|
EstablishGuidSecurity(
|
|
IN PTCHAR GuidString,
|
|
IN PTCHAR SDDLString,
|
|
IN DWORD Flags
|
|
)
|
|
/*++
|
|
|
|
Function:
|
|
|
|
EstablishGuidSecurity
|
|
|
|
Purpose:
|
|
|
|
Writes security information to registry key (specified by WMIGUIDSECURITYKEY in
|
|
regstr.w). Makes sure that the DACL is not null. Function will only write
|
|
security information if it is not specified or the SCWMI_OVERWRITE_SECURITY is set.
|
|
|
|
|
|
Arguments:
|
|
|
|
GuidString [in]
|
|
SDDLString [in]
|
|
Flags [in] - SCWMI_OVERWRITE_SECURITY flag only
|
|
|
|
Returns:
|
|
|
|
Status, normally NO_ERROR
|
|
|
|
--*/
|
|
{
|
|
HKEY Key;
|
|
PACL Dacl, Sacl;
|
|
PSID Owner, Group;
|
|
SECURITY_INFORMATION SecurityInformation;
|
|
PSECURITY_DESCRIPTOR SD;
|
|
ULONG Status;
|
|
ULONG SizeNeeded;
|
|
BOOL Present, Ok;
|
|
|
|
|
|
Key = INVALID_HANDLE_VALUE;
|
|
SD = NULL;
|
|
SizeNeeded = 0;
|
|
|
|
//
|
|
// First check if security has already been set for this guid. If
|
|
// so then we don't want to overwrite it.
|
|
//
|
|
Status = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
WMIGUIDSECURITYKEY,
|
|
&Key);
|
|
|
|
if(Status != ERROR_SUCCESS) {
|
|
//
|
|
// Ensure key remains INVALID_HANDLE_VALUE so we don't try to free
|
|
// it later
|
|
//
|
|
Key = INVALID_HANDLE_VALUE;
|
|
goto clean;
|
|
}
|
|
|
|
if((Flags & SCWMI_CLOBBER_SECURITY) ||
|
|
(ERROR_SUCCESS != RegQueryValueEx(Key,
|
|
GuidString,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&SizeNeeded))) {
|
|
|
|
|
|
//
|
|
// No security already setup so, lets go ahead and set it up
|
|
// Lets create a SD from the SDDL string
|
|
//
|
|
Status = GLE_FN_CALL(FALSE,
|
|
ConvertStringSecurityDescriptorToSecurityDescriptor(
|
|
SDDLString,
|
|
SDDL_REVISION_1,
|
|
&SD,
|
|
NULL)
|
|
);
|
|
|
|
if(Status != NO_ERROR) {
|
|
//
|
|
// Ensure SD remains NULL so it isn't freed later.
|
|
//
|
|
SD = NULL;
|
|
goto clean;
|
|
}
|
|
//
|
|
// Break up the SD into its components
|
|
//
|
|
Status = ParseSecurityDescriptor(SD,
|
|
&SecurityInformation,
|
|
&Owner,
|
|
&Group,
|
|
&Dacl,
|
|
&Sacl);
|
|
if(Status != NO_ERROR) {
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// Don't allow any SD to be setup with a NULL DACL
|
|
// as this results in full access for anyone
|
|
//
|
|
if(Dacl != NULL) {
|
|
//
|
|
// For wmiguids, the owner, group and sacl don't mean
|
|
// much so we just set the DACL.
|
|
//
|
|
SecurityInformation = DACL_SECURITY_INFORMATION;
|
|
Owner = NULL;
|
|
Group = NULL;
|
|
Sacl = NULL;
|
|
|
|
Status = SetNamedSecurityInfo(GuidString,
|
|
SE_WMIGUID_OBJECT,
|
|
SecurityInformation,
|
|
Owner,
|
|
Group,
|
|
Dacl,
|
|
Sacl);
|
|
if(Status != ERROR_SUCCESS) {
|
|
DbgOut(("SetNamedSecurityInfo failed %d\n",
|
|
Status));
|
|
goto clean;
|
|
}
|
|
} else {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto clean;
|
|
}
|
|
}
|
|
|
|
|
|
clean:
|
|
if(SD) {
|
|
//
|
|
// Explicity must use LocalFree for Security Descriptors returned by
|
|
// ConvertStringSecurityDescriptorToSecurityDescriptor
|
|
//
|
|
LocalFree(SD);
|
|
}
|
|
if(Key != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(Key);
|
|
}
|
|
|
|
|
|
return(Status);
|
|
}
|
|
ULONG
|
|
ParseSection(
|
|
IN INFCONTEXT InfLineContext,
|
|
IN OUT PTCHAR *GuidString,
|
|
IN OUT ULONG *GuidStringLen,
|
|
OUT PDWORD Flags,
|
|
IN OUT PTCHAR *SectionNameString,
|
|
IN OUT ULONG *SectionNameStringLen
|
|
)
|
|
/*++
|
|
|
|
|
|
Routinte Description:
|
|
|
|
This section parses the GUID, flags, and SectionName, respectively.
|
|
There should only be 3 fields in the WMIInterface section, otherwise an
|
|
error will be returned.
|
|
|
|
Arguments:
|
|
|
|
InfLineContext [in] - The line from the INF we are parsing
|
|
GuidString [in, out] - Passed as NULL by the caller, then memory is allocated
|
|
and filled with the corresponding GUID string.
|
|
GuidStringLen [in, out] - Passed as zero by the caller, and then set to the
|
|
maximum length for the GUID.
|
|
Flags [in, out] - SCWMI_CLOBBER_SECURITY flag only
|
|
SectionNameString [in, out] - assed as NULL by the caller, then memory is allocated
|
|
and filled with the corresponding section name.
|
|
SectionNameStringLen [in, out] - assed as zero by the caller, and then set to the
|
|
maximum length for the section name
|
|
|
|
Returns:
|
|
|
|
Status, normally NO_ERROR
|
|
|
|
--*/
|
|
{
|
|
PTCHAR TempGuidString = NULL;
|
|
ULONG FieldCount;
|
|
ULONG Status;
|
|
INT infFlags;
|
|
int i;
|
|
size_t Length;
|
|
|
|
Status = NO_ERROR;
|
|
|
|
//
|
|
// Make sure there are 3 fields specified in the section
|
|
//
|
|
FieldCount = SetupGetFieldCount(&InfLineContext);
|
|
if(FieldCount < 3) {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// Get the guid string
|
|
//
|
|
*GuidStringLen = MAX_GUID_STRING_LEN;
|
|
*GuidString = AllocMemory((*GuidStringLen) * sizeof(TCHAR));
|
|
|
|
//
|
|
// If the memory wasn't allocated, then return an error
|
|
//
|
|
if(!(*GuidString)) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean;
|
|
}
|
|
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupGetStringField(&InfLineContext,
|
|
1,
|
|
(PTSTR)(*GuidString),
|
|
*GuidStringLen,
|
|
NULL)
|
|
);
|
|
|
|
if(Status != NO_ERROR) {
|
|
goto clean;
|
|
}
|
|
|
|
|
|
//
|
|
// If the GUID string has curly braces take them off
|
|
//
|
|
|
|
//
|
|
// String has curly braces as first and last character
|
|
// Checks to make sure it has the same length as a GUID, otherwise, this function
|
|
// relies on the WMI security API to handle and invalid GUID.
|
|
//
|
|
if(((*GuidString)[0] == TEXT('{')) &&
|
|
SUCCEEDED(StringCchLength(*GuidString,MAX_GUID_STRING_LEN,&Length)) &&
|
|
(Length == (MAX_GUID_STRING_LEN-1)) &&
|
|
((*GuidString)[MAX_GUID_STRING_LEN-2] == TEXT('}'))) {
|
|
|
|
TempGuidString = AllocMemory((MAX_GUID_STRING_LEN-2) * sizeof(TCHAR));
|
|
if(TempGuidString == NULL) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// Copy the GuidString, except the first and last character (the braces)
|
|
//
|
|
if(FAILED(StringCchCopyN(TempGuidString,
|
|
MAX_GUID_STRING_LEN-2,
|
|
&(*GuidString)[1],
|
|
MAX_GUID_STRING_LEN-3))) {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
FreeMemory(TempGuidString);
|
|
TempGuidString = NULL;
|
|
goto clean;
|
|
}
|
|
|
|
FreeMemory(*GuidString);
|
|
|
|
//
|
|
// Set GuidString equal to our new one without braces
|
|
//
|
|
*GuidString = TempGuidString;
|
|
TempGuidString = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Now get the flags string
|
|
//
|
|
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupGetIntField(&InfLineContext,
|
|
2,
|
|
&infFlags)
|
|
);
|
|
|
|
if(Status != NO_ERROR) {
|
|
goto clean;
|
|
}
|
|
|
|
//
|
|
// if the flags in the INF were not set then use the flags indicated in the INF,
|
|
// otherwise default to use the ones passed in by the calling function.
|
|
//
|
|
if(!(*Flags)) {
|
|
*Flags = infFlags;
|
|
}
|
|
|
|
*SectionNameStringLen = MAX_INF_STRING_LENGTH;
|
|
*SectionNameString = AllocMemory(*SectionNameStringLen * sizeof(TCHAR));
|
|
|
|
//
|
|
// If the memory wasn't allocated, then return an error
|
|
//
|
|
if(!(*SectionNameString)) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean;
|
|
}
|
|
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupGetStringField(&InfLineContext,
|
|
3,
|
|
(PTSTR)(*SectionNameString),
|
|
(*SectionNameStringLen),
|
|
NULL)
|
|
);
|
|
|
|
|
|
clean:
|
|
//
|
|
// If the function exits abnormally then clean up any strings allocated.
|
|
//
|
|
if(Status != NO_ERROR) {
|
|
if(*GuidString){
|
|
FreeMemory(*GuidString);
|
|
*GuidString = NULL;
|
|
}
|
|
if(TempGuidString) {
|
|
FreeMemory(TempGuidString);
|
|
|
|
}
|
|
if(*SectionNameString){
|
|
FreeMemory(*SectionNameString);
|
|
*SectionNameString = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
GetSecurityKeyword(
|
|
IN HINF InfFile,
|
|
IN LPCTSTR WMIInterfaceSection,
|
|
IN OUT PTCHAR *SDDLString,
|
|
IN OUT ULONG *SDDLStringLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The section name specified under the WMIInterface should contain a
|
|
security section the specifies the SDDL. It should be in the form
|
|
security = <SDDL>. This fcuntion extracts the SDDL. There should
|
|
only be one security section, otherwise an error will be returned.
|
|
|
|
Arguments:
|
|
|
|
InfLineContext [in] - the line from the INF file
|
|
WMIInterfaceSection [in] - the section name indicating what
|
|
section contains the security info
|
|
SDDLString [in, out] - passed in as NULL by the caller, is
|
|
allocated and filled in with the
|
|
corresponding security description
|
|
string.
|
|
SDDLStringLen [in, out] - passed in as 0 by the caller and set
|
|
to the maximum length of an INF field.
|
|
|
|
Returns:
|
|
|
|
Status, normally NO_ERROR
|
|
|
|
--*/
|
|
{
|
|
INFCONTEXT InfLineContext;
|
|
DWORD Status;
|
|
ULONG FieldCount;
|
|
|
|
Status = NO_ERROR;
|
|
|
|
|
|
|
|
if(SetupFindFirstLine(InfFile,
|
|
WMIInterfaceSection,
|
|
WMIGUIDSECURITYSECTION_KEY,
|
|
&InfLineContext)) {
|
|
|
|
//
|
|
// WmiGuidSecurity = <SDDL>
|
|
// sddl will be at index 1
|
|
//
|
|
FieldCount = SetupGetFieldCount(&InfLineContext);
|
|
if(FieldCount < 1) {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto clean;
|
|
}
|
|
//
|
|
// Get the SDDL string
|
|
//
|
|
*SDDLStringLen = MAX_INF_STRING_LENGTH;
|
|
*SDDLString = AllocMemory(*SDDLStringLen * sizeof(TCHAR));
|
|
|
|
//
|
|
// If the memory wasn't allocated, then return an error
|
|
//
|
|
if(!(*SDDLString)) {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean;
|
|
}
|
|
|
|
Status = GLE_FN_CALL(FALSE,
|
|
SetupGetStringField(&InfLineContext,
|
|
1,
|
|
(PTSTR)(*SDDLString),
|
|
(*SDDLStringLen),
|
|
NULL)
|
|
);
|
|
|
|
if(Status == NO_ERROR) {
|
|
|
|
//
|
|
// There should not be more than one security entry
|
|
//
|
|
|
|
if(SetupFindNextMatchLine(&InfLineContext,
|
|
WMIGUIDSECURITYSECTION_KEY,
|
|
&InfLineContext)) {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto clean;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
clean:
|
|
//
|
|
// If the function exits abnormally then clean up any strings allocated.
|
|
//
|
|
if(Status != NO_ERROR) {
|
|
if(*SDDLString) {
|
|
FreeMemory(*SDDLString);
|
|
*SDDLString = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
__stdcall WmiGuidSecurityINF (
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO DeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
IN OUT PCOINSTALLER_CONTEXT_DATA Context
|
|
)
|
|
/*++
|
|
|
|
Function:
|
|
|
|
WmiGuidSecurityINF
|
|
|
|
Purpose:
|
|
|
|
Responds to co-installer messages
|
|
|
|
Arguments:
|
|
|
|
InstallFunction [in]
|
|
DeviceInfoSet [in]
|
|
DeviceInfoData [in]
|
|
Context [in,out]
|
|
|
|
Returns:
|
|
|
|
NO_ERROR, or an error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status = NO_ERROR;
|
|
|
|
switch(InstallFunction) {
|
|
case DIF_INSTALLDEVICE:
|
|
//
|
|
// We want to set security on the device before we install to eliminate
|
|
// the race condition of setting up a device without security.
|
|
// (No Post Processing required)
|
|
//
|
|
Status = PreProcessInstallDevice(DeviceInfoSet,
|
|
DeviceInfoData,
|
|
Context);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
DebugPrintX(
|
|
PCHAR DebugMessage,
|
|
...
|
|
)
|
|
{
|
|
CHAR SpewBuffer[DEBUG_BUFFER_LENGTH];
|
|
va_list ap;
|
|
|
|
va_start(ap, DebugMessage);
|
|
|
|
StringCchVPrintf(SpewBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
|
|
|
|
OutputDebugStringA("WMIInst: ");
|
|
OutputDebugStringA(SpewBuffer);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
#endif
|