windows-nt/Source/XPSP1/NT/base/ntos/config/i386/geninst.c

1495 lines
44 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
geninst.c
Abstract:
This modules contains routines to implement GenInstall of an inf section.
This is based on the code from the setupapi. Currently, it only supports
a subset of GenInstall functionality i.e AddReg and DelReg and BitReg.
Author:
Santosh Jodh (santoshj) 08-Aug-1998
Environment:
Kernel mode.
Revision History:
--*/
#include "cmp.h"
#include "stdlib.h"
#include "parseini.h"
#include "geninst.h"
typedef
BOOLEAN
(* PFN_INFRULE)(
IN PVOID InfHandle,
IN PCHAR Section,
IN PVOID RefData
);
typedef
BOOLEAN
(* PFN_REGLINE)(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
);
BOOLEAN
CmpProcessReg(
IN PVOID InfHandle,
IN PCHAR Section,
IN PVOID RefData
);
NTSTATUS
CmpProcessAddRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
);
NTSTATUS
CmpProcessDelRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
);
NTSTATUS
CmpProcessBitRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
);
NTSTATUS
CmpGetAddRegInfData(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex,
IN ULONG ValueIndex,
IN ULONG ValueType,
OUT PVOID *Data,
OUT PULONG DataSize
);
NTSTATUS
CmpOpenRegKey(
IN OUT PHANDLE Key,
IN OUT PULONG Disposition,
IN PCHAR Root,
IN PCHAR SubKey,
IN ULONG DesiredAccess,
IN BOOLEAN Create
);
NTSTATUS
CmpAppendStringToMultiSz(
IN HANDLE Key,
IN PCHAR ValueName,
IN OUT PVOID *Data,
IN OUT PULONG DataSize
);
//
// Copied from setupapi.h
//
// Flags for AddReg section lines in INF. The corresponding value
// is <ValueType> in the AddReg line format given below:
//
// <RegRootString>,<SubKey>,<ValueName>,<ValueType>,<Value>...
//
// The low word contains basic flags concerning the general data type
// and AddReg action. The high word contains values that more specifically
// identify the data type of the registry value. The high word is ignored
// by the 16-bit Windows 95 SETUPX APIs.
//
#define FLG_ADDREG_BINVALUETYPE ( 0x00000001 )
#define FLG_ADDREG_NOCLOBBER ( 0x00000002 )
#define FLG_ADDREG_DELVAL ( 0x00000004 )
#define FLG_ADDREG_APPEND ( 0x00000008 ) // Currently supported only
// for REG_MULTI_SZ values.
#define FLG_ADDREG_KEYONLY ( 0x00000010 ) // Just create the key, ignore value
#define FLG_ADDREG_OVERWRITEONLY ( 0x00000020 ) // Set only if value already exists
#define FLG_ADDREG_TYPE_MASK ( 0xFFFF0000 | FLG_ADDREG_BINVALUETYPE )
#define FLG_ADDREG_TYPE_SZ ( 0x00000000 )
#define FLG_ADDREG_TYPE_MULTI_SZ ( 0x00010000 )
#define FLG_ADDREG_TYPE_EXPAND_SZ ( 0x00020000 )
#define FLG_ADDREG_TYPE_BINARY ( 0x00000000 | FLG_ADDREG_BINVALUETYPE )
#define FLG_ADDREG_TYPE_DWORD ( 0x00010000 | FLG_ADDREG_BINVALUETYPE )
#define FLG_ADDREG_TYPE_NONE ( 0x00020000 | FLG_ADDREG_BINVALUETYPE )
#define FLG_BITREG_CLEAR ( 0x00000000 )
#define FLG_BITREG_SET ( 0x00000001 )
#define FLG_BITREG_TYPE_BINARY ( 0x00000000 )
#define FLG_BITREG_TYPE_DWORD ( 0x00000002 )
//
// We currently only support AddReg and DelReg sections.
//
#define NUM_OF_INF_RULES 3
//
// GenInstall methods we support.
//
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("INITCONST")
#endif
struct {
PCHAR Name;
PFN_INFRULE Action;
PVOID RefData;
} const gInfRuleTable[NUM_OF_INF_RULES] =
{
{"AddReg", CmpProcessReg, CmpProcessAddRegLine},
{"DelReg", CmpProcessReg, CmpProcessDelRegLine},
{"BitReg", CmpProcessReg, CmpProcessBitRegLine}
};
static const UNICODE_STRING NullString = {0, 1, L""};
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpAppendStringToMultiSz)
#pragma alloc_text(INIT,CmpOpenRegKey)
#pragma alloc_text(INIT,CmpGetAddRegInfData)
#pragma alloc_text(INIT,CmpProcessReg)
#pragma alloc_text(INIT,CmpProcessAddRegLine)
#pragma alloc_text(INIT,CmpProcessDelRegLine)
#pragma alloc_text(INIT,CmpProcessBitRegLine)
#pragma alloc_text(INIT,CmpGenInstall)
#endif
BOOLEAN
CmpGenInstall(
IN PVOID InfHandle,
IN PCHAR Section
)
/*++
Routine Description:
This routine does a GenInstall of the section in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
Return Value:
TRUE iff the entire section was processed successfully.
--*/
{
ULONG ruleNumber;
ULONG i;
PCHAR ruleName;
PCHAR regSection;
BOOLEAN result = FALSE;
if (CmpSearchInfSection(InfHandle, Section))
{
//
// Go through all the rules in the section and try to process
// each of them.
//
for ( ruleNumber = 0;
ruleName = CmpGetKeyName(InfHandle, Section, ruleNumber);
ruleNumber++)
{
//
// Search for the proceesing function in our table.
//
for ( i = 0;
i < NUM_OF_INF_RULES &&
_stricmp(ruleName, gInfRuleTable[i].Name);
i++);
if ( i >= NUM_OF_INF_RULES ||
(regSection = CmpGetSectionLineIndex( InfHandle,
Section,
ruleNumber,
0)) == NULL ||
!CmpSearchInfSection(InfHandle, Section))
{
result = FALSE;
break;
}
if (!(*gInfRuleTable[i].Action)(InfHandle, regSection, gInfRuleTable[i].RefData))
{
result = FALSE;
}
}
//
// All inf rules processed.
//
if (ruleNumber)
{
result = TRUE;
}
}
return (result);
}
BOOLEAN
CmpProcessReg(
IN PVOID InfHandle,
IN PCHAR Section,
IN PVOID RefData
)
/*++
Routine Description:
This routine processes a AddReg section in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
Return Value:
TRUE iff the entire section was processed successfully.
--*/
{
ULONG lineIndex;
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS temp;
//
// Process all the lines in the xxxReg Section.
//
for ( lineIndex = 0;
CmpSearchInfLine(InfHandle, Section, lineIndex);
lineIndex++)
{
temp = (*(PFN_REGLINE)RefData)(InfHandle, Section, lineIndex);
if (!NT_SUCCESS(temp))
{
status = temp;
}
}
if (NT_SUCCESS(status))
{
return (TRUE);
}
return (FALSE);
}
NTSTATUS
CmpProcessAddRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
)
/*++
Routine Description:
This routine processes a AddReg line in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCHAR rootKeyName;
PCHAR subKeyName;
PCHAR valueName;
ULONG flags;
ULONG valueType;
PCHAR buffer;
HANDLE key;
ULONG disposition;
BOOLEAN dontSet;
PVOID data = 0;
ULONG dataSize = 0;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
OBJECT_ATTRIBUTES objectAttributes;
//
// Get the root-key name.
//
rootKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
0);
if (rootKeyName)
{
//
// Get the optional sub-key name.
//
subKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
1);
//
// Value name is optional. Can be NULL or "".
//
valueName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
2);
//
// If we don't have a value name, the type is REG_SZ to force
// the right behavior in RegSetValueEx. Otherwise get the data type.
//
valueType = REG_SZ;
//
// Read in the flags.
//
if (!CmpGetIntField( InfHandle,
Section,
LineIndex,
3,
&flags))
{
flags = 0;
}
//
// Convert the flags to the registry type.
//
switch(flags & FLG_ADDREG_TYPE_MASK)
{
case FLG_ADDREG_TYPE_SZ:
valueType = REG_SZ;
break;
case FLG_ADDREG_TYPE_MULTI_SZ:
valueType = REG_MULTI_SZ;
break;
case FLG_ADDREG_TYPE_EXPAND_SZ:
valueType = REG_EXPAND_SZ;
break;
case FLG_ADDREG_TYPE_BINARY:
valueType = REG_BINARY;
break;
case FLG_ADDREG_TYPE_DWORD:
valueType = REG_DWORD;
break;
case FLG_ADDREG_TYPE_NONE:
valueType = REG_NONE;
break;
default :
//
// If the FLG_ADDREG_BINVALUETYPE is set, then the highword
// can contain just about any random reg data type ordinal value.
//
if(flags & FLG_ADDREG_BINVALUETYPE)
{
//
// Disallow the following reg data types:
//
// REG_NONE, REG_SZ, REG_EXPAND_SZ, REG_MULTI_SZ
//
valueType = HIGHWORD(flags);
if(valueType < REG_BINARY || valueType == REG_MULTI_SZ)
{
return (STATUS_INVALID_PARAMETER);
}
}
else
{
return (STATUS_INVALID_PARAMETER);
}
break;
}
//
// Presently, the append behavior flag is only supported for
// REG_MULTI_SZ values.
//
if((flags & FLG_ADDREG_APPEND) && valueType != REG_MULTI_SZ)
{
return (STATUS_INVALID_PARAMETER);
}
//
// W9x compatibility.
//
if( (!valueName || *valueName == '\0') && valueType == REG_EXPAND_SZ)
{
valueType = REG_SZ;
}
//
// Open the specified key if possible.
//
status = CmpOpenRegKey( &key,
&disposition,
rootKeyName,
subKeyName,
KEY_QUERY_VALUE | KEY_SET_VALUE,
(BOOLEAN)!(flags & FLG_ADDREG_OVERWRITEONLY));
if (NT_SUCCESS(status))
{
//
// Respect the key only flag.
//
if (!(flags & FLG_ADDREG_KEYONLY))
{
status = CmpGetAddRegInfData( InfHandle,
Section,
LineIndex,
4,
valueType,
&data,
&dataSize);
if (NT_SUCCESS(status))
{
//
// This variable gets set to TRUE if we dont actually want to set
// the value.
//
dontSet = FALSE;
if (flags & FLG_ADDREG_APPEND)
{
status = CmpAppendStringToMultiSz( key,
valueName,
&data,
&dataSize);
}
if (NT_SUCCESS(status))
{
//
// W9x compatibility.
//
if (disposition == REG_OPENED_EXISTING_KEY)
{
if ( (flags & FLG_ADDREG_NOCLOBBER) &&
(valueName == NULL || *valueName == '\0'))
{
status = NtQueryValueKey( key,
(PUNICODE_STRING)&NullString,
KeyValueBasicInformation,
NULL,
0,
&disposition);
if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL)
{
flags &= ~FLG_ADDREG_NOCLOBBER;
}
status = STATUS_SUCCESS;
}
if (flags & FLG_ADDREG_DELVAL)
{
//
// setupx compatibility.
//
dontSet = TRUE;
if (valueName)
{
//
// Delete the specified value.
//
RtlInitAnsiString(&ansiString, valueName);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
status = NtDeleteValueKey(key, &unicodeString);
RtlFreeUnicodeString(&unicodeString);
}
}
}
}
else
{
flags &= ~FLG_ADDREG_NOCLOBBER;
}
if (!dontSet)
{
//
// If no clobber flag is set, make sure that the value does not
// already exist.
//
RtlInitAnsiString(&ansiString, valueName);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
NTSTATUS existStatus;
if (flags & FLG_ADDREG_NOCLOBBER)
{
existStatus = NtQueryValueKey( key,
&unicodeString,
KeyValueBasicInformation,
NULL,
0,
&disposition);
if (NT_SUCCESS(existStatus) || existStatus == STATUS_BUFFER_TOO_SMALL) {
dontSet = TRUE;
}
}
else
{
if (flags & FLG_ADDREG_OVERWRITEONLY)
{
existStatus = NtQueryValueKey( key,
&unicodeString,
KeyValueBasicInformation,
NULL,
0,
&disposition);
if (!NT_SUCCESS(existStatus) && existStatus != STATUS_BUFFER_TOO_SMALL) {
dontSet = TRUE;
}
}
}
if (!dontSet)
{
status = NtSetValueKey( key,
&unicodeString,
0,
valueType,
data,
dataSize);
}
RtlFreeUnicodeString(&unicodeString);
}
}
}
}
}
NtClose(key);
}
else if (flags & FLG_ADDREG_OVERWRITEONLY)
{
status = STATUS_SUCCESS;
}
}
return (status);
}
NTSTATUS
CmpProcessDelRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
)
/*++
Routine Description:
This routine processes a DelReg line in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCHAR rootKeyName;
PCHAR subKeyName;
PCHAR valueName;
HANDLE key;
ULONG disposition;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
//
// Read the required fields.
//
rootKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
0);
subKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
1);
if (rootKeyName && subKeyName)
{
//
// Read the optional field.
//
valueName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
2);
//
// Open the specified registry key.
//
status = CmpOpenRegKey( &key,
&disposition,
rootKeyName,
subKeyName,
KEY_ALL_ACCESS,
FALSE);
//
// Proceed if we successfully opened the registry key.
//
if (NT_SUCCESS(status))
{
//
// If the key was successfully opened, do the DelReg.
//
if (valueName)
{
//
// Delete the specified value.
//
RtlInitAnsiString(&ansiString, valueName);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
status = NtDeleteValueKey(key, &unicodeString);
RtlFreeUnicodeString(&unicodeString);
}
}
else
{
//
// No value specified. The subkey needs to be deleted.
//
status = NtDeleteKey(key);
}
//
// Close the key handle.
//
NtClose(key);
}
}
return (status);
}
NTSTATUS
CmpProcessBitRegLine(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex
)
/*++
Routine Description:
This routine processes a BitReg line in the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCHAR rootKeyName;
PCHAR subKeyName;
PCHAR valueName;
ULONG flags;
ULONG mask;
ULONG field;
HANDLE key;
ULONG disposition;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
PCHAR buffer;
ULONG size;
PKEY_VALUE_FULL_INFORMATION valueInfo;
//
// Get the root-key name.
//
rootKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
0);
if (rootKeyName)
{
//
// Get the optional sub-key name.
//
subKeyName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
1);
//
// Value name is optional. Can be NULL or "".
//
valueName = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
2);
if (valueName && *valueName)
{
//
// Read in the flags.
//
if (!CmpGetIntField( InfHandle,
Section,
LineIndex,
3,
&flags))
{
flags = 0;
}
if (!CmpGetIntField( InfHandle,
Section,
LineIndex,
4,
&mask))
{
mask = 0;
}
if (!(flags & FLG_BITREG_TYPE_DWORD))
{
if (!CmpGetIntField( InfHandle,
Section,
LineIndex,
5,
&field))
{
return (status);
}
}
//
// Open the specified registry key.
//
status = CmpOpenRegKey( &key,
&disposition,
rootKeyName,
subKeyName,
KEY_ALL_ACCESS,
FALSE);
if (NT_SUCCESS(status))
{
//
// Read the existing data.
//
RtlInitAnsiString(&ansiString, valueName);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
size = 0;
status = NtQueryValueKey( key,
&unicodeString,
KeyValueFullInformation,
NULL,
0,
&size);
if (size)
{
status = STATUS_NO_MEMORY;
buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
if (buffer)
{
status = NtQueryValueKey( key,
&unicodeString,
KeyValueFullInformation,
buffer,
size,
&size);
if (NT_SUCCESS(status))
{
valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
if (flags & FLG_BITREG_TYPE_DWORD)
{
if (valueInfo->Type == REG_DWORD && valueInfo->DataLength == sizeof(ULONG))
{
if (flags & FLG_BITREG_SET)
{
*(PULONG)(buffer + valueInfo->DataOffset) |= mask;
}
else
{
*(PULONG)(buffer + valueInfo->DataOffset) &= ~mask;
}
}
}
else
{
if (valueInfo->Type == REG_BINARY && field < valueInfo->DataLength)
{
if (flags & FLG_BITREG_SET)
{
*(PUCHAR)(buffer + valueInfo->DataOffset + field) |= mask;
}
else
{
*(PUCHAR)(buffer + valueInfo->DataOffset + field) &= ~mask;
}
}
}
status = NtSetValueKey( key,
&unicodeString,
0,
valueInfo->Type,
buffer + valueInfo->DataOffset,
valueInfo->DataLength);
}
else
{
#ifndef _CM_LDR_
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Value cannot be read for BitReg in %s line %d\n", Section, LineIndex);
#endif //_CM_LDR_
ASSERT(NT_SUCCESS(status));
}
ExFreePool(buffer);
}
else
{
ASSERT(buffer);
status = STATUS_NO_MEMORY;
}
}
RtlFreeUnicodeString(&unicodeString);
}
//
// Close the key handle.
//
NtClose(key);
}
}
}
return (status);
}
NTSTATUS
CmpGetAddRegInfData(
IN PVOID InfHandle,
IN PCHAR Section,
IN ULONG LineIndex,
IN ULONG ValueIndex,
IN ULONG ValueType,
OUT PVOID *Data,
OUT PULONG DataSize
)
/*++
Routine Description:
This routine reads AddReg data from the inf.
Input Parameters:
InfHandle - Handle to the inf to be read.
Section - Name of the section to be read.
LineIndex - Index of the line to be read.
ValueIndex - Index of the value to be read.
ValueType - Data type to be read.
Data - Receives pointer to the buffer in which data has been read.
DataSize - Receives the size of the data buffer.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCHAR str;
ULONG count;
ULONG i;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
//
// Validate the required fields.
//
ASSERT(Data);
ASSERT(DataSize);
switch (ValueType)
{
case REG_DWORD:
*DataSize = sizeof(ULONG);
*Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
if (*Data)
{
//
// DWORD data is specified as four bytes in W9x.
//
if (CmpGetSectionLineIndexValueCount( InfHandle,
Section,
LineIndex) == 8)
{
if (!CmpGetBinaryField( InfHandle,
Section,
LineIndex,
ValueIndex,
*Data,
*DataSize,
NULL))
{
*((PULONG)*Data) = 0;
}
status = STATUS_SUCCESS;
}
else
{
//
// Get the DWORD value.
//
if (!CmpGetIntField( InfHandle,
Section,
LineIndex,
4,
*Data))
{
*((PULONG)*Data) = 0;
}
status = STATUS_SUCCESS;
}
}
else
{
ASSERT(*Data);
status = STATUS_NO_MEMORY;
}
break;
case REG_SZ:
case REG_EXPAND_SZ:
//
// Null terminated string. Gets converted to unicode before being
// added into the registry.
//
str = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
ValueIndex);
if (str)
{
RtlInitAnsiString(&ansiString, str);
*DataSize = (ansiString.Length << 1) + sizeof(UNICODE_NULL);
unicodeString.MaximumLength = (USHORT)*DataSize;
unicodeString.Buffer = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
*Data = NULL;
if (unicodeString.Buffer)
{
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
if (NT_SUCCESS(status))
{
*Data = unicodeString.Buffer;
status = STATUS_SUCCESS;
}
}
else
{
ASSERT(unicodeString.Buffer);
status = STATUS_NO_MEMORY;
}
}
else
{
ASSERT(str);
status = STATUS_NO_MEMORY;
}
break;
case REG_MULTI_SZ:
*DataSize = 0;
*Data = NULL;
//
// Loop to determine the total memory that needs to be allocated.
//
count = CmpGetSectionLineIndexValueCount( InfHandle,
Section,
LineIndex);
if (count > ValueIndex)
{
count -= ValueIndex;
for (i = 0; i < count; i++)
{
str = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
ValueIndex + i);
if (str == NULL)
{
break;
}
*DataSize += ((strlen(str) * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
}
if (i == count)
{
//
// Account for the terminating NULL.
//
*DataSize += sizeof(UNICODE_NULL);
*Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
if (*Data)
{
for ( i = 0, unicodeString.Buffer = *Data;
i < count;
i++, (PCHAR)unicodeString.Buffer += unicodeString.MaximumLength)
{
str = CmpGetSectionLineIndex( InfHandle,
Section,
LineIndex,
ValueIndex + i);
if (str == NULL)
{
break;
}
RtlInitAnsiString(&ansiString, str);
unicodeString.MaximumLength = (ansiString.Length * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
if (!NT_SUCCESS(status))
{
break;
}
}
//
// Terminate the multi-sz string.
//
if (i == count)
{
unicodeString.Buffer[0] = UNICODE_NULL;
status = STATUS_SUCCESS;
}
}
else
{
ASSERT(*Data);
status = STATUS_NO_MEMORY;
}
}
}
break;
case REG_BINARY:
default:
//
// Free form binary data.
//
if (CmpGetBinaryField( InfHandle,
Section,
LineIndex,
ValueIndex,
NULL,
0,
DataSize) && *DataSize)
{
*Data = ExAllocatePoolWithTag(PagedPool, *DataSize, CM_GENINST_TAG);
if (*Data)
{
if (CmpGetBinaryField( InfHandle,
Section,
LineIndex,
4,
*Data,
*DataSize,
NULL))
{
status = STATUS_SUCCESS;
}
}
else
{
ASSERT(*Data);
status = STATUS_NO_MEMORY;
}
}
else
{
status = STATUS_UNSUCCESSFUL;
}
break;
}
return (status);
}
NTSTATUS
CmpOpenRegKey(
IN OUT PHANDLE Key,
IN OUT PULONG Disposition,
IN PCHAR Root,
IN PCHAR SubKey,
IN ULONG DesiredAccess,
IN BOOLEAN Create
)
/*++
Routine Description:
This routine opens\creates a handle to the registry key.
Input Parameters:
Key - Receives the handle to the key.
Disposition - Receives the disposition of the key.
Root - Abbreviated name of the root key.
SubKey - Name of the subkey under the root.
DesiredAccess - Desired access flags for the key.
Create - TRUE if the key needs to be created instead of opened.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status = STATUS_OBJECT_NAME_INVALID;
ULONG size;
PCHAR str;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
OBJECT_ATTRIBUTES objectAttributes;
str = NULL;
size = strlen(SubKey) + 1;
//
// Check if we understand the specified root name.
//
if (_stricmp(Root, "HKLM") == 0)
{
size += (sizeof("\\Registry\\Machine\\") - 1); // Already added one above for NULL
str = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
if (str)
{
strcpy(str, "\\Registry\\Machine\\");
strcat(str, SubKey);
}
else
{
ASSERT(str);
status = STATUS_NO_MEMORY;
}
}
else
{
ASSERT(_stricmp(Root, "HKLM") == 0);
}
//
// Proceed if we have a valid key name.
//
if (str)
{
RtlInitAnsiString(&ansiString, str);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
InitializeObjectAttributes( &objectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (Create)
{
//
// Create a new key or open an existing one.
//
status = NtCreateKey( Key,
DesiredAccess,
&objectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
Disposition ? Disposition : &size);
}
else
{
//
// Open existing key.
//
if (Disposition)
{
*Disposition = REG_OPENED_EXISTING_KEY;
}
status = NtOpenKey( Key,
DesiredAccess,
&objectAttributes);
}
RtlFreeUnicodeString(&unicodeString);
}
else
{
ASSERT(NT_SUCCESS(status));
}
ExFreePool(str);
}
return (status);
}
NTSTATUS
CmpAppendStringToMultiSz(
IN HANDLE Key,
IN PCHAR ValueName,
IN OUT PVOID *Data,
IN OUT PULONG DataSize
)
/*++
Routine Description:
This routine opens\creates a handle to the registry key.
Input Parameters:
Key - Receives the handle to the key.
ValueName - Name of the value to be appended to.
Data - Buffer containing the multi-sz to be appended.
DataSize - Size of the data.
Return Value:
Standard NT status value.
--*/
{
NTSTATUS status;
ULONG size;
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
PKEY_VALUE_FULL_INFORMATION valueInfo;
PVOID buffer;
PVOID str;
ASSERT(DataSize && *DataSize);
ASSERT(*Data);
RtlInitAnsiString(&ansiString, ValueName);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (NT_SUCCESS(status))
{
size = 0;
status = NtQueryValueKey( Key,
&unicodeString,
KeyValueFullInformation,
NULL,
0,
&size);
if (size)
{
buffer = ExAllocatePoolWithTag(PagedPool, size, CM_GENINST_TAG);
if (buffer)
{
status = NtQueryValueKey( Key,
&unicodeString,
KeyValueFullInformation,
buffer,
size,
&size);
if (NT_SUCCESS(status))
{
valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
str = ExAllocatePoolWithTag( PagedPool,
valueInfo->DataLength +
*DataSize - sizeof(UNICODE_NULL),
CM_GENINST_TAG);
if (str)
{
memcpy( str,
(PCHAR)buffer + valueInfo->DataOffset,
valueInfo->DataLength);
memcpy( (PCHAR)str + valueInfo->DataLength - sizeof(UNICODE_NULL),
*Data,
*DataSize);
ExFreePool(*Data);
*Data = str;
*DataSize += valueInfo->DataLength - sizeof(UNICODE_NULL);
}
else
{
#ifndef _CM_LDR_
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
#endif //_CM_LDR_
ASSERT(str);
status = STATUS_NO_MEMORY;
}
}
ExFreePool(buffer);
}
else
{
#ifndef _CM_LDR_
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpAppendStringToMultiSz: Failed to allocate memory!\n");
#endif //_CM_LDR_
ASSERT(buffer);
status = STATUS_NO_MEMORY;
}
}
RtlFreeUnicodeString(&unicodeString);
}
return (status);
}