windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pki/chain/extract.cpp

511 lines
14 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// 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)
}