/*++ 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 inftojet.c pfget.c config.c analyze.c 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 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; iRegValueCount; 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) ); }