Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2598 lines
76 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
regvalue.cpp
Abstract:
Routines to read/write/configure registry value settings
The following modules have links to registry values
scejet.c <SceJetAddSection>
inftojet.c <SceConvertpInfKeyValue>
pfget.c <ScepGetRegistryValues>
config.c <ScepConfigureRegistryValues>
analyze.c <ScepAnalyzeRegistryValues>
Author:
Jin Huang (jinhuang) 07-Jan-1998
Revision History:
--*/
#include "headers.h"
#include "serverp.h"
#include "regvalue.h"
#include "pfp.h"
DWORD
ScepUnescapeAndAddCRLF(
IN PWSTR pszSource,
IN OUT PWSTR pszDest
);
DWORD
ScepEscapeAndRemoveCRLF(
IN const PWSTR pszSource,
IN const DWORD dwSourceSize,
IN OUT PWSTR pszDest
);
SCESTATUS
ScepSaveRegistryValueToBuffer(
IN DWORD RegType,
IN PWSTR Value,
IN DWORD dwBytes,
IN OUT PSCE_REGISTRY_VALUE_INFO pRegValues
);
SCESTATUS
ScepEnumAllRegValues(
IN OUT PDWORD pCount,
IN OUT PSCE_REGISTRY_VALUE_INFO *paRegValues
);
DWORD
ScepAnalyzeOneRegistryValueNoValidate(
IN HKEY hKey,
IN PWSTR ValueName,
IN PSCESECTION hSection OPTIONAL,
IN DWORD dwAnalFlag,
IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
);
extern "C" {
VOID
pSetupGetRealSystemTime(
OUT LPSYSTEMTIME RealSystemTime
);
}
SCESTATUS
ScepGetRegistryValues(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
OUT PSCE_REGISTRY_VALUE_INFO * ppRegValues,
OUT LPDWORD pValueCount,
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
)
/*++
Routine Description:
This routine retrieves registry values to secure from the Jet database
and stores in the output buffer ppRegValues
Arguments:
hProfile - The profile handle context
ppRegValues - the output array of registry values.
pValueCount - the buffer to hold number of elements in the array
Errlog - A buffer to hold all error codes/text encountered when
parsing the INF file. If Errlog is NULL, no further error
information is returned except the return DWORD
Return value:
SCESTATUS - SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_BAD_FORMAT
SCESTATUS_INVALID_DATA
--*/
{
if ( !hProfile || !ppRegValues || !pValueCount ) {
return(SCESTATUS_INVALID_PARAMETER);
}
SCESTATUS rc;
PSCESECTION hSection=NULL;
LPTSTR KeyName=NULL;
DWORD KeyLen;
DWORD i,j;
LPTSTR ValueStr=NULL;
LPTSTR Value=NULL;
DWORD ValueLen;
LONG dType;
DWORD Status;
DWORD dCount;
rc = ScepOpenSectionForName(
hProfile,
(ProfileType==SCE_ENGINE_GPO) ? SCE_ENGINE_SCP : ProfileType,
szRegistryValues,
&hSection
);
if ( SCESTATUS_SUCCESS != rc ) {
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
Errlog, SCEERR_OPEN,
szRegistryValues
);
return(rc);
}
//
// get total number of values in this section
//
*ppRegValues = NULL;
rc = SceJetGetLineCount(
hSection,
NULL,
FALSE,
pValueCount
);
if ( SCESTATUS_SUCCESS == rc && *pValueCount > 0 ) {
//
// allocate memory for all objects
//
*ppRegValues = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc( LMEM_ZEROINIT,
*pValueCount*sizeof(SCE_REGISTRY_VALUE_INFO) );
if ( *ppRegValues ) {
//
// goto the first line of this section
//
rc = SceJetGetValue(
hSection,
SCEJET_PREFIX_MATCH,
NULL,
NULL,
0,
&KeyLen,
NULL,
0,
&ValueLen
);
i=0;
JET_COLUMNID ColGpoID = 0;
JET_ERR JetErr;
LONG GpoID=0;
DWORD Actual;
if ( ProfileType == SCE_ENGINE_GPO ) {
JET_COLUMNDEF ColumnGpoIDDef;
JetErr = JetGetTableColumnInfo(
hSection->JetSessionID,
hSection->JetTableID,
"GpoID",
(VOID *)&ColumnGpoIDDef,
sizeof(JET_COLUMNDEF),
JET_ColInfo
);
if ( JET_errSuccess == JetErr ) {
ColGpoID = ColumnGpoIDDef.columnid;
}
}
//
// this count is for SCE_ENGINE_GPO type
//
dCount=0;
while ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_BUFFER_TOO_SMALL ) {
//
// Get string key and a int value.
//
if ( i >= *pValueCount ) {
//
// more lines than allocated
//
rc = SCESTATUS_INVALID_DATA;
ScepBuildErrorLogInfo(ERROR_INVALID_DATA,
Errlog,
SCEERR_MORE_OBJECTS,
*pValueCount
);
break;
}
GpoID = 1;
if ( ProfileType == SCE_ENGINE_GPO ) {
GpoID = 0;
if ( ColGpoID > 0 ) {
//
// query if the setting comes from a GPO
// get GPO ID field from the current line
//
JetErr = JetRetrieveColumn(
hSection->JetSessionID,
hSection->JetTableID,
ColGpoID,
(void *)&GpoID,
4,
&Actual,
0,
NULL
);
}
}
if ( GpoID <= 0 ) {
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&KeyLen,
NULL,
0,
&ValueLen
);
continue;
}
dCount++;
//
// allocate memory for the group name and value string
//
KeyName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, KeyLen+2);
if ( KeyName ) {
Value = (PWSTR)ScepAlloc(LMEM_ZEROINIT, ValueLen+2);
if ( Value ) {
rc = SceJetGetValue(
hSection,
SCEJET_CURRENT,
NULL,
KeyName,
KeyLen,
&KeyLen,
Value,
ValueLen,
&ValueLen
);
if ( rc == SCESTATUS_SUCCESS ||
rc == SCESTATUS_BUFFER_TOO_SMALL ) {
rc = SCESTATUS_SUCCESS;
if ( ValueLen > 0 )
Value[ValueLen/2] = L'\0';
KeyName[KeyLen/2] = L'\0';
if ( ValueLen > 0 && Value[0] != L'\0' ) {
//
// the first ansi character is the value type,
// second ansi character is the status (if in SAP)
// should be terminated by L'\0'
//
//dType = _wtol(Value);
dType = *((CHAR *)Value) - '0';
if ( *((CHAR *)Value+1) >= '0' ) {
Status = *((CHAR *)Value+1) - '0';
} else {
Status = 0;
}
// if ( *(Value+2) ) { // a char and a null delimiter
if ( ValueLen > 4 ) { // a char and a null delimiter
//
// the second field and after is the registry value
// convert the multi-sz delimeter to ,
//
if ( dType == REG_MULTI_SZ &&
(0 == _wcsicmp( KeyName, szLegalNoticeTextKeyName) ) ) {
//
// check for commas and escape them with "," so the UI etc.
// understands this, since, at this point for lines such as
// k=7,a",",b,c
// pValueStr will be a,\0b\0c\0\0 which we should make
// a","\0b\0c\0\0
//
DWORD dwCommaCount = 0;
j = 0;
for ( j=2; j< ValueLen/2 ; j++) {
if ( Value[j] == L',' )
dwCommaCount++;
}
if ( dwCommaCount > 0 ) {
//
// in this case we have to escape commas
//
PWSTR pszValueEscaped;
DWORD dwBytes = (ValueLen/2 + 1 + dwCommaCount*2) * sizeof(WCHAR);
pszValueEscaped = (PWSTR)ScepAlloc(LMEM_ZEROINIT, dwBytes);
if (pszValueEscaped) {
memset(pszValueEscaped, '\0', dwBytes);
ValueLen = 2 * ScepEscapeString(Value,
ValueLen/2,
L',',
L'"',
pszValueEscaped
);
ScepFree(Value);
Value = pszValueEscaped;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
}
ScepConvertMultiSzToDelim(Value+2, ValueLen/2-2, L'\0', L',');
ValueStr = (PWSTR)ScepAlloc(0, (ValueLen/2-1)*sizeof(WCHAR));
if ( ValueStr ) {
wcscpy(ValueStr, Value+2);
ValueStr[ValueLen/2-2] = L'\0';
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
} // else no value available
//
// assign name to the output buffer
//
(*ppRegValues)[i].FullValueName = KeyName;
KeyName = NULL;
(*ppRegValues)[i].ValueType = dType;
(*ppRegValues)[i].Value = ValueStr;
(*ppRegValues)[i].Status = Status;
ValueStr = NULL;
//
// increment the count
//
i++;
} else {
// shouldn't be possible to get into this loop
// if it does, ignore this one
rc = SCESTATUS_INVALID_DATA;
}
} else if ( rc != SCESTATUS_RECORD_NOT_FOUND ){
ScepBuildErrorLogInfo( ERROR_READ_FAULT,
Errlog,
SCEERR_QUERY_VALUE,
szRegistryValues
);
}
if ( Value ) {
ScepFree(Value);
Value = NULL;
}
if ( ValueStr ) {
ScepFree(ValueStr);
ValueStr = NULL;
}
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
//
// remember to free the KeyName
//
if ( KeyName ) {
ScepFree(KeyName);
KeyName = NULL;
}
if ( rc != SCESTATUS_SUCCESS ) {
break;
}
//
// read next line
//
rc = SceJetGetValue(
hSection,
SCEJET_NEXT_LINE,
NULL,
NULL,
0,
&KeyLen,
NULL,
0,
&ValueLen
);
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
if ( rc == SCESTATUS_RECORD_NOT_FOUND ||
rc == SCESTATUS_BUFFER_TOO_SMALL ) {
rc = SCESTATUS_SUCCESS;
}
if ( rc != SCESTATUS_SUCCESS ) {
//
// free memory
//
ScepFreeRegistryValues( ppRegValues, *pValueCount );
*ppRegValues = NULL;
} else if ( ProfileType == SCE_ENGINE_GPO &&
*pValueCount > dCount ) {
//
// reallocate the output buffer
//
if ( dCount > 0 ) {
PSCE_REGISTRY_VALUE_INFO pTempRegValues = *ppRegValues;
//
// allocate memory for all objects
//
*ppRegValues = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc( LMEM_ZEROINIT,
dCount*sizeof(SCE_REGISTRY_VALUE_INFO) );
if ( *ppRegValues ) {
for ( i=0,j=0; i<*pValueCount; i++ ) {
if ( pTempRegValues[i].Value ) {
(*ppRegValues)[j].FullValueName = pTempRegValues[i].FullValueName;
(*ppRegValues)[j].Value = pTempRegValues[i].Value;
(*ppRegValues)[j].ValueType = pTempRegValues[i].ValueType;
(*ppRegValues)[j].Status = pTempRegValues[i].Status;
j++;
} else if ( pTempRegValues[i].FullValueName ) {
ScepFree( pTempRegValues[i].FullValueName );
}
}
ScepFree( pTempRegValues );
*pValueCount = dCount;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
*pValueCount = 0;
}
} else {
//
// no registry value from the GPO settings are found
//
ScepFreeRegistryValues( ppRegValues, *pValueCount );
*ppRegValues = NULL;
*pValueCount = 0;
}
}
//
// close the section
//
SceJetCloseSection(&hSection, TRUE);
return(rc);
}
DWORD
ScepSetDriverSigningPolicy(
BYTE Policy)
/* ++
Routine Description:
This routine configures driver signing policy through a private API
that ensures the value is not being reset by the code signing
"anti-tampering" feature.
Arguments:
bPolicy - new policy to set
Return value:
win32 error
-- */
{
DWORD Err;
HKEY hKey;
DWORD dwData = 0, dwSize, dwType;
BYTE NewPolicy;
SYSTEMTIME RealSystemTime;
Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("System\\WPA\\PnP"),
0,
KEY_READ,
&hKey
);
if(Err != ERROR_SUCCESS) {
return Err;
}
dwSize = sizeof(dwData);
Err = RegQueryValueEx(hKey,
TEXT("seed"),
NULL,
&dwType,
(PBYTE)&dwData,
&dwSize
);
if(Err == ERROR_SUCCESS) {
if(dwType != REG_DWORD) {
Err = ERROR_DATATYPE_MISMATCH;
} else if(dwSize != sizeof(dwData)) {
Err = ERROR_INVALID_DATA;
} else {
RealSystemTime.wDayOfWeek = LOWORD(&hKey) | 4;
RealSystemTime.wMinute = LOWORD(dwData);
RealSystemTime.wYear = HIWORD(dwData);
RealSystemTime.wMilliseconds = (LOWORD(&dwType)&~3072)|(((WORD)(Policy&3))<<10);
pSetupGetRealSystemTime(&RealSystemTime);
RealSystemTime.wDayOfWeek = LOWORD(&hKey) | 4;
pSetupGetRealSystemTime(&RealSystemTime);
NewPolicy = (BYTE)(((RealSystemTime.wMilliseconds+2)&15)^8)/4;
if(Policy != NewPolicy) {
Err = ERROR_FUNCTION_FAILED;
}
}
}
RegCloseKey(hKey);
return Err;
}
SCESTATUS
ScepConfigureRegistryValues(
IN PSCECONTEXT hProfile OPTIONAL,
IN PSCE_REGISTRY_VALUE_INFO pRegValues,
IN DWORD ValueCount,
IN PSCE_ERROR_LOG_INFO *pErrLog,
IN DWORD ConfigOptions,
OUT PBOOL pAnythingSet
)
/* ++
Routine Description:
This routine configure registry values in the area of security
policy.
Arguments:
pRegValues - The array of registry values to configure
ValueCount - the number of values to configure
Return value:
SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_OTHER_ERROR
-- */
{
if ( !pRegValues || ValueCount == 0 ) {
//
// if no info to configure
//
return SCESTATUS_SUCCESS;
}
DWORD rc;
SCESTATUS Saverc=SCESTATUS_SUCCESS;
PWSTR pStart, pTemp, pValue;
HKEY hKey=NULL;
HKEY hKeyRoot;
PSCESECTION hSectionDomain=NULL;
PSCESECTION hSectionTattoo=NULL;
SCE_REGISTRY_VALUE_INFO OneRegValue;
if ( pAnythingSet )
*pAnythingSet = FALSE;
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) {
ScepTattooOpenPolicySections(
hProfile,
szRegistryValues,
&hSectionDomain,
&hSectionTattoo
);
}
for ( DWORD i=0; i<ValueCount; i++ ) {
if ( !pRegValues[i].FullValueName ||
!pRegValues[i].Value ) {
//
// no value to configure
//
continue;
}
ScepLogOutput3(2, 0, SCEDLL_SCP_CONFIGURE, pRegValues[i].FullValueName);
//
// look for the first \\
//
pStart = wcschr(pRegValues[i].FullValueName, L'\\') ;
if ( !pStart ) {
Saverc = SCESTATUS_INVALID_DATA;
if ( pErrLog ) {
ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
pRegValues[i].FullValueName);
} else {
ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
}
if ( ConfigOptions & SCE_RSOP_CALLBACK )
ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
continue;
}
//
// find the root key
//
if ( (7 == pStart-pRegValues[i].FullValueName) &&
(0 == _wcsnicmp(L"MACHINE", pRegValues[i].FullValueName, 7)) ) {
hKeyRoot = HKEY_LOCAL_MACHINE;
} else if ( (5 == pStart-pRegValues[i].FullValueName) &&
(0 == _wcsnicmp(L"USERS", pRegValues[i].FullValueName, 5)) ) {
hKeyRoot = HKEY_USERS;
} else if ( (12 == pStart-pRegValues[i].FullValueName) &&
(0 == _wcsnicmp(L"CLASSES_ROOT", pRegValues[i].FullValueName, 12)) ) {
hKeyRoot = HKEY_CLASSES_ROOT;
} else {
Saverc = SCESTATUS_INVALID_DATA;
if ( pErrLog ) {
ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
pRegValues[i].FullValueName);
} else {
ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
}
if ( ConfigOptions & SCE_RSOP_CALLBACK )
ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
continue;
}
//
// find the value name
//
pValue = pStart+1;
do {
pTemp = wcschr(pValue, L'\\');
if ( pTemp ) {
pValue = pTemp+1;
}
} while ( pTemp );
if ( pValue == pStart+1 ) {
Saverc = SCESTATUS_INVALID_DATA;
if ( pErrLog ) {
ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
pRegValues[i].FullValueName);
} else {
ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
}
if ( ConfigOptions & SCE_RSOP_CALLBACK )
ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
continue;
}
//
// terminate the subkey for now
//
*(pValue-1) = L'\0';
//
// set the value
// always create the key if it does not exist.
//
rc = RegCreateKeyEx(hKeyRoot,
pStart+1,
0,
NULL,
0,
KEY_READ | KEY_SET_VALUE,
NULL,
&hKey,
NULL
);
if ( rc == ERROR_SUCCESS ||
rc == ERROR_ALREADY_EXISTS ) {
/*
if(( rc = RegOpenKeyEx(hKeyRoot,
pStart+1,
0,
KEY_SET_VALUE,
&hKey
)) == ERROR_SUCCESS ) {
*/
//
// restore the char
//
*(pValue-1) = L'\\';
OneRegValue.FullValueName = NULL;
OneRegValue.Value = NULL;
BOOL bLMSetting = FALSE;
if ( (REG_DWORD == pRegValues[i].ValueType) &&
_wcsicmp(SCEP_LMC_SETTING, pRegValues[i].FullValueName) == 0 ) {
//
// check if dcpromo upgrade in progress
//
DWORD dwInSetup=0;
DWORD dwUpgraded=0;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("PromoteUpgradeInProgress"),
&dwUpgraded
);
if ( dwUpgraded ) {
//
// in dcpromo upgrade, we need to do special check about
// this setting
//
bLMSetting = TRUE;
} else {
//
// check if in setup upgrade
//
dwUpgraded=0;
ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
TEXT("System\\Setup"),
TEXT("SystemSetupInProgress"),
&dwInSetup
);
if ( dwInSetup ) {
//
// if system is upgraded, the state is stored in registry
// by SCE client at very beginning of GUI setup
//
ScepRegQueryIntValue(
HKEY_LOCAL_MACHINE,
SCE_ROOT_PATH,
TEXT("SetupUpgraded"),
(DWORD *)&dwUpgraded
);
if ( dwUpgraded ) {
//
// in setup upgrade, we need to do special check about
// this setting
//
bLMSetting = TRUE;
}
}
}
}
//
// if in policy propagation, query the existing value
//
if ( ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) ||
bLMSetting ) {
OneRegValue.FullValueName = pRegValues[i].FullValueName;
OneRegValue.ValueType = pRegValues[i].ValueType;
OneRegValue.Status = 0;
DWORD rc2 = ScepAnalyzeOneRegistryValueNoValidate(
hKey,
pValue,
NULL,
SCEREG_VALUE_SYSTEM,
&OneRegValue
);
if ( ERROR_SUCCESS != rc2 ) {
if ( !bLMSetting ) {
ScepLogOutput3(1, 0, SCESRV_POLICY_TATTOO_ERROR_QUERY, rc2, pRegValues[i].FullValueName);
} else if ( ERROR_FILE_NOT_FOUND != rc2 ) {
ScepLogOutput3(1, 0, SCESRV_SETUPUPD_ERROR_LMCOMPAT, rc2, pRegValues[i].FullValueName);
}
}
}
if ( REG_DWORD == pRegValues[i].ValueType ) {
//
// REG_DWORD type, value is a dword
//
LONG RegValue = _wtol(pRegValues[i].Value);
if ( !bLMSetting || OneRegValue.Value == NULL ||
_wtol(OneRegValue.Value) <= RegValue ) {
rc = RegSetValueEx( hKey,
pValue,
0,
REG_DWORD,
(BYTE *)&RegValue,
sizeof(DWORD)
);
} else {
//
// for LMCompatibility level, if in setup, set this value only if
// current system setting is less than configuration, or not defined
//
ScepLogOutput3(2, 0, SCESRV_SETUPUPD_IGNORE_LMCOMPAT, pRegValues[i].FullValueName);
}
} else if ( -1 == pRegValues[i].ValueType ) {
//
// delete the registry value
//
rc = RegDeleteValue(hKey, pValue);
//
// if the value doesn't exist, ignore the error
//
if ( ERROR_FILE_NOT_FOUND == rc )
rc = ERROR_SUCCESS;
} else {
PBYTE pRegBytes=NULL;
DWORD nLen;
nLen = wcslen(pRegValues[i].Value);
if ( REG_MULTI_SZ == pRegValues[i].ValueType || REG_QWORD == pRegValues[i].ValueType) {
//
// translate the comma delimited string to multi-sz string
//
//
// LegalNoticeText is special cased i.e. \0 should be converted to \r\n
// and commas should be unescaped before writing this value into the registry
//
BOOL bIsLegalNoticeText = FALSE;
if ( !(REG_MULTI_SZ == pRegValues[i].ValueType &&
(0 == _wcsicmp(szLegalNoticeTextKeyName, pRegValues[i].FullValueName ) ) ) ) {
pRegBytes = (PBYTE)ScepAlloc(0, (nLen+2)*sizeof(WCHAR));
if ( pRegBytes ) {
wcscpy((PWSTR)pRegBytes, pRegValues[i].Value);
((PWSTR)pRegBytes)[nLen] = L'\0';
((PWSTR)pRegBytes)[nLen+1] = L'\0';
ScepConvertMultiSzToDelim((PWSTR)pRegBytes,
nLen+1,
L',',
L'\0'
);
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
else {
DWORD dwCommaCount = 0;
DWORD dwBytes;
bIsLegalNoticeText = TRUE;
for ( DWORD dwIndex = 0; dwIndex <= nLen; dwIndex++) {
if ( pRegValues[i].Value[dwIndex] == L',' )
dwCommaCount++;
}
dwBytes = (nLen + dwCommaCount + 2)*sizeof(WCHAR);
pRegBytes = (PBYTE)ScepAlloc(0, dwBytes);
if ( pRegBytes ) {
memset(pRegBytes, '\0', dwBytes);
//
// unescape the "," and add \r\n wherever there is a ,
//
nLen = ScepUnescapeAndAddCRLF( pRegValues[i].Value, (PWSTR) pRegBytes);
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
if ( rc == NO_ERROR ) {
//
// engine/UI treat LegalNoticeText as REG_MULTI_SZ but
// we force it to be REG_SZ for compatibility sake
//
rc = RegSetValueEx( hKey,
pValue,
0,
bIsLegalNoticeText ? REG_SZ : pRegValues[i].ValueType,
pRegBytes,
(nLen+2)*sizeof(WCHAR)
);
ScepFree(pRegBytes);
}
} else if ( REG_BINARY == pRegValues[i].ValueType ) {
if ( nLen > 0 ) {
//
// binary type, translate the unicode string to binary data
// 4 bytes (2 wchars) to 1 byte
//
DWORD newLen;
newLen = nLen/2;
if ( nLen % 2 ) {
newLen++; // pad a leading 0
}
pRegBytes = (PBYTE)ScepAlloc(0, newLen);
if ( pRegBytes ) {
BYTE dByte;
for ( INT j=newLen-1; j>=0; j-- ) {
if ( nLen % 2 ) {
// odd number of chars
dByte = (pRegValues[i].Value[j*2]-L'0') % 16;
if ( j*2 >= 1 ) {
dByte += ((pRegValues[i].Value[j*2-1]-L'0') % 16) * 16;
}
} else {
// even number of chars
dByte = (pRegValues[i].Value[j*2+1]-L'0') % 16;
dByte += ((pRegValues[i].Value[j*2]-L'0') % 16) * 16;
}
pRegBytes[j] = dByte;
}
// Special case for code signing policy, this value is protected from
// "tampering" so we need to set it through their API to avoid being
// overwritten.
if (_wcsicmp(
SCEP_DRIVER_SIGNING_SETTING,
pRegValues[i].FullValueName) == 0 ) {
rc = ScepSetDriverSigningPolicy(*pRegBytes);
} else {
rc = RegSetValueEx( hKey,
pValue,
0,
REG_BINARY,
pRegBytes,
newLen
);
}
ScepFree(pRegBytes);
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
} else {
//
// sz type, expand_sz
//
rc = RegSetValueEx( hKey,
pValue,
0,
pRegValues[i].ValueType,
(BYTE *)(pRegValues[i].Value),
(nLen)*sizeof(WCHAR)
);
}
}
//
// manage the tattoo value
//
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) {
//
// if can't query system setting (OneRegValue.Value == NULL)
// (may be because they are deleted e.g. demotion)
// we still need to delete the tattoo values
//
ScepTattooManageOneRegistryValue(hSectionDomain,
hSectionTattoo,
pRegValues[i].FullValueName,
0,
&OneRegValue,
rc
);
}
if ( OneRegValue.Value ) ScepFree(OneRegValue.Value);
RegCloseKey( hKey );
}
if ( NO_ERROR != rc ) {
if ( pErrLog ) {
ScepBuildErrorLogInfo(rc,pErrLog, SCEDLL_ERROR_SET_INFO,
pRegValues[i].FullValueName);
}
if ( ERROR_FILE_NOT_FOUND != rc &&
ERROR_PATH_NOT_FOUND != rc ) {
ScepLogOutput3(1, rc, SCEDLL_ERROR_SET_INFO, pRegValues[i].FullValueName);
Saverc = ScepDosErrorToSceStatus(rc);
}
}
if ( ConfigOptions & SCE_RSOP_CALLBACK )
ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, rc, pRegValues[i].FullValueName, 0, 0);
if ( pAnythingSet ) {
*pAnythingSet = TRUE;
}
}
if ( hSectionDomain ) SceJetCloseSection(&hSectionDomain, TRUE);
if ( hSectionTattoo ) SceJetCloseSection(&hSectionTattoo, TRUE);
return(Saverc);
}
DWORD
ScepUnescapeAndAddCRLF(
IN PWSTR pszSource,
IN OUT PWSTR pszDest
)
/* ++
Routine Description:
Primarily used just before configuration
Unescapes commas i.e. a","\0b\0c\0\0 -> a,\0b\0c\0\0
Also replaces , with \r\n
Arguments:
pszSource - The source string
dwSourceChars - The number of chars in pszSource
pszDest - The destination string
Return value:
Number of characters copied to the destination
-- */
{
DWORD dwCharsCopied = 0;
while (pszSource[0] != L'\0') {
if (0 == wcsncmp(pszSource, L"\",\"", 3)) {
pszDest[0] = L',';
++dwCharsCopied;
++pszDest;
pszSource +=3;
}
else if (pszSource[0] == L',') {
pszDest[0] = L'\r';
pszDest[1] = L'\n';
dwCharsCopied +=2;
pszDest +=2 ;
++pszSource;
}
else {
pszDest[0] = pszSource[0];
++dwCharsCopied;
++pszDest;
++pszSource;
}
}
pszDest = L'\0';
++dwCharsCopied;
return dwCharsCopied;
}
DWORD
ScepEscapeAndRemoveCRLF(
IN const PWSTR pszSource,
IN const DWORD dwSourceSize,
IN OUT PWSTR pszDest
)
/* ++
Routine Description:
Primarily used before analysis
Escapes commas i.e. a,\0b\0c\0\0 -> a","\0b\0c\0\0
Also replaces \r\n with ,
This routine is the inverse of ScepUnescapeAndAddCRLF
Arguments:
pszSource - The source string
dwSourceChars - The number of chars in pszSource
pszDest - The destination string
Return value:
Number of characters copied to the destination
-- */
{
DWORD dwSourceIndex = 0;
DWORD dwCopiedChars = 0;
while (dwSourceIndex < dwSourceSize) {
if (0 == wcsncmp(pszSource + dwSourceIndex, L"\r\n", 2)) {
pszDest[0] = L',';
++pszDest;
++dwCopiedChars;
dwSourceIndex +=2;
}
else if (pszSource[dwSourceIndex] == L',') {
pszDest[0] = L'"';
pszDest[1] = L',';
pszDest[2] = L'"';
pszDest +=3 ;
dwCopiedChars +=3 ;
++dwSourceIndex;
}
else {
pszDest[0] = pszSource[dwSourceIndex];
++pszDest;
++dwCopiedChars;
++dwSourceIndex;
}
}
pszDest = L'\0';
return dwCopiedChars;
}
SCESTATUS
ScepAnalyzeRegistryValues(
IN PSCECONTEXT hProfile,
IN DWORD dwAnalFlag,
IN PSCE_PROFILE_INFO pSmpInfo
)
/* ++
Routine Description:
This routine analyze registry values in the area of security
policy.
Arguments:
Return value:
SCESTATUS_SUCCESS
SCESTATUS_NOT_ENOUGH_RESOURCE
SCESTATUS_INVALID_PARAMETER
SCESTATUS_OTHER_ERROR
-- */
{
if ( !pSmpInfo ) {
return SCESTATUS_INVALID_PARAMETER;
}
if ( (dwAnalFlag != SCEREG_VALUE_SYSTEM) && !hProfile ) {
return SCESTATUS_INVALID_PARAMETER;
}
SCESTATUS Saverc=SCESTATUS_SUCCESS;
if ( dwAnalFlag != SCEREG_VALUE_ROLLBACK ) {
Saverc = ScepEnumAllRegValues(
&(pSmpInfo->RegValueCount),
&(pSmpInfo->aRegValues)
);
}
if ( Saverc != SCESTATUS_SUCCESS ) {
return(Saverc);
}
if ( pSmpInfo->RegValueCount == 0 ||
pSmpInfo->aRegValues == NULL ) {
//
// if no info to configure
//
return SCESTATUS_SUCCESS;
}
DWORD rc;
DWORD i;
PSCESECTION hSection=NULL;
SCEJET_TABLE_TYPE tblType;
if ( dwAnalFlag != SCEREG_VALUE_SYSTEM ) {
//
// query value from system doesn't require accessing the database
//
switch ( dwAnalFlag ) {
case SCEREG_VALUE_SNAPSHOT:
case SCEREG_VALUE_FILTER:
case SCEREG_VALUE_ROLLBACK:
tblType = SCEJET_TABLE_SMP;
break;
default:
tblType = SCEJET_TABLE_SAP;
break;
}
//
// Prepare a new section
// for delay filter mode, data is written to the SMP (local) table
// when the setting is different from the effective setting (changed outside GPO)
//
Saverc = ScepStartANewSection(
hProfile,
&hSection,
tblType,
szRegistryValues
);
if ( Saverc != SCESTATUS_SUCCESS ) {
ScepLogOutput3(1, ScepSceStatusToDosError(Saverc),
SCEDLL_SAP_START_SECTION, (PWSTR)szRegistryValues);
return(Saverc);
}
}
for ( i=0; i<pSmpInfo->RegValueCount; i++ ) {
if ( dwAnalFlag == SCEREG_VALUE_SYSTEM ) {
//
// mark the status field
//
(pSmpInfo->aRegValues)[i].Status = SCE_STATUS_ERROR_NOT_AVAILABLE;
}
if ( !((pSmpInfo->aRegValues)[i].FullValueName) ) {
continue;
}
ScepLogOutput3(2, 0, SCEDLL_SAP_ANALYZE, (pSmpInfo->aRegValues)[i].FullValueName);
rc = ScepAnalyzeOneRegistryValue(
hSection,
dwAnalFlag,
&((pSmpInfo->aRegValues)[i])
);
if ( SCESTATUS_INVALID_PARAMETER == rc ||
SCESTATUS_INVALID_DATA == rc ) {
continue;
}
if ( SCESTATUS_SUCCESS != rc ) {
Saverc = rc;
break;
}
}
//
// close the section
//
SceJetCloseSection( &hSection, TRUE);
return(Saverc);
}
SCESTATUS
ScepAnalyzeOneRegistryValue(
IN PSCESECTION hSection OPTIONAL,
IN DWORD dwAnalFlag,
IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
)
{
SCESTATUS Saverc=SCESTATUS_SUCCESS;
PWSTR pStart, pTemp, pValue;
HKEY hKey=NULL, hKeyRoot;
DWORD rc=0;
if ( pOneRegValue == NULL ||
pOneRegValue->FullValueName == NULL ) {
return(SCESTATUS_INVALID_DATA);
}
if ( hSection == NULL &&
(SCEREG_VALUE_ANALYZE == dwAnalFlag ||
SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
return(SCESTATUS_INVALID_PARAMETER);
}
//
// look for the first \\
//
pStart = wcschr(pOneRegValue->FullValueName, L'\\') ;
if ( !pStart ) {
//
// if it's in snapshot mode, ignore bogus reg value names
//
Saverc = SCESTATUS_INVALID_DATA;
if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
//
// error analyzing the value, save it
//
ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
pOneRegValue->ValueType,
NULL,
0,
SCE_STATUS_ERROR_NOT_AVAILABLE
);
}
return(Saverc);
}
//
// find the root key
//
if ( (7 == pStart-pOneRegValue->FullValueName) &&
(0 == _wcsnicmp(L"MACHINE", pOneRegValue->FullValueName, 7)) ) {
hKeyRoot = HKEY_LOCAL_MACHINE;
} else if ( (5 == pStart-pOneRegValue->FullValueName) &&
(0 == _wcsnicmp(L"USERS", pOneRegValue->FullValueName, 5)) ) {
hKeyRoot = HKEY_USERS;
} else if ( (12 == pStart-pOneRegValue->FullValueName) &&
(0 == _wcsnicmp(L"CLASSES_ROOT", pOneRegValue->FullValueName, 12)) ) {
hKeyRoot = HKEY_CLASSES_ROOT;
} else {
//
// if it's in snapshot mode, ignore bogus reg value names
//
Saverc = SCESTATUS_INVALID_DATA;
if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
//
// error analyzing the value, save it
//
ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
pOneRegValue->ValueType,
NULL,
0,
SCE_STATUS_ERROR_NOT_AVAILABLE
);
}
return(Saverc);
}
//
// find the value name
//
pValue = pStart+1;
do {
pTemp = wcschr(pValue, L'\\');
if ( pTemp ) {
pValue = pTemp+1;
}
} while ( pTemp );
if ( pValue == pStart+1 ) {
//
// if it's in snapshot mode, ignore bogus reg value names
//
Saverc = SCESTATUS_INVALID_DATA;
if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
//
// error analyzing the value, save it
//
ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
pOneRegValue->ValueType,
NULL,
0,
SCE_STATUS_ERROR_NOT_AVAILABLE
);
}
return(Saverc);
}
//
// terminate the subkey for now
//
*(pValue-1) = L'\0';
if(( rc = RegOpenKeyEx(hKeyRoot,
pStart+1,
0,
KEY_READ,
&hKey
)) == ERROR_SUCCESS ) {
//
// resotre the char
//
*(pValue-1) = L'\\';
rc = ScepAnalyzeOneRegistryValueNoValidate(hKey,
pValue,
hSection,
dwAnalFlag,
pOneRegValue
);
//
// close the key
//
RegCloseKey(hKey);
} else {
//
// restore the char
//
*(pValue-1) = L'\\';
//
// error analyzing the value, or it doesn't exist, save it
//
if ( (SCEREG_VALUE_ANALYZE == dwAnalFlag) ||
(SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
(SCEREG_VALUE_ANALYZE == dwAnalFlag) ? pOneRegValue->ValueType : -1,
NULL,
0,
(SCEREG_VALUE_ANALYZE == dwAnalFlag) ? SCE_STATUS_ERROR_NOT_AVAILABLE : 0
);
}
if ( rc == ERROR_FILE_NOT_FOUND ||
rc == ERROR_PATH_NOT_FOUND ||
rc == ERROR_INVALID_HANDLE ||
rc == ERROR_ACCESS_DENIED ) {
rc = ERROR_SUCCESS;
}
}
if ( rc != NO_ERROR ) {
ScepLogOutput3(1, rc, SCEDLL_SAP_ERROR_ANALYZE, pOneRegValue->FullValueName);
Saverc = ScepDosErrorToSceStatus(rc);
}
return(Saverc);
}
DWORD
ScepAnalyzeOneRegistryValueNoValidate(
IN HKEY hKey,
IN PWSTR ValueName,
IN PSCESECTION hSection OPTIONAL,
IN DWORD dwAnalFlag,
IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
)
/*
Query and/or compare one registry value without validating the value name, etc.
The validation should be done outside of this routine.
This routine is primarily defined for sharing in both configuration and analysis.
*/
{
if ( hKey == NULL || ValueName == NULL || pOneRegValue == NULL )
return(ERROR_INVALID_PARAMETER);
DWORD rc;
DWORD dSize=0;
DWORD RegType=pOneRegValue->ValueType;
DWORD RegData=0;
PWSTR strValue=NULL;
BOOL bIsLegalNoticeText = FALSE;
if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
//
// reset the status field, it's not error'ed
//
pOneRegValue->Status = 0;
}
if(( rc = RegQueryValueEx(hKey,
ValueName,
0,
&RegType,
NULL,
&dSize
)) == ERROR_SUCCESS ) {
//
// we treat REG_DWORD_BIG_ENDIAN the same as REG_DWORD
//
if ( RegType == REG_DWORD_BIG_ENDIAN ) {
RegType = REG_DWORD;
}
if ( 0 == _wcsicmp( pOneRegValue->FullValueName, szLegalNoticeTextKeyName)) {
bIsLegalNoticeText = TRUE;
RegType = REG_MULTI_SZ;
} else if ( RegType != pOneRegValue->ValueType ) {
//
// if it's a wrong type, we assure it's not the value we found
//
rc = ERROR_FILE_NOT_FOUND;
}
if ( ERROR_SUCCESS == rc ) {
switch (RegType) {
case REG_DWORD:
dSize = sizeof(DWORD);
rc = RegQueryValueEx(hKey,
ValueName,
0,
&RegType,
(BYTE *)&RegData,
&dSize
);
break;
default:
//
// can be REG_BINARY, REG_MULTI_SZ, REG_SZ, and REG_EXPAND_SZ
// everything else is treated as REG_SZ
//
strValue = (PWSTR)ScepAlloc(0, dSize + 4);
dSize += 2;
if ( strValue ) {
memset(strValue, 0, dSize + 4 - 2);
rc = RegQueryValueEx(hKey,
ValueName,
0,
&RegType,
(BYTE *)strValue,
&dSize
);
if (bIsLegalNoticeText) {
RegType = REG_MULTI_SZ;
}
} else {
rc = ERROR_NOT_ENOUGH_MEMORY;
}
break;
}
}
}
if ( rc == NO_ERROR ) {
DWORD dwStatus = SCE_STATUS_NOT_CONFIGURED;
if ( SCEREG_VALUE_SNAPSHOT == dwAnalFlag ||
SCEREG_VALUE_ROLLBACK == dwAnalFlag )
dwStatus = 0;
switch ( RegType ) {
case REG_DWORD:
case REG_DWORD_BIG_ENDIAN:
if ( pOneRegValue->Value == NULL ||
(SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ) {
if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
//
// add the value to OneRegValue buffer
//
rc = ScepSaveRegistryValueToBuffer(
REG_DWORD,
(PWSTR)&RegData,
sizeof(DWORD),
pOneRegValue
);
} else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
//
// not configured, or snapshot the current value
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
REG_DWORD,
(PWSTR)&RegData,
sizeof(DWORD),
dwStatus
);
} // else for the delay filter, only query the reg values configured
} else if ( (LONG)RegData != _wtol(pOneRegValue->Value) ) {
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
REG_DWORD,
(PWSTR)&RegData,
sizeof(DWORD),
0
);
}
break;
case REG_BINARY:
DWORD nLen;
if ( pOneRegValue->Value ) {
nLen = wcslen(pOneRegValue->Value);
} else {
nLen = 0;
}
if ( pOneRegValue->Value == NULL ||
(SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ||
nLen == 0 ) {
if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
//
// add the value to OneRegValue buffer
//
rc = ScepSaveRegistryValueToBuffer(
RegType,
strValue,
dSize,
pOneRegValue
);
} else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
//
// not configured, or snapshot the current value
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
dwStatus
);
}
} else if ( strValue ) {
DWORD newLen;
newLen = nLen/2;
if ( nLen % 2 ) {
newLen++; // pad a leading 0
}
PBYTE pRegBytes = (PBYTE)ScepAlloc(0, newLen);
if ( pRegBytes ) {
BYTE dByte;
for ( INT j=newLen-1; j>=0; j-- ) {
if ( nLen % 2 ) {
// odd number of chars
dByte = (pOneRegValue->Value[j*2]-L'0') % 16;
if ( j*2 >= 1 ) {
dByte += ((pOneRegValue->Value[j*2-1]-L'0') % 16) * 16;
}
} else {
// even number of chars
dByte = (pOneRegValue->Value[j*2+1]-L'0') % 16;
dByte += ((pOneRegValue->Value[j*2]-L'0') % 16) * 16;
}
pRegBytes[j] = dByte;
}
if ( memcmp(strValue, pRegBytes, dSize) == 0 ) {
//
// matched, do not do anything
//
} else {
//
// mismatched, save the binary data
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
0
);
}
ScepFree(pRegBytes);
} else {
//
// out of memory
//
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
} else {
//
// mismatched, save the binary data
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
0
);
}
break;
case REG_MULTI_SZ:
case REG_QWORD:
if ( strValue ) {
if ( !(RegType == REG_MULTI_SZ &&
(0 == _wcsicmp( pOneRegValue->FullValueName, szLegalNoticeTextKeyName) ) ) ) {
ScepConvertMultiSzToDelim(strValue, dSize/2, L'\0', L',');
}
else {
DWORD dwCommaCount = 0;
PWSTR strValueNew;
DWORD dwBytes;
for (DWORD dwIndex=0; dwIndex < dSize/2; dwIndex++) {
if ( strValue[dwIndex] == L',' )
dwCommaCount++;
}
dwBytes = (dSize/2+dwCommaCount * 2 + 1) * sizeof(WCHAR);
strValueNew = (PWSTR)ScepAlloc(0, dwBytes);
if (strValueNew) {
memset(strValueNew, '\0', dwBytes);
dSize = 2 + 2 * ScepEscapeAndRemoveCRLF( strValue, dSize/2, strValueNew);
ScepFree(strValue);
strValue = strValueNew;
}
else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
break;
}
}
}
// fall through
default:
if ( pOneRegValue->Value == NULL ||
(SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ) {
if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
//
// add the value to OneRegValue buffer
//
rc = ScepSaveRegistryValueToBuffer(
RegType,
strValue,
dSize,
pOneRegValue
);
} else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
dwStatus
);
}
} else if ( strValue && bIsLegalNoticeText &&
(pOneRegValue->ValueType != RegType)) {
//
// legalnotice text special case
// must be old template is used
// each comma is escaped with two quotes
//
DWORD Len = wcslen(pOneRegValue->Value);
PWSTR NewValue = (PWSTR)ScepAlloc(LPTR, Len*3*sizeof(WCHAR));
if ( NewValue ) {
ScepEscapeAndRemoveCRLF(pOneRegValue->Value, Len, NewValue);
if ( _wcsicmp(NewValue, strValue) != 0 ) {
//
// mismatched, save the item to the database
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
0
);
}
ScepFree(NewValue);
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
} else if ( strValue &&
_wcsicmp(pOneRegValue->Value, strValue) == 0 ) {
//
// matched, do not do anything
//
} else {
//
// mismatched, save the item to the database
//
rc = ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
RegType,
strValue,
dSize,
0
);
}
break;
}
rc = ScepSceStatusToDosError(rc);
} else {
//
// error analyzing the value, or it doesn't exist, save it
// if the registry value doesn't exist, doesn't mean it's 0
// just log an "not available" status in this case
//
if ( (SCEREG_VALUE_ANALYZE == dwAnalFlag) ||
(SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
ScepSaveRegistryValue(
hSection,
pOneRegValue->FullValueName,
(SCEREG_VALUE_ANALYZE == dwAnalFlag) ? pOneRegValue->ValueType : -1,
NULL,
0,
(SCEREG_VALUE_ANALYZE == dwAnalFlag) ? SCE_STATUS_ERROR_NOT_AVAILABLE : 0
);
}
if ( rc == ERROR_FILE_NOT_FOUND ||
rc == ERROR_PATH_NOT_FOUND ||
rc == ERROR_INVALID_HANDLE ||
rc == ERROR_ACCESS_DENIED ) {
rc = ERROR_SUCCESS;
}
}
//
// free buffer
//
if ( strValue ) {
ScepFree(strValue);
strValue = NULL;
}
return(rc);
}
SCESTATUS
ScepSaveRegistryValue(
IN PSCESECTION hSection,
IN PWSTR Name,
IN DWORD RegType,
IN PWSTR CurrentValue,
IN DWORD CurrentBytes,
IN DWORD Status
)
/* ++
Routine Description:
This routine compares system settings in string with the baseline profile
settings. If there is mismatch or unknown, the entry is saved in the SAP
profile.
Arguments:
hSection - The section handle
Name - The entry name
RegType - the registry value type
CurrentValue - The current system setting
CurrentBytes - The length of the current setting
Status - the status of this registry vlue analyzed
Return Value:
SCESTATUS_SUCCESS
SCESTATUS_INVALID_PARAMETER
SCESTATUS returned from SceJetSetLine
-- */
{
SCESTATUS rc;
if ( Name == NULL )
return(SCESTATUS_INVALID_PARAMETER);
if ( CurrentValue == NULL &&
REG_DWORD == RegType &&
Status == 0 ) {
//
// only return if it's a DWORD type and saving for mismatch status
// for other types, NULL should be treated as ""
return(SCESTATUS_SUCCESS);
}
//
// build a buffer containing type and value
// note MULTI_SZ must be converted to null delimited
//
if ( REG_DWORD == RegType ) {
TCHAR StrValue[20];
memset(StrValue, '\0', 40);
*((CHAR *)StrValue) = (BYTE)RegType + '0';
if ( Status == 0) {
*((CHAR *)StrValue+1) = SCE_STATUS_MISMATCH + '0';
} else {
*((CHAR *)StrValue+1) = (BYTE)Status + '0';
}
StrValue[1] = L'\0';
if ( CurrentValue ) {
swprintf(StrValue+2, L"%d", *CurrentValue);
}
rc = SceJetSetLine( hSection, Name, FALSE, StrValue, (2+wcslen(StrValue+2))*2, 0);
} else {
PWSTR StrValue;
if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
StrValue = (PWSTR)ScepAlloc(0, CurrentBytes+9);
}
else {
StrValue = (PWSTR)ScepAlloc(0, CurrentBytes+8); // 4 wide chars: one for type, one delim, and two NULL
}
if ( StrValue ) {
memset(StrValue, 0, sizeof(StrValue));
*((CHAR *)StrValue) = (BYTE)RegType + '0';
if ( Status == 0) {
*((CHAR *)StrValue+1) = SCE_STATUS_MISMATCH + '0';
} else {
*((CHAR *)StrValue+1) = (BYTE)Status + '0';
}
StrValue[1] = L'\0';
if ( CurrentValue ) {
if (REG_BINARY == RegType && CurrentBytes == 1) {
swprintf(StrValue+2, L"%d", *CurrentValue);
}
else {
memcpy(StrValue+2, (PBYTE)CurrentValue, CurrentBytes);
}
}
if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
StrValue[CurrentBytes/2+3] = L'\0';
StrValue[CurrentBytes/2+4] = L'\0';
}
else {
StrValue[CurrentBytes/2+2] = L'\0';
StrValue[CurrentBytes/2+3] = L'\0';
}
if ( REG_MULTI_SZ == RegType || REG_QWORD == RegType ) {
//
// convert the , to null
//
ScepConvertMultiSzToDelim(StrValue+2, CurrentBytes/2, L',', L'\0');
}
if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
rc = SceJetSetLine( hSection, Name, FALSE, StrValue, CurrentBytes+7, 0);
}
else {
rc = SceJetSetLine( hSection, Name, FALSE, StrValue, CurrentBytes+6, 0);
}
ScepFree(StrValue);
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
switch (Status) {
case SCE_STATUS_ERROR_NOT_AVAILABLE:
ScepLogOutput3(2, 0, SCEDLL_STATUS_ERROR, Name);
break;
case SCE_STATUS_NOT_CONFIGURED:
ScepLogOutput3(2, 0, SCEDLL_STATUS_NC, Name);
break;
default:
ScepLogOutput3(2, 0, SCEDLL_STATUS_MISMATCH, Name);
break;
}
return(rc);
}
SCESTATUS
ScepSaveRegistryValueToBuffer(
IN DWORD RegType,
IN PWSTR Value,
IN DWORD dwBytes,
IN OUT PSCE_REGISTRY_VALUE_INFO pRegValues
)
/* ++
Routine Description:
This routine saves the registry value to the buffer
Arguments:
RegType - the registry value type
Value - The current system setting
dwBytes - The length of the current setting
pRegValues - the buffer for this registry value to save to
-- */
{
SCESTATUS rc=SCESTATUS_SUCCESS;
if ( pRegValues == NULL ) {
return(SCESTATUS_INVALID_PARAMETER);
}
if ( Value == NULL || dwBytes == 0 ) {
// nothing to save
return(SCESTATUS_SUCCESS);
}
//
// build a buffer containing type and value
// note MULTI_SZ must be converted to null delimited
//
if ( REG_DWORD == RegType ) {
TCHAR StrValue[20];
DWORD *pdwValue = (DWORD *)Value;
memset(StrValue, '\0', 40);
_ultow(*pdwValue, StrValue, 10);
PWSTR pValue = (PWSTR)ScepAlloc(0, (wcslen(StrValue)+1)*2);
if ( pValue ) {
wcscpy(pValue, StrValue);
pRegValues->Value = pValue;
pRegValues->ValueType = RegType;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
} else {
PWSTR StrValue;
if ( (dwBytes % 2) && REG_BINARY == RegType ) {
StrValue = (PWSTR)ScepAlloc(LPTR, dwBytes+5);
} else {
StrValue = (PWSTR)ScepAlloc(LPTR, dwBytes+4); // 2 wide chars: two NULL
}
if ( StrValue ) {
if (REG_BINARY == RegType && dwBytes == 1) {
swprintf(StrValue, L"%d", *Value);
} else {
memcpy(StrValue, (PBYTE)Value, dwBytes);
}
if ( (dwBytes % 2) && REG_BINARY == RegType ) {
StrValue[dwBytes/2+1] = L'\0';
StrValue[dwBytes/2+2] = L'\0';
}
else {
StrValue[dwBytes/2+0] = L'\0';
StrValue[dwBytes/2+1] = L'\0';
}
pRegValues->Value = StrValue;
pRegValues->ValueType = RegType;
} else {
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
}
}
return(rc);
}
SCESTATUS
ScepEnumAllRegValues(
IN OUT PDWORD pCount,
IN OUT PSCE_REGISTRY_VALUE_INFO *paRegValues
)
/*
Routine Description:
Enumerate all registry values supported by SCE from registry.
Arguments:
pCount - the number of reg values to output
paRegValues - the array of registry values to output
Return Value:
*/
{
DWORD Win32Rc;
HKEY hKey=NULL;
PSCE_NAME_STATUS_LIST pnsList=NULL;
DWORD nAdded=0;
Win32Rc = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
SCE_ROOT_REGVALUE_PATH,
0,
KEY_READ,
&hKey
);
DWORD cSubKeys = 0;
DWORD nMaxLen;
if ( Win32Rc == ERROR_SUCCESS ) {
//
// enumerate all subkeys of the key
//
Win32Rc = RegQueryInfoKey (
hKey,
NULL,
NULL,
NULL,
&cSubKeys,
&nMaxLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
}
if ( Win32Rc == ERROR_SUCCESS && cSubKeys > 0 ) {
PWSTR szName = (PWSTR)ScepAlloc(0, (nMaxLen+2)*sizeof(WCHAR));
if ( !szName ) {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
} else {
DWORD BufSize;
DWORD index = 0;
do {
BufSize = nMaxLen+1;
Win32Rc = RegEnumKeyEx(
hKey,
index,
szName,
&BufSize,
NULL,
NULL,
NULL,
NULL);
if ( ERROR_SUCCESS == Win32Rc ) {
index++;
//
// get the full registry key name and Valuetype
//
cSubKeys = REG_SZ;
//
// query ValueType, if error, default REG_SZ
//
ScepRegQueryIntValue( hKey,
szName,
SCE_REG_VALUE_TYPE,
&cSubKeys
);
if ( cSubKeys < REG_SZ || cSubKeys > REG_MULTI_SZ ) {
cSubKeys = REG_SZ;
}
//
// convert the path name
//
ScepConvertMultiSzToDelim(szName, BufSize, L'/', L'\\');
//
// compare with the input array, if not exist,
// add it
//
for ( DWORD i=0; i<*pCount; i++ ) {
if ( (*paRegValues)[i].FullValueName &&
_wcsicmp(szName, (*paRegValues)[i].FullValueName) == 0 ) {
break;
}
}
if ( i >= *pCount ) {
//
// did not find a match, add it
//
if ( SCESTATUS_SUCCESS != ScepAddToNameStatusList(&pnsList,
szName,
BufSize,
cSubKeys) ) {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
break;
}
nAdded++;
}
} else if ( ERROR_NO_MORE_ITEMS != Win32Rc ) {
break;
}
} while ( Win32Rc != ERROR_NO_MORE_ITEMS );
if ( Win32Rc == ERROR_NO_MORE_ITEMS ) {
Win32Rc = ERROR_SUCCESS;
}
//
// free the enumeration buffer
//
ScepFree(szName);
}
}
if ( hKey ) {
RegCloseKey(hKey);
}
if ( ERROR_SUCCESS == Win32Rc ) {
//
// add the name list to the output arrays
//
DWORD nNewCount = *pCount + nAdded;
PSCE_REGISTRY_VALUE_INFO aNewArray;
if ( nNewCount ) {
aNewArray = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc(0, nNewCount*sizeof(SCE_REGISTRY_VALUE_INFO));
if ( aNewArray ) {
DWORD i;
for ( i=0; i<*pCount; i++ ) {
aNewArray[i].FullValueName = (*paRegValues)[i].FullValueName;
aNewArray[i].Value = (*paRegValues)[i].Value;
aNewArray[i].ValueType = (*paRegValues)[i].ValueType;
}
i=0;
for ( PSCE_NAME_STATUS_LIST pns=pnsList;
pns; pns=pns->Next ) {
if ( pns->Name && i < nAdded ) {
aNewArray[*pCount+i].FullValueName = pns->Name;
pns->Name = NULL;
aNewArray[*pCount+i].Value = NULL;
aNewArray[*pCount+i].ValueType = pns->Status;
i++;
}
}
//
// free the original array
// all components in the array are already transferred to the new array
//
ScepFree(*paRegValues);
*pCount = nNewCount;
*paRegValues = aNewArray;
} else {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
if ( ERROR_FILE_NOT_FOUND == Win32Rc ||
ERROR_PATH_NOT_FOUND == Win32Rc ) {
//
// no value has been registered
//
Win32Rc = ERROR_SUCCESS;
}
//
// free the name status list
//
SceFreeMemory(pnsList, SCE_STRUCT_NAME_STATUS_LIST);
return( ScepDosErrorToSceStatus(Win32Rc) );
}