|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: classchk.cxx
//
// Classchk is a program for verifying that the contents of the registry are
// OKY-DOKY as far as OLE is concerned.
//
// In general, we verify that all CLSID's are of the correct length, all string
// parameters are NULL terminated.
//
// There are several phases of checking.
//
// 1) Checking that PROGID entries that have CLSID sections match.
// 2) Checking that PROGID entries have correct and existing protocol entries
// 3) Checking that PROGID entries
//
// History: 5-31-95 kevinro Created
//
//----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <ctype.h>
#include "classchk.h"
//
// The following registry values are used quite a few times in this program.
// These global variables keep us from needing to open them constantly.
//
HKEY hkey_clsid = 0;
DWORD g_VerbosityLevel = VERB_LEVEL_WARN | VERB_LEVEL_ERROR;
#define StrICmp(x,y) (CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE,x,-1,y,-1) - 2)
//+---------------------------------------------------------------------------
//
// Function: ReadRegistryString
//
// Synopsis: Reads a string from the registry
//
// Effects:
//
// This function reads in a string from the registry, and does some basic
// consistency checking on it, such as verifying the length and NULL
// terminatation.
//
//
// Arguments: [hkeyRoot] --
// [pszSubKeyName] --
// [pszValueName] --
// [pszValue] --
// [pcbValue] --
//
// Returns: ERROR_SUCCESS Everything peachy
// ERROR_FILE_NOT_FOUND Couldn't read entry from registry
// CLASSCHK_SOMETHINGODD Something about the string is wrong
// (other) Return value from registry
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD ReadRegistryString( HKEY hkeyRoot, LPSTR pszSubKeyName, LPSTR pszValueName, LPSTR pszValue, PULONG pcbValue) { LONG lRetValue; DWORD dwType; DWORD dwReturn = ERROR_SUCCESS; HKEY hkey = hkeyRoot;
if(pszSubKeyName != NULL) { lRetValue = RegOpenKeyEx(hkeyRoot, pszSubKeyName, NULL, KEY_READ, &hkey);
//
// It is common to see keys that don't exist. Let the caller decide if it is
// important or not.
//
if(lRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_TRACE,printf("Unable to open subkey %s to read value %s\n",pszSubKeyName,pszValueName);); return lRetValue; } }
lRetValue = RegQueryValueEx(hkey, pszValueName, NULL, // Must be NULL according to spec
&dwType, (BYTE *)pszValue, pcbValue); if(hkeyRoot != hkey) { //
// Always close the new subkey if we opened it
//
RegCloseKey(hkey); }
switch(lRetValue) { case ERROR_SUCCESS: //
// Read the value, everything A-OK
//
break; case ERROR_MORE_DATA: VERBOSITY(VERB_LEVEL_WARN,printf("The value '%s' is larger than expected. May be a problem\n",pszValueName);) return lRetValue; break;
case ERROR_FILE_NOT_FOUND: //
// This may be expected, so don't report any errors. Let the caller handle that
//
return lRetValue; default: VERBOSITY(VERB_LEVEL_WARN,printf("RegQueryValueEx() for '%s' returned unexpected error 0x%x\n",pszValueName,lRetValue);) return lRetValue; }
//
// We expect this type to be REG_SZ. If it isn't, complain
//
if(dwType != REG_SZ) { VERBOSITY(VERB_LEVEL_WARN,printf("The value for '%s' is type 0x%x, was expecting REG_SZ (0x%x)\n",pszValueName,dwType,REG_SZ);) dwReturn = CLASSCHK_SOMETHINGODD; }
//
// We expect the value to be NULL terminated
//
if(pszValue[(*pcbValue)-1] != 0) {
VERBOSITY(VERB_LEVEL_WARN,printf("The value for '%s' may not be NULL terminated.\n",pszValueName);) }
//
// We expect strlen to be the same as the length returned (which includes the NULL)
//
if((strlen(pszValue) + 1) != *pcbValue) { VERBOSITY(VERB_LEVEL_WARN,printf("The string value for '%s' may not have the correct length\n",pszValueName);) if(dwType == REG_SZ) { VERBOSITY(VERB_LEVEL_WARN,printf("The string value is '%s'\n",pszValue);) } dwReturn = CLASSCHK_SOMETHINGODD; }
return dwReturn; }
//+---------------------------------------------------------------------------
//
// Function: AllHexDigits
//
// Synopsis: Verify that all of the digits specified are hexidecimal
//
// Effects:
//
// Arguments: [pszString] -- String to check
// [chString] -- Number of characters
//
// Requires:
//
// Returns: TRUE All hex digits
// FALSE Not all hex digits
//
// History: 5-31-95 kevinro Created
//----------------------------------------------------------------------------
BOOL AllHexDigits(LPSTR pszString, ULONG chString) { while(chString--) { if(!isxdigit(pszString[chString])) { return FALSE; } } return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: CheckForValidGuid
//
// Synopsis: Given a string, determine if the string is a GUID
//
// Arguments: [pszValue] -- String to check
//
// History: 5-31-95 kevinro Created
//
//----------------------------------------------------------------------------
DWORD CheckForValidGuid(LPSTR pszValue) { DWORD dwResult = 0; if((strlen(pszValue) != 38) || (pszValue[0] != '{') || (pszValue[37] != '}')) { dwResult = CLASSCHK_SOMETHINGODD; } else { // Check the internals of the GUID.
if(!AllHexDigits(&pszValue[1],8) || pszValue[9] != '-' || !AllHexDigits(&pszValue[10],4) || pszValue[14] != '-' || !AllHexDigits(&pszValue[15],4) || pszValue[19] != '-' || !AllHexDigits(&pszValue[20],4) || pszValue[24] != '-' || !AllHexDigits(&pszValue[25],12) ) { dwResult = CLASSCHK_SOMETHINGODD; } } return dwResult; }
//+---------------------------------------------------------------------------
//
// Function: ReadRegistryGuid
//
// Synopsis: Read a GUID from the registry, and check to see if it is valid.
//
// Arguments: [hkey] -- Key to start from
// [pszSubKeyName] -- Subkey relative to hkey (NULL if hkey)
// [pszValueName] -- Value name (NULL if default value)
// [pszValue] -- Pointer to return buffer
// [pcbValue] -- Size of return buffer in characters
//
// Returns: ERROR_SUCCESS Read and verified GUID
// (other) Something is wrong
// ERROR_FILE_NOT_FOUND Key didn't exist
// CLASSCHK_SOMETHINGODD Read key, but something is wrong with it.
//
// History: 5-31-95 kevinro Created
//
//----------------------------------------------------------------------------
DWORD ReadRegistryGuid( HKEY hkey, LPSTR pszSubKeyName, LPSTR pszValueName, LPSTR pszValue, PULONG pcbValue) { DWORD dwResult; //
// First, just read the value from the registry.
//
dwResult = ReadRegistryString(hkey, pszSubKeyName, pszValueName, pszValue, pcbValue);
if(dwResult == ERROR_SUCCESS) { //
// Do some additional basic checking, such as the length being correct, and the
// GUID correctly formed.
//
dwResult = CheckForValidGuid(pszValue); if(dwResult != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("*** Malformed GUID '%s' ***\n",pszValue);) }
} return dwResult; }
//+---------------------------------------------------------------------------
//
// Function: ReadRegistryFile
//
// Synopsis: Read a registry entry which is supposed to be a file,
// and determine if the file exists
//
// Arguments: [hkey] -- Key to start from
// [pszSubKeyName] -- Subkey relative to hkey (NULL if hkey)
// [pszValueName] -- Value name (NULL if default value)
// [pszValue] -- Pointer to return buffer
// [pcbValue] -- Size of return buffer in characters
//
// Returns: ERROR_SUCCESS Read and verified
// (other) Something is wrong
// ERROR_FILE_NOT_FOUND Key didn't exist
// CLASSCHK_SOMETHINGODD Read key, but something is wrong with it.
//
// History: 5-31-95 kevinro Created
//
//----------------------------------------------------------------------------
ReadRegistryFile(HKEY hkey, LPSTR pszSubKeyName, LPSTR pszValueName, LPSTR pszValue, PULONG pcbValue) { DWORD dwResult; //
// First, just read the value from the registry.
//
dwResult = ReadRegistryString(hkey, pszSubKeyName, pszValueName, pszValue, pcbValue);
if (dwResult == ERROR_SUCCESS) { char achFoundPath[MAX_PATH]; char *pszFileNamePart; //
// Some apps append a switch at the end.
// If there is a switch, terminate the path at that point
//
if(pszFileNamePart = strchr(pszValue,'/')) { *pszFileNamePart = 0; } else if(pszFileNamePart = strchr(pszValue,'-')) { //
// Some applications also use the '-' character
// as a switch delimiter. If this character is in
// the string, and the previous character is a space,
// then assume it is a delimiter. This isn't foolproof,
// but it should work most of the time.
//
if(pszFileNamePart[-1] == ' ') { *pszFileNamePart = 0; } }
if(SearchPath(NULL,pszValue,NULL,MAX_PATH,achFoundPath,&pszFileNamePart) == 0) { //
// Didn't find the name in the path.
//
VERBOSITY(VERB_LEVEL_ERROR,printf("*** Could not find path '%s' ***\n",pszValue)); dwResult = CLASSCHK_SOMETHINGODD;
} else { VERBOSITY(VERB_LEVEL_TRACE,printf("Found path %s (%s)\n",achFoundPath,pszValue)); }
}
return dwResult; }
//+---------------------------------------------------------------------------
//
// Function: CheckProgID
//
// Synopsis:
//
// Given a PROGID entry, do some checking to insure the entry is sane. Of the things to check,
// we should check to insure the name string is readable. If there is a CLSID entry, we should
// check to see if it has a CLSID in it.
//
//
// Arguments: [pszProgID] -- PROGID string to check
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD CheckProgID(LPSTR pszProgID) {
LONG lRetValue = 0; char achValue[MAX_PATH]; DWORD cbValue; DWORD dwRetValue; HKEY progidKey = NULL;
lRetValue = RegOpenKeyEx(HKEY_CLASSES_ROOT, pszProgID, NULL, KEY_READ, &progidKey);
if(lRetValue == ERROR_SUCCESS) { cbValue = MAX_PATH; //
// Read the default key value for the PROGID. Normally, this should be the name of the class name
// or program name that would be shown.
//
dwRetValue = ReadRegistryString(progidKey,NULL,NULL,achValue,&cbValue);
if(dwRetValue == CLASSCHK_SOMETHINGODD) { VERBOSITY(VERB_LEVEL_WHINE,printf("HKEY_CLASSES_ROOT\\%s found odd description '%s'\n",pszProgID,achValue);) }
cbValue = MAX_PATH;
dwRetValue = ReadRegistryGuid(progidKey,"CLSID",NULL,achValue,&cbValue);
switch(dwRetValue) { case ERROR_SUCCESS: break; case ERROR_FILE_NOT_FOUND: // Not all of these entries will have a CLSID section
break; default: VERBOSITY(VERB_LEVEL_ERROR, printf("*** Possible invalid CLSID in HKEY_CLASSES_ROOT\\%s\\CLSID\n",pszProgID);) }
if(dwRetValue == ERROR_SUCCESS) { char achValue2[MAX_PATH]; DWORD cbValue2 = MAX_PATH; //
// We appear to have a valid CLSID. Check for existence of the CLSID. We are actually only
// interested in it being found or not.
//
dwRetValue = ReadRegistryString(hkey_clsid,achValue,NULL,achValue2,&cbValue2); if(dwRetValue == ERROR_FILE_NOT_FOUND) { VERBOSITY(VERB_LEVEL_ERROR,printf("ProgID %s has CLSID %s. Unable to find HKEY_CLASSES_ROOT\\CLSID\\%s\n",pszProgID,achValue,achValue);) } }
//
// Check to see if there is an OLE 1.0 section that specifies protocol\stdfileediting\server
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryFile(progidKey,"protocol\\stdfileediting\\server",NULL,achValue,&cbValue); if(dwRetValue == CLASSCHK_SOMETHINGODD) { VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\%s\\Protocol\\StdFileEditing\\server may have invalid entry\n",pszProgID);) } } else { VERBOSITY(VERB_LEVEL_WARN,printf("Unable to open HKEY_CLASSES_ROOT\\%s\n",pszProgID);) }
if(progidKey != NULL) { RegCloseKey(progidKey); } return 0; }
//
// Given an extention (ie something that starts with a '.'), determine if the mapping to PROGID is correct
//
DWORD CheckExtentionToProgID(LPSTR pszExtention) {
LONG lRetValue = 0; char achValue[MAX_PATH]; DWORD cbValue; DWORD dwRetValue; HKEY subKey = NULL; HKEY progidKey = NULL;
lRetValue = RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExtention, NULL, KEY_READ, &subKey);
if(lRetValue == ERROR_SUCCESS) { cbValue = MAX_PATH; //
// Read the default key value for the extention. Normally, this should point to a
// PROGID.
//
dwRetValue = ReadRegistryString(subKey,NULL,NULL,achValue,&cbValue); VERBOSITY(VERB_LEVEL_TRACE,printf("HKEY_CLASSES_ROOT\\%s = %s\n",pszExtention,achValue);)
if(dwRetValue == CLASSCHK_SOMETHINGODD) { VERBOSITY(VERB_LEVEL_WARN,printf("Reading HKEY_CLASSES_ROOT\\%s found something odd\n",pszExtention);) } //
// If it is an extension, the value should be a PROGID.Take a look to see if it is.
//
lRetValue = RegOpenKeyEx(HKEY_CLASSES_ROOT, achValue, NULL, KEY_READ, &progidKey); //
// It should have been there. If it wasn't, then report a strangeness
//
switch(lRetValue) { case ERROR_SUCCESS: //
// The PROGID actually existed. We will verify its contents later.
//
break; case ERROR_FILE_NOT_FOUND: //
// The PROGID doesn't exist. This could be a potential problem in the registry. Report it.
//
VERBOSITY(VERB_LEVEL_ERROR, printf("HKEY_CLASSES_ROOT\\%s **** PROGID '%s' didn't exist ***\n*** Check Registry ***\n", pszExtention, achValue);) break; default: VERBOSITY(VERB_LEVEL_WARN,printf("Unexpected error opening HKEY_CLASSES_ROOT\\%s (error 0x%x)\n",achValue,lRetValue);)
}
} else { VERBOSITY(VERB_LEVEL_WARN,printf("Unable to open HKEY_CLASSES_ROOT\\%s\n",pszExtention);) }
if(subKey != NULL) RegCloseKey(subKey); if(progidKey != NULL) RegCloseKey(progidKey); return 0; }
//+---------------------------------------------------------------------------
//
// Function: CheckOLE1CLSID
//
// Synopsis: CheckOLE1CLSID looks at CLSID's that are typically OLE 1.0.
// This includes checking for AutoConvert, checking the PROGID,
// and checking that the Ole1Class key exists.
//
// Arguments: [pszCLSID] -- Name of OLE 1.0 CLASSID to check
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD CheckOLE1CLSID(LPSTR pszCLSID) { LONG lRetValue = 0; char achValue[MAX_PATH]; DWORD cbValue; DWORD dwRetValue; HKEY subKey = NULL; BOOL fFoundAServer = FALSE; char achValue2[MAX_PATH]; DWORD cbValue2 = MAX_PATH;
lRetValue = RegOpenKeyEx(hkey_clsid,pszCLSID,NULL,KEY_READ,&subKey);
if(lRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("Unable to open HKEY_CLASSES_ROOT\\CLSID\\%s error 0x%x\n",pszCLSID,lRetValue);) return CLASSCHK_SOMETHINGODD; }
//
// Check to insure that there is an Ole1Class entry
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryString(subKey,"Ole1Class",NULL,achValue,&cbValue); switch(dwRetValue) { case ERROR_FILE_NOT_FOUND: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s is missing its Ole1Class key\n",pszCLSID);) break; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\Ole1Class key is odd\n",pszCLSID);)
}
//
// Quite often, there will be a AutoConvertTo key, which is supposed to be a GUID
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryGuid(subKey,"AutoConvertTo",NULL,achValue,&cbValue); switch(dwRetValue) { case ERROR_SUCCESS: //
// The CLSID should normally point to another class, such as the 2.0 version. Check to
// insure the CLSID exists
//
dwRetValue = ReadRegistryString(hkey_clsid,achValue,NULL,achValue2,&cbValue2); if(dwRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\AutoConvertTo key is odd\n",pszCLSID);) switch(dwRetValue) { case ERROR_FILE_NOT_FOUND:
VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s doesn't appear to exist\n",achValue);) break; } }
break; case ERROR_FILE_NOT_FOUND: //
// This entry isn't required. If it doesn't exist, no big deal.
//
break; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\AutoConvertTo key is odd\n",pszCLSID);) break;
}
//
// It would be abnormal to find a missing PROGID key
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryString(subKey,"ProgID",NULL,achValue,&cbValue); switch(dwRetValue) { case ERROR_SUCCESS: //
// The PROGID should normally point to a valid PROGID
//
cbValue2 = MAX_PATH; dwRetValue = ReadRegistryString(HKEY_CLASSES_ROOT,achValue,NULL,achValue2,&cbValue2); if(dwRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\PROGID key is odd\n",pszCLSID);) switch(dwRetValue) { case ERROR_FILE_NOT_FOUND:
VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\%s doesn't appear to exist\n",achValue);) break; } }
break; case ERROR_FILE_NOT_FOUND: //
// This entry is required.
//
VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\PROGID key is missing\n",pszCLSID);)
break; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\Ole1Class key is odd\n",pszCLSID);)
}
return dwRetValue; }
//+---------------------------------------------------------------------------
//
// Function: CheckForDLL
//
// Synopsis: Given a CLSID, its hkey, and the name of the DLL value,
// determine if the DLL exists as a file, and if the threading
// model value is appropriate.
//
// Arguments: [pszCLSID] -- Name of the CLSID (for debug output)
// [hkeyCLSID] -- HKEY for the clsid
// [pszDLLKey] -- Name of the subkey to check for
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD CheckForDLL(LPSTR pszCLSID, HKEY hkeyCLSID, LPSTR pszDLLKey) { LONG lRetValue = 0; char achValue[MAX_PATH]; DWORD cbValue; DWORD dwRetValue; char achThreadModel[MAX_PATH]; DWORD cbThreadModel = MAX_PATH; //
// The DLL name should be in
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryFile(hkeyCLSID,pszDLLKey,NULL,achValue,&cbValue);
switch(dwRetValue) { case ERROR_FILE_NOT_FOUND: //
// The registry key didn't exist. Thats normally OK.
//
return dwRetValue; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\%s key is odd\n",pszCLSID,pszDLLKey);) return dwRetValue; }
//
// If the DLL exists, check to see if the ThreadingModelKey is valid
//
dwRetValue = ReadRegistryString(hkeyCLSID,pszDLLKey,"ThreadingModel",achThreadModel,&cbThreadModel); switch(dwRetValue) { case ERROR_FILE_NOT_FOUND: //
// The registry key didn't exist. Thats normally OK.
//
return ERROR_SUCCESS; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\%s\\ThreadingModel value is odd\n",pszCLSID,pszDLLKey);) return dwRetValue; }
//
// Check to insure the threading model is something we understand
//
if( StrICmp( achThreadModel, "Apartment") && StrICmp( achThreadModel, "Both") && StrICmp( achThreadModel, "Free")) { VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\%s\\ThreadingModel value is %s\n",pszCLSID,pszDLLKey,achThreadModel);) VERBOSITY(VERB_LEVEL_WARN,printf("Expected 'Apartment','Both', or 'Free'");) return CLASSCHK_SOMETHINGODD; } return ERROR_SUCCESS; }
//+---------------------------------------------------------------------------
//
// Function: CheckCLSIDEntry
//
// Synopsis: Given the name of a CLSID entry, verify that the entry is
// valid by looking for the 'usual' key information, and
// cross checking it against things that we assert should be
// true.
// Effects:
//
// Arguments: [pszCLSID] -- CLSID in a string form. Used to open key
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD CheckCLSIDEntry(LPSTR pszCLSID) { LONG lRetValue = 0; char achValue[MAX_PATH]; DWORD cbValue; char achPROGID[MAX_PATH]; DWORD cbPROGID = MAX_PATH; char achPROGIDPath[MAX_PATH]; DWORD cbPROGIDPath = MAX_PATH; char achPROGIDValue[MAX_PATH]; DWORD cbPROGIDValue = MAX_PATH;
LPSTR pszLocalServer = "LocalServer32"; DWORD dwRetValue; HKEY subKey = NULL; BOOL fFoundAServer = FALSE;
lRetValue = RegOpenKeyEx(hkey_clsid, pszCLSID, NULL, KEY_READ, &subKey);
if(lRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("Unable to open HKEY_CLASSES_ROOT\\CLSID\\%s error 0x%x\n",pszCLSID,lRetValue);) return CLASSCHK_SOMETHINGODD; }
//
// Basic sanity check: Is the description string a valid string
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryString(subKey,NULL,NULL,achValue,&cbValue); if(dwRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_WHINE,printf("HKEY_CLASSES_ROOT\\CLSID\\%s has odd description string\n",pszCLSID);) }
//
// A CLSID entry typically has several values. Least of which is supposed to be one or more of the following:
// InprocHandler
// InprocServer
// LocalServer
// InprocHandler32
// InprocServer32
// LocalServer32
//
// It may also have an optional PROGID entry, which we can use to verify that that the LocalServer and
// the protocol\StdFileEditing\server entries match.
//
// Another couple of things to watch for include checking the Inproc entries for ThreadingModel,
//
// Yet another thing to look at is the value of the CLSID itself. If the first 4 digits are 0003 or 0004, then
// the CLSID is for an OLE 1.0 class, and we need to do a seperate check
//
if((strncmp(&pszCLSID[1],"0003",4) == 0) || (strncmp(&pszCLSID[1],"0004",4) == 0) ) { //
// In theory, this is supposed to be an OLE1CLASS. Check it seperately
//
RegCloseKey(subKey); return CheckOLE1CLSID(pszCLSID); }
dwRetValue = CheckForDLL(pszCLSID, subKey, "InprocHandler"); dwRetValue = CheckForDLL(pszCLSID, subKey, "InprocHandler32");
dwRetValue = CheckForDLL(pszCLSID, subKey, "InprocServer"); if(dwRetValue != ERROR_FILE_NOT_FOUND) fFoundAServer++;
dwRetValue = CheckForDLL(pszCLSID, subKey, "InprocServer32"); if(dwRetValue != ERROR_FILE_NOT_FOUND) fFoundAServer++;
//
// First, check for LocalServer32. If that doesn't exist, then try for
// LocalServer.
//
cbValue = MAX_PATH; dwRetValue = ReadRegistryFile(subKey,pszLocalServer,NULL,achValue,&cbValue); if(dwRetValue == ERROR_FILE_NOT_FOUND) { cbValue = MAX_PATH; pszLocalServer = "LocalServer"; dwRetValue = ReadRegistryFile(subKey,pszLocalServer,NULL,achValue,&cbValue); if(dwRetValue == CLASSCHK_SOMETHINGODD) { VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\LocalServer32 is odd\n",pszCLSID);)
} } else if(dwRetValue == CLASSCHK_SOMETHINGODD) { VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\%s is odd\n",pszCLSID,pszLocalServer);)
}
if(dwRetValue == ERROR_SUCCESS) { fFoundAServer++; //
// We have a valid LocalServer. Lets get the PROGID's version of the local server, and compare the
// two. They should compare.
//
dwRetValue = ReadRegistryString(subKey,"PROGID",NULL,achPROGID,&cbPROGID); switch(dwRetValue) { case ERROR_FILE_NOT_FOUND: //
// Most CLSID's should indeed have a PROGID, but it isn't 100% required.
//
VERBOSITY(VERB_LEVEL_WHINE,printf("HKEY_CLASSES_ROOT\\CLSID\\%s missing a PROGID entry\n",pszCLSID);) break; case CLASSCHK_SOMETHINGODD: VERBOSITY(VERB_LEVEL_WARN,printf("HKEY_CLASSES_ROOT\\CLSID\\%s PROGID entry is odd\n",pszCLSID);) break; default: sprintf(achPROGIDPath,"%s\\protocol\\stdfileediting\\server",achPROGID); dwRetValue = ReadRegistryFile(HKEY_CLASSES_ROOT,achPROGIDPath,NULL,achPROGIDValue,&cbPROGIDValue); //
// The only thing we are interested in checking is if the two strings compare.
//
if(dwRetValue == ERROR_SUCCESS) { if(StrICmp(achPROGIDValue,achValue) != 0) { VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\CLSID\\%s is inconsistent with its PROGID\n",pszCLSID);) VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\%s = '%s'\n",achPROGIDPath,achPROGIDValue);) VERBOSITY(VERB_LEVEL_ERROR,printf("HKEY_CLASSES_ROOT\\CLSID\\%s\\%s = '%s'\n",pszCLSID,pszLocalServer,achValue);)
} } } }
if(!fFoundAServer) { VERBOSITY(VERB_LEVEL_ERROR,printf("*** Unable to find a valid server for HKEY_CLASSES_ROOT\\CLSID\\%s ***\n",pszCLSID);) }
RegCloseKey(subKey);
return dwRetValue; }
//+---------------------------------------------------------------------------
//
// Function: EnumerateClsidRoot
//
// Synopsis: Enumerate and check each entry in the CLSID section
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD EnumerateClsidRoot() { LONG lRetValue = 0; DWORD iSubKey = 0; char achKeyName[MAX_PATH]; DWORD cbKeyName; FILETIME filetime;
while(1) { cbKeyName = MAX_PATH;
lRetValue = RegEnumKeyEx(hkey_clsid, iSubKey, achKeyName, &cbKeyName, NULL, NULL, NULL, &filetime);
if(lRetValue == ERROR_NO_MORE_ITEMS) { // End of enumeration
break; }
if(lRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("EnumerateClsidRoot:RegEnumKeyEx returned %x\n",lRetValue);) return CLASSCHK_ERROR; }
//
// Each of the sub keys enumerated here is expected to be a GUID. If it isn't a GUID, then it
// might be some other random garbage that we don't care about.
//
if(CheckForValidGuid(achKeyName) == ERROR_SUCCESS) { CheckCLSIDEntry(achKeyName); }
iSubKey++; }
return 0; }
//+---------------------------------------------------------------------------
//
// Function: EnumerateClassesRoot
//
// Synopsis: Enumerate the root of HKEY_CLASSES, and check each entry
// based on what we think it should be.
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD EnumerateClassesRoot() { LONG lRetValue = 0; DWORD iSubKey = 0; char achKeyName[MAX_PATH]; DWORD cbKeyName; FILETIME filetime;
while(1) { cbKeyName = MAX_PATH; lRetValue = RegEnumKeyEx(HKEY_CLASSES_ROOT, iSubKey, achKeyName, &cbKeyName, NULL, NULL, NULL, &filetime);
if(lRetValue == ERROR_NO_MORE_ITEMS) { // End of enumeration
break; }
if(lRetValue != ERROR_SUCCESS) { VERBOSITY(VERB_LEVEL_ERROR,printf("EnumerateClassesRoot:RegEnumKeyEx returned %x\n",lRetValue);) return CLASSCHK_ERROR; }
//
// We expect to find two basic things at the HKEY_CLASSES_ROOT level.
// First are extention mappings, second are PROGID's. There is also
// the special cases of CLSID, Interface, and FileType, which are
// checked differently
//
if(StrICmp(achKeyName,"CLSID") == 0) { // The CLSID section is done later
} else if(StrICmp(achKeyName,"Interface") == 0) { // The interface section is done later
} else if(StrICmp(achKeyName,"FileType") == 0) { // The FileType entry is done later
} else if(achKeyName[0] == '.') { // File extentions start with dots.
// Call the Check Extention function here
CheckExtentionToProgID(achKeyName); } else { // Assume it may be a PROGID. Call the PROGID function here.
CheckProgID(achKeyName); }
iSubKey++; }
return 0; }
//+---------------------------------------------------------------------------
//
// Function: main
//
// Synopsis: Main entry point for program. Does what main entry points
// usually do.
//
// Arguments: [argc] --
// [argv] --
//
// History: 5-31-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
int _cdecl main(int argc, char *argv[]) { LONG lRetValue = 0;
//
// HKEY_CLASSES_ROOT is often used.
//
lRetValue = RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", NULL, KEY_READ, &hkey_clsid);
if(lRetValue != ERROR_SUCCESS) { printf("Couldn't open HKEY_CLASSES_ROOT\\CLSID\n"); return(1); }
//
// Enumerate different parts of the registry, reporting
// errors as we go.
//
EnumerateClassesRoot(); EnumerateClsidRoot();
RegCloseKey(hkey_clsid); return 0;
}
|