//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: catadnew.cpp // // Contents: Microsoft Internet Security Catalog Utilities // // Functions: CryptCATAdminAcquireContext // CryptCATAdminReleaseContext // CryptCATAdminAddCatalog // CryptCATAdminRemoveCatalog // CryptCATAdminEnumCatalogFromHash // CryptCATCatalogInfoFromContext // CryptCATAdminReleaseCatalogContext // CryptCATAdminResolveCatalogPath // CryptCATAdminPauseServiceForBackup // CryptCATAdminCalcHashFromFileHandle // I_CryptCatAdminMigrateToNewCatDB // CatAdminDllMain // // History: 01-Jan-2000 reidk created // //-------------------------------------------------------------------------- #include "global.hxx" #include "cryptreg.h" #include "wintrust.h" #include "softpub.h" #include "eventlst.h" #include "sipguids.h" #include "mscat32.h" #include "catdb.h" #include "voidlist.h" #include "catutil.h" #include "..\..\common\catdbsvc\catdbcli.h" #include "errlog.h" #define MAX_HASH_LEN 20 // // default system guid for apps that just make calls to CryptCATAdminAddCatalog with // hCatAdmin == NULL... // // {127D0A1D-4EF2-11d1-8608-00C04FC295EE} // #define DEF_CAT_SUBSYS_ID \ { \ 0x127d0a1d, \ 0x4ef2, \ 0x11d1, \ { 0x86, 0x8, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee } \ } #define WSZ_CATALOG_FILE_BASE_DIRECTORY L"CatRoot" #define WSZ_DATABASE_FILE_BASE_DIRECTORY L"CatRoot2" #define WSZ_REG_FILES_NOT_TO_BACKUP L"System\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup" #define WSZ_REG_CATALOG_DATABASE_VALUE L"Catalog Database" #define WSZ_PATH_NOT_TO_BACKUP L"%SystemRoot%\\System32\\CatRoot2\\* /s\0" static WCHAR *gpwszDatabaseFileBaseDirectory = NULL; static WCHAR *gpwszCatalogFileBaseDirectory = NULL; #define WSZ_CATALOG_SUBSYTEM_SEARCH_STRING L"{????????????????????????????????????}" #define CATADMIN_LOGERR_LASTERR() ErrLog_LogError(NULL, \ ERRLOG_CLIENT_ID_CATADMIN, \ __LINE__, \ 0, \ FALSE, \ FALSE); #define CATADMIN_SETERR_LOG_RETURN(x, y) SetLastError(x); \ ErrLog_LogError(NULL, \ ERRLOG_CLIENT_ID_CATADMIN, \ __LINE__, \ 0, \ FALSE, \ FALSE); \ goto y; typedef struct CATALOG_INFO_CONTEXT_ { HANDLE hMappedFile; BYTE *pbMappedFile; WCHAR *pwszCatalogFile; PCCTL_CONTEXT pCTLContext; BOOL fResultOfAdd; } CATALOG_INFO_CONTEXT; typedef struct CRYPT_CAT_ADMIN_ { DWORD cbStruct; BOOL fUseDefSubSysId; LPWSTR pwszSubSysGUID; LPWSTR pwszCatalogFileDir; // full path to .cat files LPWSTR pwszDatabaseFileDir; // full path to CatDB file DWORD dwLastDBError; LIST CatalogInfoContextList; int nOpenCatInfoContexts; CRITICAL_SECTION CriticalSection; BOOL fCSInitialized; BOOL fCSEntered; HANDLE hClearCacheEvent; HANDLE hRegisterWaitForClearCache; BOOL fRegisteredForChangeNotification; } CRYPT_CAT_ADMIN; #define CATINFO_CONTEXT_ALLOCATION_SIZE 64 LPWSTR ppwszFilesToDelete[] = {L"hashmast.cbd", L"hashmast.cbk", L"catmast.cbd", L"catmast.cbk", L"sysmast.cbd", L"sysmast.cbk"}; #define NUM_FILES_TO_DELETE (sizeof(ppwszFilesToDelete) / \ sizeof(ppwszFilesToDelete[0])) BOOL _CatAdminMigrateSingleDatabase( LPWSTR pwszDatabaseGUID); BOOL _CatAdminSetupDefaults(void); void _CatAdminCleanupDefaults(void); BOOL _CatAdminTimeStampFilesInSync( LPWSTR pwszDatabaseGUID, BOOL *pfInSync); BOOL _CatAdminRegisterForChangeNotification( CRYPT_CAT_ADMIN *pCatAdmin ); BOOL _CatAdminFreeCachedCatalogs( CRYPT_CAT_ADMIN *pCatAdmin ); VOID CALLBACK _CatAdminWaitOrTimerCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired ); BOOL _CatAdminAddCatalogsToCache( CRYPT_CAT_ADMIN *pCatAdmin, LPWSTR pwszSubSysGUID, CRYPT_DATA_BLOB *pCryptDataBlob, LIST_NODE **ppFirstListNodeAdded ); BOOL _CatAdminAddSingleCatalogToCache( CRYPT_CAT_ADMIN *pCatAdmin, LPWSTR pwszCatalog, LIST_NODE **ppListNodeAdded ); BOOL _CatAdminMigrateCatalogDatabase( LPWSTR pwszFrom, LPWSTR pwszTo ); void _CatAdminBToHex ( LPBYTE pbDigest, DWORD iByte, LPWSTR pwszHashTag ); BOOL _CatAdminCreateHashTag( BYTE *pbHash, DWORD cbHash, LPWSTR *ppwszHashTag, CRYPT_DATA_BLOB *pCryptDataBlob ); BOOL _CatAdminRecursiveCreateDirectory( IN LPCWSTR pwszDir, LPSECURITY_ATTRIBUTES lpSecurityAttributes ); LPWSTR _CatAdminCreatePath( IN LPCWSTR pwsz1, IN LPCWSTR pwsz2, IN BOOL fAddEndingSlash ); void __RPC_FAR * __RPC_API MIDL_user_allocate(size_t len) { return(LocalAlloc(LMEM_ZEROINIT, len)); } void __RPC_API MIDL_user_free(void __RPC_FAR * ptr) { if (ptr != NULL) { LocalFree(ptr); } } //--------------------------------------------------------------------------------------- // // CryptCATAdminAcquireContext // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminAcquireContext_Internal( HCATADMIN *phCatAdmin, const GUID *pgSubsystem, DWORD dwFlags, BOOL fCalledFromMigrate) { GUID gDefault = DEF_CAT_SUBSYS_ID; const GUID *pgCatroot = &gDefault; CRYPT_CAT_ADMIN *pCatAdmin = NULL; BOOL fRet = TRUE; DWORD dwErr = 0; WCHAR wszGUID[256]; BOOL fInSync; // // Validata parameters // if (phCatAdmin == NULL) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } *phCatAdmin = NULL; // // Allocate a new CatAdmin state struct // if (NULL == (pCatAdmin = (CRYPT_CAT_ADMIN *) malloc(sizeof(CRYPT_CAT_ADMIN)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memset(pCatAdmin, 0, sizeof(CRYPT_CAT_ADMIN)); pCatAdmin->cbStruct = sizeof(CRYPT_CAT_ADMIN); LIST_Initialize(&(pCatAdmin->CatalogInfoContextList)); // // Check to see if caller specified the Catroot dir to use // if (pgSubsystem == NULL) { pCatAdmin->fUseDefSubSysId = TRUE; } else { pgCatroot = pgSubsystem; } guid2wstr(pgCatroot, wszGUID); // // Initialize the critical section // __try { InitializeCriticalSection(&(pCatAdmin->CriticalSection)); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } pCatAdmin->fCSInitialized = TRUE; pCatAdmin->fCSEntered = FALSE; // // Save a copy of the GUID as a string // if (NULL == (pCatAdmin->pwszSubSysGUID = (LPWSTR) malloc((wcslen(wszGUID) + 1) * sizeof(WCHAR)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } wcscpy(pCatAdmin->pwszSubSysGUID, wszGUID); // // Get the complete paths for the catalog files and the db file // if (NULL == (pCatAdmin->pwszCatalogFileDir = _CatAdminCreatePath( gpwszCatalogFileBaseDirectory, wszGUID, TRUE))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } if (NULL == (pCatAdmin->pwszDatabaseFileDir = _CatAdminCreatePath( gpwszDatabaseFileBaseDirectory, wszGUID, TRUE))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Make sure catalog file and database file sub-directories exists // if (!_CatAdminRecursiveCreateDirectory( pCatAdmin->pwszCatalogFileDir, NULL)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } if (!_CatAdminRecursiveCreateDirectory( pCatAdmin->pwszDatabaseFileDir, NULL)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Create the event which is notified when the catalog db changes, and register // a callback for when the event is signaled // if (NULL == (pCatAdmin->hClearCacheEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { CATADMIN_LOGERR_LASTERR() goto ErrorCreateEvent; } if (!RegisterWaitForSingleObject( &(pCatAdmin->hRegisterWaitForClearCache), pCatAdmin->hClearCacheEvent, _CatAdminWaitOrTimerCallback, pCatAdmin, INFINITE, WT_TRANSFER_IMPERSONATION)) { CATADMIN_LOGERR_LASTERR() goto ErrorRegisterWaitForSingleObject; } // // If we are being called by a real client (not the migrate code) then make sure // the TimeStamp files are in a consistent state, and if not, migrate (re-add) // the catalog files for that database // if (!fCalledFromMigrate) { if (_CatAdminTimeStampFilesInSync(wszGUID, &fInSync)) { if (!fInSync) { // // FIX FIX - may need to migrate // all DBs if the wszGUID is DEF_CAT_SUBSYS_ID // if (!_CatAdminMigrateSingleDatabase(wszGUID)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } } } else { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } } // // NOTE: // Defer registering with the service for the change notificatation so we // don't rely on the service during an acquire context // *phCatAdmin = (HCATADMIN)pCatAdmin; CommonReturn: return(fRet); ErrorReturn: if (pCatAdmin != NULL) { dwErr = GetLastError(); if (pCatAdmin->hRegisterWaitForClearCache != NULL) { UnregisterWaitEx( pCatAdmin->hRegisterWaitForClearCache, INVALID_HANDLE_VALUE); } // call UnregisterWaitEx before deteling the critical section // because the cb thread tries to enter it if (pCatAdmin->fCSInitialized) { DeleteCriticalSection(&(pCatAdmin->CriticalSection)); } if (pCatAdmin->hClearCacheEvent != NULL) { CloseHandle(pCatAdmin->hClearCacheEvent); } if (pCatAdmin->pwszSubSysGUID != NULL) { free(pCatAdmin->pwszSubSysGUID); } if (pCatAdmin->pwszCatalogFileDir != NULL) { free(pCatAdmin->pwszCatalogFileDir); } if (pCatAdmin->pwszDatabaseFileDir != NULL) { free(pCatAdmin->pwszDatabaseFileDir); } free(pCatAdmin); SetLastError(dwErr); } fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorMemory) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorRegisterWaitForSingleObject) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorCreateEvent) } BOOL WINAPI CryptCATAdminAcquireContext( OUT HCATADMIN *phCatAdmin, IN const GUID *pgSubsystem, IN DWORD dwFlags) { return (CryptCATAdminAcquireContext_Internal( phCatAdmin, pgSubsystem, dwFlags, FALSE)); } //--------------------------------------------------------------------------------------- // // CryptCATAdminReleaseContext // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminReleaseContext( IN HCATADMIN hCatAdmin, IN DWORD dwFlags) { CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; BOOL fRet = TRUE; // // Validate input params // if ((pCatAdmin == NULL) || (pCatAdmin->cbStruct != sizeof(CRYPT_CAT_ADMIN))) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } // // Un-Register for change notifications from DB process // // This needs to happen first thing, so that no callbacks // happen during cleanup // if (pCatAdmin->fRegisteredForChangeNotification) { Client_SSCatDBRegisterForChangeNotification( (DWORD_PTR) pCatAdmin->hClearCacheEvent, 0, pCatAdmin->pwszSubSysGUID, TRUE); } UnregisterWaitEx(pCatAdmin->hRegisterWaitForClearCache, INVALID_HANDLE_VALUE); CloseHandle(pCatAdmin->hClearCacheEvent); _CatAdminFreeCachedCatalogs(pCatAdmin); free(pCatAdmin->pwszSubSysGUID); free(pCatAdmin->pwszCatalogFileDir); free(pCatAdmin->pwszDatabaseFileDir); DeleteCriticalSection(&(pCatAdmin->CriticalSection)); free(pCatAdmin); CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) } //--------------------------------------------------------------------------------------- // // CryptCATAdminAddCatalog // //--------------------------------------------------------------------------------------- HCATINFO WINAPI CryptCATAdminAddCatalog( IN HCATADMIN hCatAdmin, IN WCHAR *pwszCatalogFile, IN WCHAR *pwszSelectBaseName, IN DWORD dwFlags) { CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; CATALOG_INFO_CONTEXT *pCatInfoContext = NULL; DWORD dwErr = 0; LPWSTR pwszCatalogNameUsed = NULL; LPWSTR pwszCatalogNameUsedCopy = NULL; LPWSTR pwszFullyQualifiedCatalogFile = NULL; DWORD dwLength = 0; LIST_NODE *pListNode = NULL; WCHAR wszTmp[1]; if ((pCatAdmin == NULL) || (pCatAdmin->cbStruct != sizeof(CRYPT_CAT_ADMIN)) || (pwszCatalogFile == NULL) || (dwFlags != 0)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } ErrLog_LogString(NULL, L"Adding Catalog File: ", pwszSelectBaseName, TRUE); // // first, check the catalog... // if (!(IsCatalogFile(INVALID_HANDLE_VALUE, pwszCatalogFile))) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } CATADMIN_SETERR_LOG_RETURN(ERROR_BAD_FORMAT, ErrorBadFileFormat) } EnterCriticalSection(&(pCatAdmin->CriticalSection)); pCatAdmin->fCSEntered = TRUE; if (!_CatAdminRegisterForChangeNotification(pCatAdmin)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Clear the cache, since doing the add may change things // _CatAdminFreeCachedCatalogs(pCatAdmin); // // If the file name specified by pwszCatalogFile is not a fully qualified // path name, we need to build one before calling the service. // if ((wcschr(pwszCatalogFile, L'\\') == NULL) && (wcschr(pwszCatalogFile, L':') == NULL)) { dwLength = GetCurrentDirectoryW(1, wszTmp) * sizeof(WCHAR); if (dwLength == 0) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } dwLength += (wcslen(pwszCatalogFile) + 1) * sizeof(WCHAR); if (NULL == (pwszFullyQualifiedCatalogFile = (LPWSTR) malloc(dwLength))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } if (!GetCurrentDirectoryW( dwLength / sizeof(WCHAR), pwszFullyQualifiedCatalogFile)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } if ((pwszFullyQualifiedCatalogFile[wcslen(pwszFullyQualifiedCatalogFile) - 1] != L'\\')) { wcscat(pwszFullyQualifiedCatalogFile, L"\\"); } wcscat(pwszFullyQualifiedCatalogFile, pwszCatalogFile); } // // Call the DB process to add the catalog // if (0 != (dwErr = Client_SSCatDBAddCatalog( 0, pCatAdmin->pwszSubSysGUID, (pwszFullyQualifiedCatalogFile != NULL) ? pwszFullyQualifiedCatalogFile : pwszCatalogFile, pwszSelectBaseName, &pwszCatalogNameUsed))) { CATADMIN_SETERR_LOG_RETURN(dwErr, ErrorCatDBProcess) } // // Touch the TimeStamp file // TimeStampFile_Touch(pCatAdmin->pwszCatalogFileDir); // // create a psuedo list entry, that really isn't part of the list... // this is so the caller can call CryptCATCatalogInfoFromContext // if (NULL == (pwszCatalogNameUsedCopy = (LPWSTR) malloc((wcslen(pwszCatalogNameUsed) + 1) * sizeof(WCHAR)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } wcscpy(pwszCatalogNameUsedCopy, pwszCatalogNameUsed); if (NULL == (pCatInfoContext = (CATALOG_INFO_CONTEXT *) malloc(sizeof(CATALOG_INFO_CONTEXT)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memset(pCatInfoContext, 0, sizeof(CATALOG_INFO_CONTEXT)); pCatInfoContext->pwszCatalogFile = pwszCatalogNameUsedCopy; pCatInfoContext->fResultOfAdd = TRUE; if (NULL == (pListNode = (LIST_NODE *) malloc(sizeof(LIST_NODE)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memset(pListNode, 0, sizeof(LIST_NODE)); pListNode->pElement = pCatInfoContext; CommonReturn: MIDL_user_free(pwszCatalogNameUsed); if (pwszFullyQualifiedCatalogFile != NULL) { free(pwszFullyQualifiedCatalogFile); } if ((pCatAdmin != NULL) && (pCatAdmin->fCSEntered)) { pCatAdmin->fCSEntered = FALSE; LeaveCriticalSection(&(pCatAdmin->CriticalSection)); } ErrLog_LogString(NULL, L"DONE Adding Catalog File: ", pwszSelectBaseName, TRUE); return((HCATINFO) pListNode); ErrorReturn: if (pwszCatalogNameUsedCopy != NULL) { free(pwszCatalogNameUsedCopy); } if (pCatInfoContext != NULL) { free(pCatInfoContext); } goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorBadFileFormat) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorCatDBProcess) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorMemory) } //--------------------------------------------------------------------------------------- // // CryptCATAdminRemoveCatalog // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminRemoveCatalog( IN HCATADMIN hCatAdmin, IN LPCWSTR pwszCatalogFile, IN DWORD dwFlags) { BOOL fRet = TRUE; DWORD dwErr = 0; CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; // // Call the DB process to delete the catalog // if (0 != (dwErr = Client_SSCatDBDeleteCatalog( 0, pCatAdmin->pwszSubSysGUID, pwszCatalogFile))) { CATADMIN_SETERR_LOG_RETURN(dwErr, ErrorCatDBProcess) } // // Touch the TimeStamp file // TimeStampFile_Touch(pCatAdmin->pwszCatalogFileDir); CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorCatDBProcess) } //--------------------------------------------------------------------------------------- // // CryptCATAdminEnumCatalogFromHash // //--------------------------------------------------------------------------------------- HCATINFO WINAPI CryptCATAdminEnumCatalogFromHash( IN HCATADMIN hCatAdmin, IN BYTE *pbHash, IN DWORD cbHash, IN DWORD dwFlags, IN HCATINFO *phPrevCatInfo) { CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; BOOL fFindFirstOnly; CRYPT_DATA_BLOB CryptDataBlobHash; CRYPT_DATA_BLOB CryptDataBlobHashTag; LPWSTR pwszSearch = NULL; HANDLE hFindHandle = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindData; LPWSTR pwszHashTag = NULL; DWORD dwErr = 0; LIST_NODE *pPrevListNode = NULL; LIST_NODE *pListNodeToReturn = NULL; LIST_NODE *pListNode = NULL; CATALOG_INFO_CONTEXT *pCatInfoContext = NULL; // // Validate input params // if ((pCatAdmin == NULL) || (pCatAdmin->cbStruct != sizeof(CRYPT_CAT_ADMIN)) || (cbHash == 0) || (cbHash > MAX_HASH_LEN) || (dwFlags != 0)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } if (!_CatAdminRegisterForChangeNotification(pCatAdmin)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // If phPrevCatInfo is NULL then that means the caller is only interested // in the first catalog that contains the hash, thus no enum state is // started. If phPrevCatInfo is non NULL, then it contains NULL, or a // HCATINFO that was returned from a previous call to // CryptCATAdminEnumCatalogFromHash. If it contains NULL, then this is // the start of an enum, otherwise it is enuming the next catalog containing // the hash. // if (phPrevCatInfo == NULL) { fFindFirstOnly = TRUE; } else { fFindFirstOnly = FALSE; pPrevListNode = (LIST_NODE *) *phPrevCatInfo; } // // Only allow one thread to view/modify at a time // EnterCriticalSection(&(pCatAdmin->CriticalSection)); pCatAdmin->fCSEntered = TRUE; __try { // // This data blob is used to do the find in the database // CryptDataBlobHash.pbData = pbHash; CryptDataBlobHash.cbData = cbHash; // // Create the tag to be used for calls to CertFindSubjectInSortedCTL // if (!_CatAdminCreateHashTag(pbHash, cbHash, &pwszHashTag, &CryptDataBlobHashTag)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // The enum works as follows: // // if enum-state is not being initialized OR this is the first call to start an enum // // loop through all currently cached catalogs until a catalog containing the // the hash is found, and return it // // if a catalog was not found in the cache, then call the DB process to try and // find one // // else (enum state has already been started) // // loop through currently cached catalogs, starting with the catalog just after // the current catalog, and until a catalog containing the hash is found // if ((fFindFirstOnly) || (pPrevListNode == NULL)) { pListNode = LIST_GetFirst(&(pCatAdmin->CatalogInfoContextList)); while (pListNode != NULL) { pCatInfoContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); if (CertFindSubjectInSortedCTL( &CryptDataBlobHashTag, pCatInfoContext->pCTLContext, NULL, NULL, NULL)) { pListNodeToReturn = pListNode; goto CommonReturn; } pListNode = LIST_GetNext(pListNode); } // // If we are here, that means we did not find a cached catalog that contained // the hash, so call the DB process to try and find one or more. // // Call the DB process once if we are not using the default sub-system ID, // otherwise call the DB process once for each sub-system. if (!pCatAdmin->fUseDefSubSysId) { if (_CatAdminAddCatalogsToCache( pCatAdmin, pCatAdmin->pwszSubSysGUID, &CryptDataBlobHash, &pListNodeToReturn)) { if (pListNodeToReturn == NULL) { SetLastError(ERROR_NOT_FOUND); //CATADMIN_LOGERR_LASTERR() goto CatNotFound; } goto CommonReturn; } else { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } } else { // // For each subdir, add all the catalogs that contain the hash // // // Create search string to find all subdirs // if (NULL == (pwszSearch = _CatAdminCreatePath( gpwszDatabaseFileBaseDirectory, WSZ_CATALOG_SUBSYTEM_SEARCH_STRING, FALSE))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Do the initial find // hFindHandle = FindFirstFileU(pwszSearch, &FindData); if (hFindHandle == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); // // no sub dirs found // if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_FILE_NOT_FOUND)) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_FOUND, CatNotFound) } else { goto ErrorFindFirstFile; } } while (1) { // // Only care about directories // if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // Add all the catalogs in this subdir that contain the hash to // the catalog cache // if (!_CatAdminAddCatalogsToCache( pCatAdmin, FindData.cFileName, &CryptDataBlobHash, (pListNodeToReturn == NULL) ? &pListNodeToReturn : NULL)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } } // // Get next subdir // if (!FindNextFileU(hFindHandle, &FindData)) { if (GetLastError() == ERROR_NO_MORE_FILES) { break; } else { goto ErrorFindNextFile; } } } if (pListNodeToReturn == NULL) { SetLastError(ERROR_NOT_FOUND); //CATADMIN_LOGERR_LASTERR() goto CatNotFound; } } } else { // // Enum state already started, so just search through the rest of the cached // catalogs to try and find one that contains the hash // pListNode = LIST_GetNext(pPrevListNode); while (pListNode != NULL) { pCatInfoContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); if (CertFindSubjectInSortedCTL( &CryptDataBlobHashTag, pCatInfoContext->pCTLContext, NULL, NULL, NULL)) { pListNodeToReturn = pListNode; goto CommonReturn; } pListNode = LIST_GetNext(pListNode); } // // If we get here that means no catalog was found // SetLastError(ERROR_NOT_FOUND); } } __except(EXCEPTION_EXECUTE_HANDLER) { CATADMIN_SETERR_LOG_RETURN(GetExceptionCode(), ErrorException) } CommonReturn: dwErr = GetLastError(); if (pwszHashTag != NULL) { free(pwszHashTag); } if (pwszSearch != NULL) { free(pwszSearch); } if (hFindHandle != INVALID_HANDLE_VALUE) { FindClose(hFindHandle); } if (pListNodeToReturn != NULL) { pCatAdmin->nOpenCatInfoContexts++; } if (pPrevListNode != NULL) { *phPrevCatInfo = NULL; // // Decrement, since this is the equivalent of // calling CryptCATAdminReleaseCatalogContext // pCatAdmin->nOpenCatInfoContexts--; } if ((pCatAdmin != NULL) && (pCatAdmin->fCSEntered)) { pCatAdmin->fCSEntered = FALSE; LeaveCriticalSection(&(pCatAdmin->CriticalSection)); } SetLastError(dwErr); return((HCATINFO) pListNodeToReturn); ErrorReturn: goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, CatNotFound) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorFindFirstFile) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorFindNextFile) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorException) } //--------------------------------------------------------------------------------------- // // CryptCATCatalogInfoFromContext // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATCatalogInfoFromContext( IN HCATINFO hCatInfo, IN OUT CATALOG_INFO *psCatInfo, IN DWORD dwFlags) { BOOL fRet = TRUE; LIST_NODE *pListNode = (LIST_NODE *) hCatInfo; CATALOG_INFO_CONTEXT *pContext = NULL; if ((pListNode == NULL) || (psCatInfo == NULL)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } pContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); if (pContext->pwszCatalogFile != NULL) { if ((wcslen(pContext->pwszCatalogFile) + 1) > MAX_PATH) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorTooLong) } wcscpy(psCatInfo->wszCatalogFile, pContext->pwszCatalogFile); } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorTooLong) } //--------------------------------------------------------------------------------------- // // CryptCATAdminReleaseCatalogContext // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminReleaseCatalogContext( IN HCATADMIN hCatAdmin, IN HCATINFO hCatInfo, IN DWORD dwFlags) { BOOL fRet = TRUE; CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; LIST_NODE *pListNode = (LIST_NODE *) hCatInfo; CATALOG_INFO_CONTEXT *pCatInfoContext = NULL; if ((pCatAdmin == NULL) || (pCatAdmin->cbStruct != sizeof(CRYPT_CAT_ADMIN)) || (pListNode == NULL)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } // // check to see if this is from and add operation, if so, then clean // up allocated memory, otherwise, just decrement ref count // pCatInfoContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); if (pCatInfoContext->fResultOfAdd) { free(pCatInfoContext->pwszCatalogFile); free(pCatInfoContext); free(pListNode); } else { // FIX FIX - may need to be smarter about this... like verify // the node is actually in the list. pCatAdmin->nOpenCatInfoContexts--; } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam); } //--------------------------------------------------------------------------------------- // // CryptCATAdminResolveCatalogPath // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminResolveCatalogPath( IN HCATADMIN hCatAdmin, IN WCHAR *pwszCatalogFile, IN OUT CATALOG_INFO *psCatInfo, IN DWORD dwFlags) { BOOL fRet = TRUE; CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *)hCatAdmin; if ((pCatAdmin == NULL) || (pCatAdmin->cbStruct != sizeof(CRYPT_CAT_ADMIN)) || (pwszCatalogFile == NULL) || (psCatInfo == NULL) || (psCatInfo->cbStruct != sizeof(CATALOG_INFO)) || (dwFlags != 0)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, ErrorInvalidParam) } if ((wcslen(pCatAdmin->pwszCatalogFileDir) + wcslen(pwszCatalogFile) + 1) > MAX_PATH) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorTooLong) } wcscpy(psCatInfo->wszCatalogFile, pCatAdmin->pwszCatalogFileDir); wcscat(psCatInfo->wszCatalogFile, pwszCatalogFile); CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorInvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorTooLong) } //--------------------------------------------------------------------------------------- // // CryptCATAdminPauseServiceForBackup // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminPauseServiceForBackup( IN DWORD dwFlags, IN BOOL fResume) { BOOL fRet = TRUE; DWORD dwErr = 0; // // Call the DB process to delete the catalog // if (0 != (dwErr = Client_SSCatDBPauseResumeService( 0, fResume))) { CATADMIN_SETERR_LOG_RETURN(dwErr, ErrorCatDBProcess) } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorCatDBProcess) } //--------------------------------------------------------------------------------------- // // CryptCATAdminCalcHashFromFileHandle // //--------------------------------------------------------------------------------------- BOOL WINAPI CryptCATAdminCalcHashFromFileHandle( IN HANDLE hFile, IN OUT DWORD *pcbHash, IN BYTE *pbHash, IN DWORD dwFlags) { BYTE *pbRet = NULL; SIP_INDIRECT_DATA *pbIndirectData = NULL; BOOL fRet; GUID gSubject; SIP_DISPATCH_INFO sSip; if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE) || (pcbHash == NULL) || (dwFlags != 0)) { CATADMIN_SETERR_LOG_RETURN(ERROR_INVALID_PARAMETER, InvalidParam) } if (!CryptSIPRetrieveSubjectGuidForCatalogFile(L"CATADMIN", hFile, &gSubject)) { goto ErrorMemory; } memset(&sSip, 0x00, sizeof(SIP_DISPATCH_INFO)); sSip.cbSize = sizeof(SIP_DISPATCH_INFO); if (!CryptSIPLoad(&gSubject, 0, &sSip)) { CATADMIN_LOGERR_LASTERR() goto SIPLoadError; } SIP_SUBJECTINFO sSubjInfo; DWORD cbIndirectData; memset(&sSubjInfo, 0x00, sizeof(SIP_SUBJECTINFO)); sSubjInfo.cbSize = sizeof(SIP_SUBJECTINFO); sSubjInfo.DigestAlgorithm.pszObjId = (char *)CertAlgIdToOID(CALG_SHA1); sSubjInfo.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | MSSIP_FLAGS_PROHIBIT_RESIZE_ON_CREATE; sSubjInfo.pgSubjectType = &gSubject; sSubjInfo.hFile = hFile; sSubjInfo.pwsFileName = L"CATADMIN"; sSubjInfo.dwEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; cbIndirectData = 0; sSip.pfCreate(&sSubjInfo, &cbIndirectData, NULL); if (cbIndirectData == 0) { SetLastError(E_NOTIMPL); //CATADMIN_LOGERR_LASTERR() goto SIPError; } if (NULL == (pbIndirectData = (SIP_INDIRECT_DATA *) malloc(cbIndirectData))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } if (!(sSip.pfCreate(&sSubjInfo, &cbIndirectData, pbIndirectData))) { if (GetLastError() == 0) { SetLastError(ERROR_INVALID_DATA); } CATADMIN_LOGERR_LASTERR() goto SIPError; } if ((pbIndirectData->Digest.cbData == 0) || (pbIndirectData->Digest.cbData > MAX_HASH_LEN)) { SetLastError( ERROR_INVALID_DATA ); goto SIPError; } if (NULL == (pbRet = (BYTE *) malloc(pbIndirectData->Digest.cbData))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memcpy(pbRet, pbIndirectData->Digest.pbData, pbIndirectData->Digest.cbData); fRet = TRUE; CommonReturn: if (pbRet) { if (*pcbHash < pbIndirectData->Digest.cbData) { SetLastError(ERROR_INSUFFICIENT_BUFFER); fRet = FALSE; } else if (pbHash) { memcpy(pbHash, pbRet, pbIndirectData->Digest.cbData); } *pcbHash = pbIndirectData->Digest.cbData; free(pbRet); } if (pbIndirectData) { free(pbIndirectData); } if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (pbHash == NULL)) { fRet = TRUE; } return(fRet); ErrorReturn: free(pbRet); fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, SIPLoadError) TRACE_ERROR_EX(DBG_SS_TRUST, SIPError) TRACE_ERROR_EX(DBG_SS_TRUST, InvalidParam) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorMemory) } //--------------------------------------------------------------------------------------- // // I_CryptCatAdminMigrateToNewCatDB // //--------------------------------------------------------------------------------------- BOOL WINAPI I_CryptCatAdminMigrateToNewCatDB() { BOOL fRet = TRUE; LPWSTR pwszSearchCatDirs = NULL; LPWSTR pwszDeleteFile = NULL; LPWSTR pwsz = NULL; LPWSTR pwszMigrateFromDir = NULL; HCATADMIN hCatAdmin = NULL; GUID gDefault = DEF_CAT_SUBSYS_ID; HANDLE hFindHandleCatDirs = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW FindDataCatDirs; DWORD dwErr = 0; HKEY hKey; DWORD dwDisposition; int i; BOOL fInSync; WCHAR wszGUID[256]; LPWSTR pwszCatalogFileDir = NULL; LPWSTR pwszDatabaseFileDir = NULL; // // FIRST!! // // Clean up the old reg based catroot entry, and if needed, move // the old style catalog database from its old directory to the new directory, // then do the migrate from there // if (RegCreateKeyExU( HKEY_LOCAL_MACHINE, REG_MACHINE_SETTINGS_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS) { DWORD dwType; DWORD cbSize; cbSize = 0; RegQueryValueExU( hKey, WSZ_CATALOG_FILE_BASE_DIRECTORY, NULL, &dwType, NULL, &cbSize); if (cbSize > 0) { if (NULL == (pwszMigrateFromDir = (LPWSTR) malloc(sizeof(WCHAR) * ((cbSize / sizeof(WCHAR)) + 3)))) { RegCloseKey(hKey); CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } pwszMigrateFromDir[0] = NULL; RegQueryValueExU( hKey, WSZ_CATALOG_FILE_BASE_DIRECTORY, NULL, &dwType, (BYTE *)pwszMigrateFromDir, &cbSize); if (!_CatAdminMigrateCatalogDatabase( pwszMigrateFromDir, gpwszCatalogFileBaseDirectory)) { RegCloseKey(hKey); CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } RegDeleteValueU(hKey, WSZ_CATALOG_FILE_BASE_DIRECTORY); } RegCloseKey(hKey); } // // NOW, that we are in a consistent state // // For each catalog sub-system, enumerate all catalogs and add them to the // new catalog database under the same sub-system GUID. // // // Create search string to find all catalog sub dirs // if (NULL == (pwszSearchCatDirs = _CatAdminCreatePath( gpwszCatalogFileBaseDirectory, WSZ_CATALOG_SUBSYTEM_SEARCH_STRING, FALSE))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Do the initial find // hFindHandleCatDirs = FindFirstFileU(pwszSearchCatDirs, &FindDataCatDirs); if (hFindHandleCatDirs == INVALID_HANDLE_VALUE) { // // See if a real error occurred, or just no files // dwErr = GetLastError(); if ((dwErr == ERROR_NO_MORE_FILES) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_FILE_NOT_FOUND)) { // // There is nothing to do // SetLastError(0); goto RegKeyAdd; } else { CATADMIN_LOGERR_LASTERR() goto ErrorFindFirstFile; } } while (1) { // // Only care about directories // if (FindDataCatDirs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { _CatAdminMigrateSingleDatabase(FindDataCatDirs.cFileName); } // // Get rid of old files // dwErr = GetLastError(); if (NULL != (pwsz = _CatAdminCreatePath( gpwszCatalogFileBaseDirectory, FindDataCatDirs.cFileName, FALSE))) { for (i=0; ifRegisteredForChangeNotification) { goto CommonReturn; } // // NOTE: // Currently the service ignores the pwszSubSysGUID when registering a change // notification because it DOES NOT do notifications on a per pwszSubSysDir basis... // it really should at some point. // When it does start to do notifications on per pwszSubSysGUID this will need to // change. CryptCatAdminAcquireContext can be called with a NULL subSysGUID, // in which case all SubSysDirs are used, so we would need to register a // change notification for all of them. // // // Register the event with the DB process, so the DB process can SetEvent() it // when a changed occurs // if (0 != (dwErr = Client_SSCatDBRegisterForChangeNotification( (DWORD_PTR) pCatAdmin->hClearCacheEvent, 0, pCatAdmin->pwszSubSysGUID, FALSE))) { CATADMIN_SETERR_LOG_RETURN(dwErr, ErrorCatDBProcess) } pCatAdmin->fRegisteredForChangeNotification = TRUE; CommonReturn: return fRet; ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorCatDBProcess) } //--------------------------------------------------------------------------------------- // // _CatAdminFreeCachedCatalogs // //--------------------------------------------------------------------------------------- BOOL _CatAdminFreeCachedCatalogs( CRYPT_CAT_ADMIN *pCatAdmin) { BOOL fRet = TRUE; LIST_NODE *pListNode = NULL; CATALOG_INFO_CONTEXT *pCatInfoContext = NULL; // // NOTE: the caller of this function must have entered the Critical Section for // the CatAdminContext // // // Enumerate through all the cached CATALOG_INFO_CONTEXTs and free all the // resources for each // pListNode = LIST_GetFirst(&(pCatAdmin->CatalogInfoContextList)); while (pListNode != NULL) { pCatInfoContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); free(pCatInfoContext->pwszCatalogFile); CertFreeCTLContext(pCatInfoContext->pCTLContext); UnmapViewOfFile(pCatInfoContext->pbMappedFile); CloseHandle(pCatInfoContext->hMappedFile); free(pCatInfoContext); pListNode = LIST_GetNext(pListNode); } LIST_RemoveAll(&(pCatAdmin->CatalogInfoContextList)); return(fRet); } //--------------------------------------------------------------------------------------- // // _CatAdminWaitOrTimerCallback // //--------------------------------------------------------------------------------------- VOID CALLBACK _CatAdminWaitOrTimerCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired) { CRYPT_CAT_ADMIN *pCatAdmin = (CRYPT_CAT_ADMIN *) lpParameter; // // Enter the CS before wacking anything // EnterCriticalSection(&(pCatAdmin->CriticalSection)); pCatAdmin->fCSEntered = TRUE; // // If there is an open ref count, then we can't clean up // if (pCatAdmin->nOpenCatInfoContexts != 0) { pCatAdmin->fCSEntered = FALSE; LeaveCriticalSection(&(pCatAdmin->CriticalSection)); return; } // // Cleanup all the cached CATALOG_INFO_CONTEXTs // _CatAdminFreeCachedCatalogs(pCatAdmin); pCatAdmin->fCSEntered = FALSE; LeaveCriticalSection(&(pCatAdmin->CriticalSection)); } //--------------------------------------------------------------------------------------- // // _CatAdminAddCatalogsToCache // //--------------------------------------------------------------------------------------- BOOL _CatAdminAddCatalogsToCache( CRYPT_CAT_ADMIN *pCatAdmin, LPWSTR pwszSubSysGUID, CRYPT_DATA_BLOB *pCryptDataBlob, LIST_NODE **ppFirstListNodeAdded) { BOOL fRet = TRUE; LPWSTR pwszCopy = NULL; DWORD i; DWORD dwNumCatalogNames = 0; LPWSTR *ppwszCatalogNames = NULL; DWORD dwErr = 0; LIST_NODE *pListNode = NULL; LPWSTR pwszSubSysDir = NULL; if (ppFirstListNodeAdded != NULL) { *ppFirstListNodeAdded = NULL; } if (NULL == (pwszSubSysDir = _CatAdminCreatePath( gpwszCatalogFileBaseDirectory, pwszSubSysGUID, FALSE))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } // // Call DB process and get list of catalogs into ppwszCatalogNames // // NOTE: the order in which the service adds CatNames to the list results in // only the first CatName of the list being guaranteed to contain the // hash... all other CatNames may or may not contain the hash. Which // is OK because this code only assumes the first CatName contains the // hash, and then searches all other CatNames for the hash before returning them. // if (0 != (dwErr = Client_SSCatDBEnumCatalogs( 0, pwszSubSysGUID, pCryptDataBlob->pbData, pCryptDataBlob->cbData, &dwNumCatalogNames, &ppwszCatalogNames))) { CATADMIN_SETERR_LOG_RETURN(dwErr, ErrorServiceError) } // // Loop for each catalog and create the CTL context // for (i=0; iCatalogInfoContextList)); while (pListNode != NULL) { pCatInfoContext = (CATALOG_INFO_CONTEXT *) LIST_GetElement(pListNode); if (_wcsicmp(pCatInfoContext->pwszCatalogFile, pwszCatalog) == 0) { *ppListNodeAdded = pListNode; goto CommonReturn; } pListNode = LIST_GetNext(pListNode); } // // Allocate space for a new cached catalog context // if (NULL == (pCatInfoContextAdd = (CATALOG_INFO_CONTEXT *) malloc(sizeof(CATALOG_INFO_CONTEXT)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memset(pCatInfoContextAdd, 0, sizeof(CATALOG_INFO_CONTEXT)); pCatInfoContextAdd->fResultOfAdd = FALSE; // // Open, create a file mapping, and create the CTL context for // the catalog file // if (!CatUtil_CreateCTLContextFromFileName( pwszCatalog, &pCatInfoContextAdd->hMappedFile, &pCatInfoContextAdd->pbMappedFile, &pCatInfoContextAdd->pCTLContext, TRUE)) { CATADMIN_LOGERR_LASTERR() ErrLog_LogString(NULL, L"The following file was not found - ", pwszCatalog, TRUE); goto ErrorReturn; } pCatInfoContextAdd->pwszCatalogFile = pwszCatalog; // // Add to the list of cached catalog contexts // if (NULL == (pListNode = LIST_AddTail( &(pCatAdmin->CatalogInfoContextList), pCatInfoContextAdd))) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } *ppListNodeAdded = pListNode; CommonReturn: return(fRet); ErrorReturn: dwErr = GetLastError(); if (pCatInfoContextAdd != NULL) { if (pCatInfoContextAdd->pCTLContext != NULL) { CertFreeCTLContext(pCatInfoContextAdd->pCTLContext); } if (pCatInfoContextAdd->pbMappedFile != NULL) { UnmapViewOfFile(pCatInfoContextAdd->pbMappedFile); } if (pCatInfoContextAdd->hMappedFile != NULL) { CloseHandle(pCatInfoContextAdd->hMappedFile); } free(pCatInfoContextAdd); } SetLastError(dwErr); fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, ErrorMemory) } //--------------------------------------------------------------------------------------- // // _CatAdminMigrateCatalogDatabase // // This migration code deals with very old catalog databases. In the olden days, the // catroot dir location could be specified by a particular registry key... that is no // longer true. So, if an old system is being upgraded that has the registry key, this // code moves all the catalog files from the location specified by the registry key to // the %SystemDefaultDir%\Catroot dir. Then it shwacks the registry key. // //--------------------------------------------------------------------------------------- BOOL _CatAdminMigrateCatalogDatabase( LPWSTR pwszFrom, LPWSTR pwszTo) { DWORD dwAttr = 0; WCHAR wszFrom[MAX_PATH]; WCHAR wszTo[MAX_PATH]; // // If they are the same dir then just get out // if (((wcslen(pwszFrom) + 2) > MAX_PATH) || ((wcslen(pwszTo) + 2) > MAX_PATH)) { return TRUE; } wcscpy(wszFrom, pwszFrom); wcscpy(wszTo, pwszTo); if (wszFrom[wcslen(wszFrom) - 1] != L'\\') { wcscat(wszFrom, L"\\"); } if (wszTo[wcslen(wszTo) - 1] != L'\\') { wcscat(wszTo, L"\\"); } if (_wcsicmp(wszFrom, wszTo) == 0) { return TRUE; } // // if the pwszTo dir already exists, then don't do a thing. // dwAttr = GetFileAttributesU(pwszTo); if (INVALID_FILE_ATTRIBUTES != dwAttr) { if (FILE_ATTRIBUTE_DIRECTORY & dwAttr) { // // dir already exists... // return TRUE; } else { // // something exists with pwszTo name, but it isn't a dir // CATADMIN_LOGERR_LASTERR() return FALSE; } } // // if the pwszFrom dir does not exist, then don't do a thing. // dwAttr = GetFileAttributesU(pwszFrom); if ((0xFFFFFFFF == dwAttr) || (!(FILE_ATTRIBUTE_DIRECTORY & dwAttr))) { return TRUE; } if (!_CatAdminRecursiveCreateDirectory(pwszTo, NULL)) { CATADMIN_LOGERR_LASTERR() return FALSE; } if (!I_RecursiveCopyDirectory(pwszFrom, pwszTo)) { CATADMIN_LOGERR_LASTERR() return FALSE; } // // Don't check for error on delete since this operation is NOT mandatory // I_RecursiveDeleteDirectory(pwszFrom); return TRUE; } //--------------------------------------------------------------------------------------- // // _CatAdminBToHex // //--------------------------------------------------------------------------------------- WCHAR rgHexDigit[] = { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' }; void _CatAdminBToHex ( LPBYTE pbDigest, DWORD iByte, LPWSTR pwszHashTag) { DWORD iTag; DWORD iHexDigit1; DWORD iHexDigit2; iTag = iByte * 2; iHexDigit1 = (pbDigest[iByte] & 0xF0) >> 4; iHexDigit2 = (pbDigest[iByte] & 0x0F); pwszHashTag[iTag] = rgHexDigit[iHexDigit1]; pwszHashTag[iTag + 1] = rgHexDigit[iHexDigit2]; } //--------------------------------------------------------------------------------------- // // _CatAdminCreateHashTag // //--------------------------------------------------------------------------------------- BOOL _CatAdminCreateHashTag( BYTE *pbHash, DWORD cbHash, LPWSTR *ppwszHashTag, CRYPT_DATA_BLOB *pCryptDataBlob) { DWORD cwTag; DWORD cCount; cwTag = ((cbHash * 2) + 1); if (NULL == (*ppwszHashTag = (LPWSTR) malloc(cwTag * sizeof(WCHAR)))) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); CATADMIN_LOGERR_LASTERR() return(FALSE); } for (cCount = 0; cCount < cbHash; cCount++) { _CatAdminBToHex(pbHash, cCount, *ppwszHashTag); } (*ppwszHashTag)[cwTag - 1] = L'\0'; pCryptDataBlob->pbData = (BYTE *) *ppwszHashTag; pCryptDataBlob->cbData = cwTag * sizeof(WCHAR); return (TRUE); } //--------------------------------------------------------------------------------------- // // _CatAdminRecursiveCreateDirectory // //--------------------------------------------------------------------------------------- BOOL _CatAdminRecursiveCreateDirectory( IN LPCWSTR pwszDir, LPSECURITY_ATTRIBUTES lpSecurityAttributes ) { BOOL fResult; DWORD dwAttr; DWORD dwErr; LPCWSTR pwsz; DWORD cch; WCHAR wch; LPWSTR pwszParent = NULL; // // if last char is a '\', then just strip it and recurse // if (pwszDir[wcslen(pwszDir) - 1] == L'\\') { cch = wcslen(pwszDir); if (NULL == (pwszParent = (LPWSTR) malloc(cch * sizeof(WCHAR)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memcpy(pwszParent, pwszDir, (cch - 1) * sizeof(WCHAR)); pwszParent[cch - 1] = L'\0'; fResult = _CatAdminRecursiveCreateDirectory( pwszParent, lpSecurityAttributes); goto CommonReturn; } // // See if dir already exists // dwAttr = GetFileAttributesU(pwszDir); if (0xFFFFFFFF != dwAttr) { if (FILE_ATTRIBUTE_DIRECTORY & dwAttr) { return TRUE; } CATADMIN_LOGERR_LASTERR() goto InvalidDirectoryAttr; } // // If it was an error other than file/path not found, error out // dwErr = GetLastError(); if (!(ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)) { CATADMIN_LOGERR_LASTERR() goto GetFileAttrError; } // // Try creating the new dir // if (CreateDirectoryU( pwszDir, lpSecurityAttributes)) { SetFileAttributesU(pwszDir, FILE_ATTRIBUTE_NORMAL); return TRUE; } dwErr = GetLastError(); if (!(ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)) { CATADMIN_LOGERR_LASTERR() goto CreateDirectoryError; } // // Peal off the last path name component // cch = wcslen(pwszDir); pwsz = pwszDir + cch; while (L'\\' != *pwsz) { if (pwsz == pwszDir) { // Path didn't have a \. CATADMIN_SETERR_LOG_RETURN(ERROR_BAD_PATHNAME, BadDirectoryPath) } pwsz--; } cch = (DWORD)(pwsz - pwszDir); if (0 == cch) { // Detected leading \Path CATADMIN_SETERR_LOG_RETURN(ERROR_BAD_PATHNAME, BadDirectoryPath) } // Check for leading \\ or x:\. wch = *(pwsz - 1); if ((1 == cch && L'\\' == wch) || (2 == cch && L':' == wch)) { CATADMIN_SETERR_LOG_RETURN(ERROR_BAD_PATHNAME, BadDirectoryPath) } if (NULL == (pwszParent = (LPWSTR) malloc((cch + 1) * sizeof(WCHAR)))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } memcpy(pwszParent, pwszDir, cch * sizeof(WCHAR)); pwszParent[cch] = L'\0'; if (!_CatAdminRecursiveCreateDirectory(pwszParent, lpSecurityAttributes)) { CATADMIN_LOGERR_LASTERR() goto ErrorReturn; } if (!CreateDirectoryU( pwszDir, lpSecurityAttributes)) { CATADMIN_LOGERR_LASTERR() goto CreateDirectory2Error; } SetFileAttributesU(pwszDir, FILE_ATTRIBUTE_NORMAL); fResult = TRUE; CommonReturn: if (pwszParent != NULL) { free(pwszParent); } return fResult; ErrorReturn: fResult = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS_TRUST, InvalidDirectoryAttr) TRACE_ERROR_EX(DBG_SS_TRUST, GetFileAttrError) TRACE_ERROR_EX(DBG_SS_TRUST, CreateDirectoryError) TRACE_ERROR_EX(DBG_SS_TRUST, BadDirectoryPath) TRACE_ERROR_EX(DBG_SS_TRUST, ErrorMemory) TRACE_ERROR_EX(DBG_SS_TRUST, CreateDirectory2Error) } //--------------------------------------------------------------------------------------- // // _CatAdminCreatePath // //--------------------------------------------------------------------------------------- LPWSTR _CatAdminCreatePath( IN LPCWSTR pwsz1, IN LPCWSTR pwsz2, IN BOOL fAddEndingSlash ) { LPWSTR pwszTemp = NULL; int nTotalLen = 0; int nLenStr1 = 0; // // Calculate the length of the resultant string as the sum of the length // of pwsz1, length of pwsz2, a NULL char, and a possible extra '\' char // nLenStr1 = wcslen(pwsz1); nTotalLen = nLenStr1 + wcslen(pwsz2) + 2; if (fAddEndingSlash) { nTotalLen++; } // // Allocate the string and copy pwsz1 into the buffer // if (NULL == (pwszTemp = (LPWSTR) malloc(sizeof(WCHAR) * nTotalLen))) { CATADMIN_SETERR_LOG_RETURN(ERROR_NOT_ENOUGH_MEMORY, ErrorMemory) } wcscpy(pwszTemp, pwsz1); // // Add the extra '\' if needed // if (pwsz1[nLenStr1 - 1] != L'\\') { wcscat(pwszTemp, L"\\"); } // // Tack on pwsz2 // wcscat(pwszTemp, pwsz2); if (fAddEndingSlash) { wcscat(pwszTemp, L"\\"); } CommonReturn: return (pwszTemp); ErrorReturn: goto CommonReturn; TRACE_ERROR_EX(DBG_SS_CATDBSVC, ErrorMemory) } // // Kept so that old dlls linking to this function in wintrust.dll // don't get an unresolved external. // EXTERN_C BOOL WINAPI CatalogCompactHashDatabase ( IN LPCWSTR pwszDbLock, IN LPCWSTR pwszDbDirectory, IN LPCWSTR pwszDbName, IN OPTIONAL LPCWSTR pwszUnwantedCatalog ) { return (TRUE); }