|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 2000
//
// File: extract.cpp
//
// Contents: Chain Cabinet Extraction
//
// Functions: ExtractAuthRootAutoUpdateCtlFromCab
//
// History: 11-Nov-00 philh Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
#include <setupapi.h>
#include <dbgdef.h>
#include <userenv.h>
#define CHAIN_CHAR_LEN(sz) (sizeof(sz) / sizeof(sz[0]))
//+===========================================================================
// Extract helper functions
//============================================================================
//+-------------------------------------------------------------------------
// Allocate and read a blob from a file.
//
// The allocated bytes must be freed by calling PkiFree().
//--------------------------------------------------------------------------
BOOL WINAPI ReadBlobFromFileA( IN LPCSTR pszFileName, OUT BYTE **ppb, OUT DWORD *pcb ) { BOOL fResult; HANDLE hFile; BYTE *pb = NULL; DWORD cb = 0; DWORD cbRead = 0;
hFile = CreateFileA( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // lpsa
OPEN_EXISTING, 0, // fdwAttrsAndFlags
NULL // TemplateFile
); if (INVALID_HANDLE_VALUE == hFile) goto CreateFileError;
cb = GetFileSize(hFile, NULL); if (0 == cb) goto EmptyFile;
if (NULL == (pb = (BYTE *) PkiNonzeroAlloc(cb))) goto OutOfMemory;
if (!ReadFile(hFile, pb, cb, &cbRead, NULL)) goto ReadFileError; if (cbRead != cb) goto InvalidFileLengthError;
fResult = TRUE; CommonReturn: if (INVALID_HANDLE_VALUE != hFile) { DWORD dwLastErr = GetLastError(); CloseHandle(hFile); SetLastError(dwLastErr); }
*ppb = pb; *pcb = cb;
return fResult;
ErrorReturn: if (pb) { PkiFree(pb); pb = NULL; } cb = 0; fResult = FALSE; goto CommonReturn;
TRACE_ERROR(CreateFileError) SET_ERROR(EmptyFile, ERROR_INVALID_DATA) TRACE_ERROR(OutOfMemory) TRACE_ERROR(ReadFileError) SET_ERROR(InvalidFileLengthError, ERROR_INVALID_DATA) }
//+-------------------------------------------------------------------------
// Write the blob to the specified file
//--------------------------------------------------------------------------
BOOL WINAPI WriteBlobToFileA( IN LPCSTR pszFileName, IN const BYTE *pb, IN DWORD cb ) { BOOL fResult; HANDLE hFile; DWORD cbWritten;
hFile = CreateFileA( pszFileName, GENERIC_WRITE, 0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS, 0, // fdwAttrsAndFlags
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hFile) goto CreateFileError;
if (!WriteFile(hFile, pb, cb, &cbWritten, NULL)) goto WriteFileError;
fResult = TRUE; CommonReturn: if (INVALID_HANDLE_VALUE != hFile) { DWORD dwLastErr = GetLastError(); CloseHandle(hFile); SetLastError(dwLastErr); }
return fResult;
ErrorReturn: fResult = FALSE; goto CommonReturn;
TRACE_ERROR(CreateFileError) TRACE_ERROR(WriteFileError) }
typedef struct _EXTRACT_CAB_FILE_CONTEXT_A { LPCSTR pszFileInCab; LPCSTR pszTempTargetFileName; // MAX_PATH array
BOOL fDidExtract; } EXTRACT_CAB_FILE_CONTEXT_A, *PEXTRACT_CAB_FILE_CONTEXT_A;
//+-------------------------------------------------------------------------
// Callback called by SetupIterateCabinetA to extract the file.
//--------------------------------------------------------------------------
UINT CALLBACK ExtractCabFileCallbackA( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ) { UINT uRet; PEXTRACT_CAB_FILE_CONTEXT_A pCabFileContext = (PEXTRACT_CAB_FILE_CONTEXT_A) Context;
switch (Notification) { case SPFILENOTIFY_FILEINCABINET: { PFILE_IN_CABINET_INFO_A pInfo = (PFILE_IN_CABINET_INFO_A) Param1;
if (0 == _stricmp(pCabFileContext->pszFileInCab, pInfo->NameInCabinet)) { strncpy(pInfo->FullTargetName, pCabFileContext->pszTempTargetFileName, CHAIN_CHAR_LEN(pInfo->FullTargetName)); uRet = FILEOP_DOIT; } else uRet = FILEOP_SKIP; } break;
case SPFILENOTIFY_FILEEXTRACTED: { PFILEPATHS_A pInfo = (PFILEPATHS_A) Param1;
uRet = pInfo->Win32Error;
if (NO_ERROR == uRet && 0 == _stricmp(pCabFileContext->pszTempTargetFileName, pInfo->Target)) pCabFileContext->fDidExtract = TRUE; } break;
default: uRet = NO_ERROR; }
return uRet; }
typedef BOOL (WINAPI *PFN_SETUP_ITERATE_CABINET_A)( IN PCSTR CabinetFile, IN DWORD Reserved, IN PSP_FILE_CALLBACK_A MsgHandler, IN PVOID Context );
//+-------------------------------------------------------------------------
// Load setupapi.dll and call SetupIterateCabinetA to extract and
// expand the specified file in the cab.
//--------------------------------------------------------------------------
BOOL WINAPI ExtractFileFromCabFileA( IN LPCSTR pszFileInCab, IN const CHAR szTempCabFileName[MAX_PATH], IN const CHAR szTempTargetFileName[MAX_PATH] ) { BOOL fResult; HMODULE hDll = NULL; PFN_SETUP_ITERATE_CABINET_A pfnSetupIterateCabinetA; EXTRACT_CAB_FILE_CONTEXT_A CabFileContext;
if (NULL == (hDll = LoadLibraryA("setupapi.dll"))) goto LoadSetupApiDllError;
if (NULL == (pfnSetupIterateCabinetA = (PFN_SETUP_ITERATE_CABINET_A) GetProcAddress( hDll, "SetupIterateCabinetA"))) goto SetupIterateCabinetAProcAddressError;
memset(&CabFileContext, 0, sizeof(CabFileContext)); CabFileContext.pszFileInCab = pszFileInCab; CabFileContext.pszTempTargetFileName = szTempTargetFileName;
if (!pfnSetupIterateCabinetA( szTempCabFileName, 0, // Reserved
ExtractCabFileCallbackA, &CabFileContext )) goto SetupIterateCabinetError;
if (!CabFileContext.fDidExtract) goto NoCabFileExtracted;
fResult = TRUE;
CommonReturn: if (hDll) { DWORD dwLastErr = GetLastError(); FreeLibrary(hDll); SetLastError(dwLastErr); } return fResult; ErrorReturn: fResult = FALSE; goto CommonReturn;
TRACE_ERROR(LoadSetupApiDllError) TRACE_ERROR(SetupIterateCabinetAProcAddressError) TRACE_ERROR(SetupIterateCabinetError) SET_ERROR(NoCabFileExtracted, ERROR_FILE_NOT_FOUND) }
typedef BOOL (WINAPI *PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A)( IN HANDLE hToken, IN LPCSTR lpSrc, OUT LPSTR lpDest, IN DWORD dwSize );
//+-------------------------------------------------------------------------
// Get the thread's temp directory. We may be doing thread impersonation.
//
// Returns 0 if unable to get a thread temp path
//--------------------------------------------------------------------------
DWORD WINAPI I_GetThreadTempPathA( OUT CHAR szTempPath[MAX_PATH] ) { DWORD cch; HANDLE hToken = NULL; HMODULE hDll = NULL; PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A pfnExpandEnvironmentStringsForUserA;
if (!FIsWinNT5()) return 0;
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &hToken )) // We aren't impersonating. Default to the system environment
// variables.
hToken = NULL;
if (NULL == (hDll = LoadLibraryA("userenv.dll"))) goto LoadUserenvDllError;
if (NULL == (pfnExpandEnvironmentStringsForUserA = (PFN_EXPAND_ENVIRONMENT_STRINGS_FOR_USER_A) GetProcAddress(hDll, "ExpandEnvironmentStringsForUserA"))) goto ExpandEnvironmentStringsForUserAProcAddressError;
szTempPath[0] = L'\0'; if (!pfnExpandEnvironmentStringsForUserA( hToken, "%Temp%\\", szTempPath, MAX_PATH - 1 ) || '\0' == szTempPath[0]) goto ExpandTempError;
szTempPath[MAX_PATH - 1] = '\0'; cch = strlen(szTempPath);
CommonReturn: if (hToken) CloseHandle(hToken); if (hDll) FreeLibrary(hDll);
return cch; ErrorReturn: cch = 0; goto CommonReturn;
TRACE_ERROR(LoadUserenvDllError) TRACE_ERROR(ExpandEnvironmentStringsForUserAProcAddressError) TRACE_ERROR(ExpandTempError) }
//+-------------------------------------------------------------------------
// Extract, expand and allocate an in-memory blob for the specified
// file from the in-memory cab.
//
// The allocated bytes must be freed by calling PkiFree().
//--------------------------------------------------------------------------
BOOL WINAPI ExtractBlobFromCabA( IN const BYTE *pbCab, IN DWORD cbCab, IN LPCSTR pszFileInCab, OUT BYTE **ppb, OUT DWORD *pcb ) { BOOL fResult; DWORD dwLastErr = 0; BYTE *pb = NULL; DWORD cb;
CHAR szTempPath[MAX_PATH]; CHAR szTempCabFileName[MAX_PATH]; szTempCabFileName[0] = '\0'; CHAR szTempTargetFileName[MAX_PATH]; szTempTargetFileName[0] = '\0'; DWORD cch;
// Get temp filenames for the cabinet and extracted target
cch = GetTempPathA(CHAIN_CHAR_LEN(szTempPath), szTempPath); if (0 == cch || (CHAIN_CHAR_LEN(szTempPath) - 1) < cch) goto GetTempPathError;
if (0 == GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName)) { dwLastErr = GetLastError();
// If we are doing thread impersonation, we may not have access to the
// process's temp directory. Try to get the impersonated thread's
// temp directory.
cch = I_GetThreadTempPathA(szTempPath); if (0 != cch) cch = GetTempFileNameA(szTempPath, "Cab", 0, szTempCabFileName);
if (0 == cch) { SetLastError(dwLastErr); szTempCabFileName[0] = '\0'; goto GetTempCabFileNameError; } }
szTempCabFileName[CHAIN_CHAR_LEN(szTempCabFileName) - 1] = '\0';
if (0 == GetTempFileNameA(szTempPath, "Tar", 0, szTempTargetFileName)) { szTempTargetFileName[0] = '\0'; goto GetTempTargetFileNameError; } szTempTargetFileName[CHAIN_CHAR_LEN(szTempTargetFileName) - 1] = '\0';
// Write the cab bytes to the temporary cab file
if (!WriteBlobToFileA(szTempCabFileName, pbCab, cbCab)) goto WriteCabFileError;
// Extract the specified file from the temporary cab file
if (!ExtractFileFromCabFileA( pszFileInCab, szTempCabFileName, szTempTargetFileName)) goto ExtractFileFromCabFileError;
// Read and allocate the bytes from the temporary target file
if (!ReadBlobFromFileA(szTempTargetFileName, &pb, &cb)) goto ReadTargetFileError;
fResult = TRUE;
CommonReturn: // Delete the temp files
if ('\0' != szTempCabFileName) DeleteFileA(szTempCabFileName); if ('\0' != szTempTargetFileName) DeleteFileA(szTempTargetFileName);
*ppb = pb; *pcb = cb;
SetLastError(dwLastErr); return fResult;
ErrorReturn: dwLastErr = GetLastError(); if (pb) { PkiFree(pb); pb = NULL; } cb = 0; fResult = FALSE; goto CommonReturn;
TRACE_ERROR(GetTempPathError) TRACE_ERROR(GetTempCabFileNameError) TRACE_ERROR(GetTempTargetFileNameError) TRACE_ERROR(WriteCabFileError) TRACE_ERROR(ExtractFileFromCabFileError) TRACE_ERROR(ReadTargetFileError) }
//+---------------------------------------------------------------------------
//
// Function: ExtractAuthRootAutoUpdateCtlFromCab
//
// Synopsis: Extract the authroot.stl file from the cabinet blob
// and create the AuthRoot Auto Update CTL.
//
// Assumption: Chain engine isn't locked in the calling thread.
//
//----------------------------------------------------------------------------
PCCTL_CONTEXT WINAPI ExtractAuthRootAutoUpdateCtlFromCab ( IN PCRYPT_BLOB_ARRAY pcbaCab ) { PCRYPT_DATA_BLOB pCabBlob; PCCTL_CONTEXT pCtl = NULL; BYTE *pbEncodedCtl = NULL; DWORD cbEncodedCtl; CERT_CREATE_CONTEXT_PARA CreateContextPara;
// Get the cab blob
pCabBlob = pcbaCab->rgBlob; if (0 == pcbaCab->cBlob || 0 == pCabBlob->cbData) goto InvalidCabBlob;
// Extract, expand and create an in-memory blob for the stl file in the
// in-memory cab
if (!ExtractBlobFromCabA( pCabBlob->pbData, pCabBlob->cbData, CERT_AUTH_ROOT_CTL_FILENAME_A, &pbEncodedCtl, &cbEncodedCtl )) goto ExtractStlFromCabError;
// Create the Ctl from the extracted bytes
memset(&CreateContextPara, 0, sizeof(CreateContextPara)); CreateContextPara.cbSize = sizeof(CreateContextPara); CreateContextPara.pfnFree = PkiFree;
pCtl = (PCCTL_CONTEXT) CertCreateContext( CERT_STORE_CTL_CONTEXT, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbEncodedCtl, cbEncodedCtl, CERT_CREATE_CONTEXT_NOCOPY_FLAG, &CreateContextPara ); // For NO_COPY_FLAG, pbEncodedCtl is always freed, even for an error
pbEncodedCtl = NULL; if (NULL == pCtl) goto CreateCtlError;
CommonReturn: return pCtl;
ErrorReturn: assert(NULL == pCtl); if (pbEncodedCtl) PkiFree(pbEncodedCtl);
goto CommonReturn;
SET_ERROR(InvalidCabBlob, ERROR_INVALID_DATA) TRACE_ERROR(ExtractStlFromCabError) TRACE_ERROR(CreateCtlError) }
|