Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2617 lines
79 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: oidfunc.cpp
//
// Contents: Cryptographic Object ID (OID) Functions
//
// Functions: I_CryptOIDFuncDllMain
// CryptInitOIDFunctionSet
// CryptInstallOIDFunctionAddress
//
// CryptSetOIDFunctionValue
// CryptGetOIDFunctionValue
// CryptRegisterOIDFunction
// CryptUnregisterOIDFunction
// CryptRegisterDefaultOIDFunction
// CryptUnregisterDefaultOIDFunction
// CryptEnumOIDFunction
//
// CryptGetOIDFunctionAddress
// CryptGetDefaultOIDDllList
// CryptGetDefaultOIDFunctionAddress
// CryptFreeOIDFunctionAddress
//
// Comments:
// For the CryptGetOIDFunctionAddress we search the installed
// const and str lists without
// entering the critical section. The adds which are within
// the critical section update the list pointers in the proper
// order to allow list searching without locking.
//
// However, registry loads are done with OIDFunc
// locked.
//
// HOLDING OID LOCK WHILE DOING A LoadLibrary() or FreeLibrary()
// MAY LEAD TO DEADLOCK !!!
//
//
// History: 07-Nov-96 philh created
// 09-Aug-98 philh changed to NOT hold OID lock when calling
// LoadLibrary() or FreeLibrary().
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
#define LEN_ALIGN(Len) ((Len + 7) & ~7)
#define CONST_OID_STR_PREFIX_CHAR '#'
//+-------------------------------------------------------------------------
// OID Element Type Definitions
//--------------------------------------------------------------------------
#define CONST_OID_TYPE 1
#define STR_OID_TYPE 2
#define DLL_OID_TYPE 3
//+-------------------------------------------------------------------------
// Dll and Procedure Element Definitions
//--------------------------------------------------------------------------
typedef struct _DLL_ELEMENT DLL_ELEMENT, *PDLL_ELEMENT;
typedef struct _DLL_PROC_ELEMENT DLL_PROC_ELEMENT, *PDLL_PROC_ELEMENT;
struct _DLL_ELEMENT {
DWORD dwOIDType;
PDLL_ELEMENT pNext;
LPWSTR pwszDll; // expanded
HMODULE hDll;
DWORD dwRefCnt;
BOOL fLoaded;
PDLL_PROC_ELEMENT pProcHead;
LPFNCANUNLOADNOW pfnDllCanUnloadNow;
// The following are used to defer the freeing of Dlls until after waiting
// at least one FREE_DLL_TIMEOUT.
DWORD dwFreeCnt; // 0, 1 or 2.
PDLL_ELEMENT pFreeNext;
PDLL_ELEMENT pFreePrev;
};
struct _DLL_PROC_ELEMENT {
PDLL_PROC_ELEMENT pNext;
PDLL_ELEMENT pDll;
LPSTR pszName;
void *pvAddr; // NULL'ed when Dll is unloaded
};
// Linked list of all the Dlls. All proc elements are on one of the Dll
// element's proc list.
static PDLL_ELEMENT pDllHead;
// Linked list of Dlls waiting to be freed.
static PDLL_ELEMENT pFreeDllHead;
// Count of elements in the above list
static DWORD dwFreeDllCnt;
// When nonzero, a FreeDll callback has been registered.
static LONG lFreeDll;
static HANDLE hFreeDllRegWaitFor;
static HMODULE hFreeDllLibModule;
// Crypt32.dll hInst
static HMODULE hOidInfoInst;
// 15 seconds
#define FREE_DLL_TIMEOUT 15000
//+-------------------------------------------------------------------------
// Installed OID Element Definitions
//--------------------------------------------------------------------------
typedef struct _CONST_OID_FUNC_ELEMENT
CONST_OID_FUNC_ELEMENT, *PCONST_OID_FUNC_ELEMENT;
struct _CONST_OID_FUNC_ELEMENT {
DWORD dwOIDType;
DWORD dwEncodingType;
PCONST_OID_FUNC_ELEMENT pNext;
DWORD_PTR dwLowOID;
DWORD_PTR dwHighOID;
HMODULE hDll;
void **rgpvFuncAddr;
};
typedef struct _STR_OID_FUNC_ELEMENT
STR_OID_FUNC_ELEMENT, *PSTR_OID_FUNC_ELEMENT;
struct _STR_OID_FUNC_ELEMENT {
DWORD dwOIDType;
DWORD dwEncodingType;
PSTR_OID_FUNC_ELEMENT pNext;
LPSTR pszOID;
HMODULE hDll;
void *pvFuncAddr;
};
//+-------------------------------------------------------------------------
// Registry OID Element Definitions
//--------------------------------------------------------------------------
typedef struct _REG_OID_FUNC_ELEMENT
REG_OID_FUNC_ELEMENT, *PREG_OID_FUNC_ELEMENT;
struct _REG_OID_FUNC_ELEMENT {
DWORD dwEncodingType;
PREG_OID_FUNC_ELEMENT pNext;
union {
DWORD_PTR dwOID;
LPSTR pszOID;
};
PDLL_PROC_ELEMENT pDllProc;
};
//+-------------------------------------------------------------------------
// Default registry DLL list Element Definitions
//--------------------------------------------------------------------------
typedef struct _DEFAULT_REG_ELEMENT
DEFAULT_REG_ELEMENT, *PDEFAULT_REG_ELEMENT;
struct _DEFAULT_REG_ELEMENT {
DWORD dwEncodingType;
PDEFAULT_REG_ELEMENT pNext;
LPWSTR pwszDllList;
DWORD cchDllList;
DWORD cDll;
LPWSTR *rgpwszDll;
PDLL_PROC_ELEMENT *rgpDllProc;
};
//+-------------------------------------------------------------------------
// Function Set Definition
//--------------------------------------------------------------------------
typedef struct _FUNC_SET FUNC_SET, *PFUNC_SET;
struct _FUNC_SET {
PFUNC_SET pNext;
LPSTR pszFuncName;
PCONST_OID_FUNC_ELEMENT pConstOIDFuncHead;
PCONST_OID_FUNC_ELEMENT pConstOIDFuncTail;
PSTR_OID_FUNC_ELEMENT pStrOIDFuncHead;
PSTR_OID_FUNC_ELEMENT pStrOIDFuncTail;
// Following are updated with OIDFunc locked
BOOL fRegLoaded;
PREG_OID_FUNC_ELEMENT pRegBeforeOIDFuncHead;
PREG_OID_FUNC_ELEMENT pRegAfterOIDFuncHead;
PDEFAULT_REG_ELEMENT pDefaultRegHead;
};
// Linked list of all the function sets
static PFUNC_SET pFuncSetHead;
// Used to protect the adding of function sets and elements to function sets.
// Protects the pDllHead list and registry loads.
static CRITICAL_SECTION OIDFuncCriticalSection;
//+-------------------------------------------------------------------------
// OIDFunc lock and unlock functions
//--------------------------------------------------------------------------
static inline void LockOIDFunc()
{
EnterCriticalSection(&OIDFuncCriticalSection);
}
static inline void UnlockOIDFunc()
{
LeaveCriticalSection(&OIDFuncCriticalSection);
}
//+-------------------------------------------------------------------------
// First try to get the EncodingType from the lower 16 bits. If 0, get
// from the upper 16 bits.
//--------------------------------------------------------------------------
static inline DWORD GetEncodingType(
IN DWORD dwEncodingType
)
{
return (dwEncodingType & CERT_ENCODING_TYPE_MASK) ?
(dwEncodingType & CERT_ENCODING_TYPE_MASK) :
(dwEncodingType & CMSG_ENCODING_TYPE_MASK) >> 16;
}
//+-------------------------------------------------------------------------
// Duplicate the Dll library's handle
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
static HMODULE DuplicateLibrary(
IN HMODULE hDll
)
{
if (hDll) {
WCHAR wszModule[_MAX_PATH + 1];
if (0 == GetModuleFileNameU(hDll, wszModule, _MAX_PATH))
goto GetModuleFileNameError;
wszModule[_MAX_PATH] = L'\0';
if (NULL == (hDll = LoadLibraryExU(wszModule, NULL, 0)))
goto LoadLibraryError;
}
CommonReturn:
return hDll;
ErrorReturn:
hDll = NULL;
goto CommonReturn;
TRACE_ERROR(GetModuleFileNameError)
TRACE_ERROR(LoadLibraryError)
}
//+-------------------------------------------------------------------------
// Add one or more functions with a constant OID. The constant OIDs are
// monotonically increasing.
//
// Upon entry, pFuncSet hasn't been added to the searched pFuncSetHead list.
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
STATIC BOOL AddConstOIDFunc(
IN HMODULE hDll,
IN DWORD dwEncodingType,
IN OUT PFUNC_SET pFuncSet,
IN DWORD cFuncEntry,
IN const CRYPT_OID_FUNC_ENTRY rgFuncEntry[]
)
{
PCONST_OID_FUNC_ELEMENT pEle;
DWORD cbEle;
void **ppvFuncAddr;
cbEle = sizeof(CONST_OID_FUNC_ELEMENT) + cFuncEntry * sizeof(void *);
if (NULL == (pEle = (PCONST_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
return FALSE;
pEle->dwOIDType = CONST_OID_TYPE;
pEle->dwEncodingType = dwEncodingType;
pEle->pNext = NULL;
pEle->dwLowOID = (DWORD_PTR) rgFuncEntry[0].pszOID;
pEle->dwHighOID = pEle->dwLowOID + cFuncEntry - 1;
pEle->hDll = DuplicateLibrary(hDll);
ppvFuncAddr =
(void **) (((BYTE *) pEle) + sizeof(CONST_OID_FUNC_ELEMENT));
pEle->rgpvFuncAddr = ppvFuncAddr;
for (DWORD i = 0; i < cFuncEntry; i++, ppvFuncAddr++)
*ppvFuncAddr = rgFuncEntry[i].pvFuncAddr;
if (pFuncSet->pConstOIDFuncTail)
pFuncSet->pConstOIDFuncTail->pNext = pEle;
else
pFuncSet->pConstOIDFuncHead = pEle;
pFuncSet->pConstOIDFuncTail = pEle;
return TRUE;
}
//+-------------------------------------------------------------------------
// Add single function with a string OID.
//
// Upon entry, pFuncSet hasn't been added to the searched pFuncSetHead list.
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
STATIC BOOL AddStrOIDFunc(
IN HMODULE hDll,
IN DWORD dwEncodingType,
IN OUT PFUNC_SET pFuncSet,
IN const CRYPT_OID_FUNC_ENTRY *pFuncEntry
)
{
PSTR_OID_FUNC_ELEMENT pEle;
DWORD cbEle;
DWORD cchOID;
LPSTR psz;
cchOID = strlen(pFuncEntry->pszOID) + 1;
cbEle = sizeof(STR_OID_FUNC_ELEMENT) + cchOID;
if (NULL == (pEle = (PSTR_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
return FALSE;
pEle->dwOIDType = STR_OID_TYPE;
pEle->dwEncodingType = dwEncodingType;
pEle->pNext = NULL;
psz = (LPSTR) (((BYTE *) pEle) + sizeof(STR_OID_FUNC_ELEMENT));
pEle->pszOID = psz;
memcpy(psz, pFuncEntry->pszOID, cchOID);
pEle->hDll = DuplicateLibrary(hDll);
pEle->pvFuncAddr = pFuncEntry->pvFuncAddr;
if (pFuncSet->pStrOIDFuncTail)
pFuncSet->pStrOIDFuncTail->pNext = pEle;
else
pFuncSet->pStrOIDFuncHead = pEle;
pFuncSet->pStrOIDFuncTail = pEle;
return TRUE;
}
//+-------------------------------------------------------------------------
// Free the constant or string function elements
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
STATIC void FreeFuncSetConstAndStrElements(
IN OUT PFUNC_SET pFuncSet
)
{
PCONST_OID_FUNC_ELEMENT pConstEle;
PSTR_OID_FUNC_ELEMENT pStrEle;
pConstEle = pFuncSet->pConstOIDFuncHead;
while (pConstEle) {
PCONST_OID_FUNC_ELEMENT pNextEle = pConstEle->pNext;
if (pConstEle->hDll)
FreeLibrary(pConstEle->hDll);
PkiFree(pConstEle);
pConstEle = pNextEle;
}
pStrEle = pFuncSet->pStrOIDFuncHead;
while (pStrEle) {
PSTR_OID_FUNC_ELEMENT pNextEle = pStrEle->pNext;
if (pStrEle->hDll)
FreeLibrary(pStrEle->hDll);
PkiFree(pStrEle);
pStrEle = pNextEle;
}
}
//+-------------------------------------------------------------------------
// Free the function set and its elements
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
STATIC void FreeFuncSet(
IN OUT PFUNC_SET pFuncSet
)
{
PREG_OID_FUNC_ELEMENT pRegEle;
PDEFAULT_REG_ELEMENT pDefaultReg;
FreeFuncSetConstAndStrElements(pFuncSet);
pRegEle = pFuncSet->pRegBeforeOIDFuncHead;
while (pRegEle) {
PREG_OID_FUNC_ELEMENT pNextEle = pRegEle->pNext;
PkiFree(pRegEle);
pRegEle = pNextEle;
}
pRegEle = pFuncSet->pRegAfterOIDFuncHead;
while (pRegEle) {
PREG_OID_FUNC_ELEMENT pNextEle = pRegEle->pNext;
PkiFree(pRegEle);
pRegEle = pNextEle;
}
pDefaultReg = pFuncSet->pDefaultRegHead;
while (pDefaultReg) {
PDEFAULT_REG_ELEMENT pNext = pDefaultReg->pNext;
PkiFree(pDefaultReg);
pDefaultReg = pNext;
}
PkiFree(pFuncSet);
}
//+-------------------------------------------------------------------------
// Free the Dll and its proc elements
//
// Upon entry/exit OIDFunc must NOT be locked!!
//--------------------------------------------------------------------------
STATIC void FreeDll(
IN OUT PDLL_ELEMENT pDll
)
{
PDLL_PROC_ELEMENT pProcEle;
pProcEle = pDll->pProcHead;
while (pProcEle) {
PDLL_PROC_ELEMENT pNextEle = pProcEle->pNext;
PkiFree(pProcEle);
pProcEle = pNextEle;
}
if (pDll->fLoaded) {
assert(pDll->hDll);
FreeLibrary(pDll->hDll);
}
PkiFree(pDll);
}
//+-------------------------------------------------------------------------
// Dll initialization
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptOIDFuncDllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fRet = TRUE;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
fRet = Pki_InitializeCriticalSection(&OIDFuncCriticalSection);
hOidInfoInst = hInst;
break;
case DLL_PROCESS_DETACH:
// Do interlock to guard against a potential race condition with
// the RegWaitFor callback thread. We doing this without doing
// a LockOIDFunc().
if (InterlockedExchange(&lFreeDll, 0)) {
assert(hFreeDllRegWaitFor);
hFreeDllLibModule = NULL;
ILS_UnregisterWait(hFreeDllRegWaitFor);
hFreeDllRegWaitFor = NULL;
}
while (pFuncSetHead) {
PFUNC_SET pFuncSet = pFuncSetHead;
pFuncSetHead = pFuncSet->pNext;
FreeFuncSet(pFuncSet);
}
while (pDllHead) {
PDLL_ELEMENT pDll = pDllHead;
pDllHead = pDll->pNext;
FreeDll(pDll);
}
DeleteCriticalSection(&OIDFuncCriticalSection);
break;
case DLL_THREAD_DETACH:
default:
break;
}
return fRet;
}
//+-------------------------------------------------------------------------
// Initialize and return handle to the OID function set identified by its
// function name.
//
// If the set already exists, a handle to the existing set is returned.
//--------------------------------------------------------------------------
HCRYPTOIDFUNCSET
WINAPI
CryptInitOIDFunctionSet(
IN LPCSTR pszFuncName,
IN DWORD dwFlags
)
{
PFUNC_SET pFuncSet;
LockOIDFunc();
// See if the set already exists
for (pFuncSet = pFuncSetHead; pFuncSet; pFuncSet = pFuncSet->pNext) {
if (0 == strcmp(pszFuncName, pFuncSet->pszFuncName))
break;
}
if (NULL == pFuncSet) {
// Allocate and initialize a new set
DWORD cchFuncName = strlen(pszFuncName) + 1;
if (pFuncSet = (PFUNC_SET) PkiZeroAlloc(
sizeof(FUNC_SET) + cchFuncName)) {
LPSTR psz = (LPSTR) (((BYTE *) pFuncSet) + sizeof(FUNC_SET));
pFuncSet->pszFuncName = psz;
memcpy(psz, pszFuncName, cchFuncName);
pFuncSet->pNext = pFuncSetHead;
pFuncSetHead = pFuncSet;
}
}
UnlockOIDFunc();
return (HCRYPTOIDFUNCSET) pFuncSet;
}
//+-------------------------------------------------------------------------
// Install a set of callable OID function addresses.
//
// By default the functions are installed at end of the list.
// Set CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG to install at beginning of list.
//
// hModule should be updated with the hModule passed to DllMain to prevent
// the Dll containing the function addresses from being unloaded by
// CryptGetOIDFuncAddress/CryptFreeOIDFunctionAddress. This would be the
// case when the Dll has also regsvr32'ed OID functions via
// CryptRegisterOIDFunction.
//
// DEFAULT functions are installed by setting rgFuncEntry[].pszOID =
// CRYPT_DEFAULT_OID.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptInstallOIDFunctionAddress(
IN HMODULE hModule, // hModule passed to DllMain
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN DWORD cFuncEntry,
IN const CRYPT_OID_FUNC_ENTRY rgFuncEntry[],
IN DWORD dwFlags
)
{
BOOL fResult;
PFUNC_SET pFuncSet;
FUNC_SET AddFuncSet;
memset(&AddFuncSet, 0, sizeof(AddFuncSet));
int ConstFirst = -1;
int ConstLast = 0;
DWORD_PTR dwOID;
DWORD_PTR dwLastOID = 0;
DWORD i;
dwEncodingType = GetEncodingType(dwEncodingType);
if (NULL == (pFuncSet = (PFUNC_SET) CryptInitOIDFunctionSet(
pszFuncName, 0)))
return FALSE;
// Don't need to hold lock while updating local copy of AddFuncSet.
for (i = 0; i < cFuncEntry; i++) {
if (0xFFFF >= (dwOID = (DWORD_PTR) rgFuncEntry[i].pszOID)) {
if (ConstFirst < 0)
ConstFirst = i;
else if (dwOID != dwLastOID + 1) {
if (!AddConstOIDFunc(
hModule,
dwEncodingType,
&AddFuncSet,
ConstLast - ConstFirst + 1,
&rgFuncEntry[ConstFirst]
)) goto AddConstOIDFuncError;
ConstFirst = i;
}
ConstLast = i;
dwLastOID = dwOID;
} else {
if (ConstFirst >= 0) {
if (!AddConstOIDFunc(
hModule,
dwEncodingType,
&AddFuncSet,
ConstLast - ConstFirst + 1,
&rgFuncEntry[ConstFirst]
)) goto AddConstOIDFuncError;
ConstFirst = -1;
}
if (!AddStrOIDFunc(
hModule,
dwEncodingType,
&AddFuncSet,
&rgFuncEntry[i]
)) goto AddStrOIDFuncError;
}
}
if (ConstFirst >= 0) {
if (!AddConstOIDFunc(
hModule,
dwEncodingType,
&AddFuncSet,
ConstLast - ConstFirst + 1,
&rgFuncEntry[ConstFirst]
)) goto AddConstOIDFuncError;
}
// NOTE:::
//
// Since the get function accesses the lists without entering the critical
// section, the following pointers must be updated in the correct
// order. Note, Get doesn't access the tail.
LockOIDFunc();
if (AddFuncSet.pConstOIDFuncHead) {
if (NULL == pFuncSet->pConstOIDFuncHead) {
pFuncSet->pConstOIDFuncHead = AddFuncSet.pConstOIDFuncHead;
pFuncSet->pConstOIDFuncTail = AddFuncSet.pConstOIDFuncTail;
} else if (dwFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
AddFuncSet.pConstOIDFuncTail->pNext = pFuncSet->pConstOIDFuncHead;
pFuncSet->pConstOIDFuncHead = AddFuncSet.pConstOIDFuncHead;
} else {
pFuncSet->pConstOIDFuncTail->pNext = AddFuncSet.pConstOIDFuncHead;
pFuncSet->pConstOIDFuncTail = AddFuncSet.pConstOIDFuncTail;
}
}
if (AddFuncSet.pStrOIDFuncHead) {
if (NULL == pFuncSet->pStrOIDFuncHead) {
pFuncSet->pStrOIDFuncHead = AddFuncSet.pStrOIDFuncHead;
pFuncSet->pStrOIDFuncTail = AddFuncSet.pStrOIDFuncTail;
} else if (dwFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
AddFuncSet.pStrOIDFuncTail->pNext = pFuncSet->pStrOIDFuncHead;
pFuncSet->pStrOIDFuncHead = AddFuncSet.pStrOIDFuncHead;
} else {
pFuncSet->pStrOIDFuncTail->pNext = AddFuncSet.pStrOIDFuncHead;
pFuncSet->pStrOIDFuncTail = AddFuncSet.pStrOIDFuncTail;
}
}
UnlockOIDFunc();
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
FreeFuncSetConstAndStrElements(&AddFuncSet);
goto CommonReturn;
TRACE_ERROR(AddConstOIDFuncError)
TRACE_ERROR(AddStrOIDFuncError)
}
STATIC LPSTR EncodingTypeToRegName(
IN DWORD dwEncodingType
)
{
LPSTR pszRegName;
DWORD cchRegName;
char szEncodingTypeValue[33];
dwEncodingType = GetEncodingType(dwEncodingType);
_ltoa(dwEncodingType, szEncodingTypeValue, 10);
cchRegName = strlen(CRYPT_OID_REG_ENCODING_TYPE_PREFIX) +
strlen(szEncodingTypeValue) +
1;
if (pszRegName = (LPSTR) PkiNonzeroAlloc(cchRegName)) {
strcpy(pszRegName, CRYPT_OID_REG_ENCODING_TYPE_PREFIX);
strcat(pszRegName, szEncodingTypeValue);
}
return pszRegName;
}
// Returns FALSE for an invalid EncodingType reg name
STATIC BOOL RegNameToEncodingType(
IN LPCSTR pszRegEncodingType,
OUT DWORD *pdwEncodingType
)
{
BOOL fResult = FALSE;
DWORD dwEncodingType = 0;
const DWORD cchPrefix = strlen(CRYPT_OID_REG_ENCODING_TYPE_PREFIX);
if (pszRegEncodingType && (DWORD) strlen(pszRegEncodingType) >= cchPrefix &&
2 == CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
pszRegEncodingType, cchPrefix,
CRYPT_OID_REG_ENCODING_TYPE_PREFIX, cchPrefix)) {
long lEncodingType;
lEncodingType = atol(pszRegEncodingType + cchPrefix);
if (lEncodingType >= 0 && lEncodingType <= 0xFFFF) {
dwEncodingType = (DWORD) lEncodingType;
fResult = TRUE;
}
}
*pdwEncodingType = dwEncodingType;
return fResult;
}
STATIC LPSTR FormatOIDFuncRegName(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID
)
{
LPSTR pszRegEncodingType;
LPSTR pszRegName;
DWORD cchRegName;
char szOID[34];
if (pszOID == NULL) {
SetLastError((DWORD) E_INVALIDARG);
return NULL;
}
if (NULL == (pszRegEncodingType = EncodingTypeToRegName(dwEncodingType)))
return NULL;
if ((DWORD_PTR) pszOID <= 0xFFFF) {
szOID[0] = CONST_OID_STR_PREFIX_CHAR;
_ltoa((long) ((DWORD_PTR)pszOID), szOID + 1, 10);
pszOID = szOID;
}
cchRegName = strlen(CRYPT_OID_REGPATH "\\") +
strlen(pszRegEncodingType) + 1 +
strlen(pszFuncName) + 1 +
strlen(pszOID) +
1;
if (pszRegName = (LPSTR) PkiNonzeroAlloc(cchRegName)) {
strcpy(pszRegName, CRYPT_OID_REGPATH "\\");
strcat(pszRegName, pszRegEncodingType);
strcat(pszRegName, "\\");
strcat(pszRegName, pszFuncName);
strcat(pszRegName, "\\");
strcat(pszRegName, pszOID);
}
PkiFree(pszRegEncodingType);
return pszRegName;
}
//+-------------------------------------------------------------------------
// Set the value for the specified encoding type, function name, OID and
// value name.
//
// See RegSetValueEx for the possible value types.
//
// String types are UNICODE.
//
// If pbValueData == NULL and cbValueData == 0, deletes the value.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptSetOIDFunctionValue(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN LPCWSTR pwszValueName,
IN DWORD dwValueType,
IN const BYTE *pbValueData,
IN DWORD cbValueData
)
{
BOOL fResult;
LONG lStatus;
LPSTR pszRegName = NULL;
HKEY hKey = NULL;
DWORD dwDisposition;
if (NULL == (pszRegName = FormatOIDFuncRegName(
dwEncodingType, pszFuncName, pszOID)))
goto FormatRegNameError;
if (ERROR_SUCCESS != (lStatus = RegCreateKeyExA(
HKEY_LOCAL_MACHINE,
pszRegName,
0, // dwReserved
NULL, // lpClass
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL, // lpSecurityAttributes
&hKey,
&dwDisposition)))
goto RegCreateKeyError;
if (NULL == pbValueData && 0 == cbValueData) {
if (ERROR_SUCCESS != (lStatus = RegDeleteValueU(
hKey,
pwszValueName)))
goto RegDeleteValueError;
} else {
if (ERROR_SUCCESS != (lStatus = RegSetValueExU(
hKey,
pwszValueName,
0, // dwReserved
dwValueType,
pbValueData,
cbValueData)))
goto RegSetValueError;
}
fResult = TRUE;
CommonReturn:
if (pszRegName)
PkiFree(pszRegName);
if (hKey)
RegCloseKey(hKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatRegNameError)
SET_ERROR_VAR(RegCreateKeyError, lStatus)
SET_ERROR_VAR(RegDeleteValueError, lStatus)
SET_ERROR_VAR(RegSetValueError, lStatus)
}
//+-------------------------------------------------------------------------
// Get the value for the specified encoding type, function name, OID and
// value name.
//
// See RegEnumValue for the possible value types.
//
// String types are UNICODE.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptGetOIDFunctionValue(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN LPCWSTR pwszValueName,
OUT DWORD *pdwValueType,
OUT BYTE *pbValueData,
IN OUT DWORD *pcbValueData
)
{
BOOL fResult;
LONG lStatus;
LPSTR pszRegName = NULL;
HKEY hKey = NULL;
if (NULL == (pszRegName = FormatOIDFuncRegName(
dwEncodingType, pszFuncName, pszOID)))
goto FormatRegNameError;
if (ERROR_SUCCESS != (lStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
pszRegName,
0, // dwReserved
KEY_READ,
&hKey))) {
if (ERROR_FILE_NOT_FOUND == lStatus) {
// Inhibit error tracing
SetLastError((DWORD) lStatus);
goto ErrorReturn;
}
goto RegOpenKeyError;
}
if (ERROR_SUCCESS != (lStatus = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // lpdwReserved
pdwValueType,
pbValueData,
pcbValueData))) goto RegQueryValueError;
fResult = TRUE;
CommonReturn:
if (pszRegName)
PkiFree(pszRegName);
if (hKey)
RegCloseKey(hKey);
return fResult;
ErrorReturn:
*pdwValueType = 0;
*pcbValueData = 0;
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatRegNameError)
SET_ERROR_VAR(RegOpenKeyError, lStatus)
SET_ERROR_VAR(RegQueryValueError, lStatus)
}
//+-------------------------------------------------------------------------
// Register the Dll containing the function to be called for the specified
// encoding type, function name and OID.
//
// pwszDll may contain environment-variable strings
// which are ExpandEnvironmentStrings()'ed before loading the Dll.
//
// In addition to registering the DLL, you may override the
// name of the function to be called. For example,
// pszFuncName = "CryptDllEncodeObject",
// pszOverrideFuncName = "MyEncodeXyz".
// This allows a Dll to export multiple OID functions for the same
// function name without needing to interpose its own OID dispatcher function.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptRegisterOIDFunction(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN OPTIONAL LPCWSTR pwszDll,
IN OPTIONAL LPCSTR pszOverrideFuncName
)
{
BOOL fResult;
LPWSTR pwszOverrideFuncName = NULL;
if (pwszDll) {
if (!CryptSetOIDFunctionValue(
dwEncodingType,
pszFuncName,
pszOID,
CRYPT_OID_REG_DLL_VALUE_NAME,
REG_SZ,
(BYTE *) pwszDll,
(wcslen(pwszDll) + 1) * sizeof(WCHAR)))
goto SetDllError;
}
if (pszOverrideFuncName) {
if (NULL == (pwszOverrideFuncName = MkWStr(
(LPSTR) pszOverrideFuncName)))
goto MkWStrError;
if (!CryptSetOIDFunctionValue(
dwEncodingType,
pszFuncName,
pszOID,
CRYPT_OID_REG_FUNC_NAME_VALUE_NAME,
REG_SZ,
(BYTE *) pwszOverrideFuncName,
(wcslen(pwszOverrideFuncName) + 1) * sizeof(WCHAR)))
goto SetFuncNameError;
}
fResult = TRUE;
CommonReturn:
if (pwszOverrideFuncName)
FreeWStr(pwszOverrideFuncName);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(SetDllError)
TRACE_ERROR(SetFuncNameError)
TRACE_ERROR(MkWStrError)
}
//+-------------------------------------------------------------------------
// Unregister the Dll containing the function to be called for the specified
// encoding type, function name and OID.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptUnregisterOIDFunction(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID
)
{
BOOL fResult;
LONG lStatus;
LPSTR pszRegName = NULL;
LPSTR pszRegOID;
HKEY hKey = NULL;
if (NULL == (pszRegName = FormatOIDFuncRegName(
dwEncodingType, pszFuncName, pszOID)))
goto FormatRegNameError;
// Separate off the OID component of the RegName. Its the
// last component of the name.
pszRegOID = pszRegName + strlen(pszRegName);
while (*pszRegOID != '\\')
pszRegOID--;
*pszRegOID++ = '\0';
if (ERROR_SUCCESS != (lStatus = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
pszRegName,
0, // dwReserved
KEY_WRITE,
&hKey))) goto RegOpenKeyError;
if (ERROR_SUCCESS != (lStatus = RegDeleteKeyA(
hKey,
pszRegOID)))
goto RegDeleteKeyError;
fResult = TRUE;
CommonReturn:
if (pszRegName)
PkiFree(pszRegName);
if (hKey)
RegCloseKey(hKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatRegNameError)
SET_ERROR_VAR(RegOpenKeyError, lStatus)
SET_ERROR_VAR(RegDeleteKeyError, lStatus)
}
STATIC BOOL GetDefaultDllList(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
OUT LPWSTR pwszList,
IN OUT DWORD *pcchList
)
{
BOOL fResult;
DWORD dwType;
DWORD cchList;
DWORD cbList;
cchList = *pcchList;
if (pwszList) {
if (cchList < 3)
goto InvalidArg;
else
// make room for two extra null terminators
cchList -= 2;
} else
cchList = 0;
cbList = cchList * sizeof(WCHAR);
fResult = CryptGetOIDFunctionValue(
dwEncodingType,
pszFuncName,
CRYPT_DEFAULT_OID,
CRYPT_OID_REG_DLL_VALUE_NAME,
&dwType,
(BYTE *) pwszList,
&cbList);
cchList = cbList / sizeof(WCHAR);
if (!fResult) {
if (ERROR_FILE_NOT_FOUND != GetLastError()) {
if (cchList)
cchList += 2;
goto GetOIDFunctionValueError;
}
cchList = 0;
} else if (!(REG_MULTI_SZ == dwType ||
REG_SZ == dwType || REG_EXPAND_SZ == dwType))
goto BadDefaultListRegType;
if (pwszList) {
// Ensure the list has two null terminators
pwszList[cchList++] = L'\0';
pwszList[cchList++] = L'\0';
} else {
if (cchList == 0)
cchList = 3;
else
cchList += 2;
}
fResult = TRUE;
CommonReturn:
*pcchList = cchList;
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOIDFunctionValueError)
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(BadDefaultListRegType, E_INVALIDARG)
}
// Remove any entries following the first empty string.
STATIC DWORD AdjustDefaultListLength(
IN LPCWSTR pwszList
)
{
LPCWSTR pwsz = pwszList;
DWORD cch;
while (cch = wcslen(pwsz))
pwsz += cch + 1;
return (DWORD)(pwsz - pwszList) + 1;
}
//+-------------------------------------------------------------------------
// Register the Dll containing the default function to be called for the
// specified encoding type and function name.
//
// Unlike CryptRegisterOIDFunction, you can't override the function name
// needing to be exported by the Dll.
//
// The Dll is inserted before the entry specified by dwIndex.
// dwIndex == 0, inserts at the beginning.
// dwIndex == CRYPT_REGISTER_LAST_INDEX, appends at the end.
//
// pwszDll may contain environment-variable strings
// which are ExpandEnvironmentStrings()'ed before loading the Dll.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptRegisterDefaultOIDFunction(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN DWORD dwIndex,
IN LPCWSTR pwszDll
)
{
BOOL fResult;
LPWSTR pwszDllList; // _alloca'ed
DWORD cchDllList;
DWORD cchDll;
LPWSTR pwsz, pwszInsert, pwszSrc, pwszDest;
DWORD cch, cchRemain;
if (NULL == pwszDll || L'\0' == *pwszDll)
goto InvalidArg;
cchDll = wcslen(pwszDll) + 1;
if (!GetDefaultDllList(
dwEncodingType,
pszFuncName,
NULL, // pwszDllList
&cchDllList)) goto GetDefaultDllListError;
__try {
pwszDllList = (LPWSTR) _alloca((cchDllList + cchDll) * sizeof(WCHAR));
} __except(EXCEPTION_EXECUTE_HANDLER) {
goto OutOfMemory;
}
if (!GetDefaultDllList(
dwEncodingType,
pszFuncName,
pwszDllList,
&cchDllList)) goto GetDefaultDllListError;
// Remove entries following the first empty entry
assert(AdjustDefaultListLength(pwszDllList) <= cchDllList);
cchDllList = AdjustDefaultListLength(pwszDllList);
// Check if the Dll already exists in the list
pwsz = pwszDllList;
while (cch = wcslen(pwsz)) {
if (0 == _wcsicmp(pwsz, pwszDll))
goto DllExistsError;
pwsz += cch + 1;
}
// Find the Null terminated DLL in the DllList to insert before.
// We insert before the dwIndex.
pwszInsert = pwszDllList;
while (dwIndex-- && 0 != (cch = wcslen(pwszInsert)))
pwszInsert += cch + 1;
// Before inserting, we need to move all the remaining entries in the
// existing DllList.
//
// Note, there must be at least the final zero terminator at
// pwszDllList[cchDllList - 1].
assert(pwszInsert < pwszDllList + cchDllList);
if (pwszInsert >= pwszDllList + cchDllList)
goto BadRegMultiSzError;
cchRemain = (DWORD)((pwszDllList + cchDllList) - pwszInsert);
assert(cchRemain);
pwszSrc = pwszDllList + cchDllList - 1;
pwszDest = pwszSrc + cchDll;
while (cchRemain--)
*pwszDest-- = *pwszSrc--;
assert(pwszSrc + 1 == pwszInsert);
// Insert the pwszDll
memcpy(pwszInsert, pwszDll, cchDll * sizeof(WCHAR));
if (!CryptSetOIDFunctionValue(
dwEncodingType,
pszFuncName,
CRYPT_DEFAULT_OID,
CRYPT_OID_REG_DLL_VALUE_NAME,
REG_MULTI_SZ,
(BYTE *) pwszDllList,
(cchDllList + cchDll) * sizeof(WCHAR))) goto SetDllListError;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
SET_ERROR(DllExistsError, ERROR_FILE_EXISTS)
SET_ERROR(BadRegMultiSzError, E_INVALIDARG)
TRACE_ERROR(GetDefaultDllListError)
TRACE_ERROR(SetDllListError)
}
BOOL
WINAPI
CryptUnregisterDefaultOIDFunction(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCWSTR pwszDll
)
{
BOOL fResult;
LPWSTR pwszDllList; // _alloca'ed
DWORD cchDllList;
DWORD cchDll;
LPWSTR pwszDelete, pwszMove;
DWORD cchDelete, cchRemain;
if (NULL == pwszDll || L'\0' == *pwszDll)
goto InvalidArg;
cchDll = wcslen(pwszDll) + 1;
if (!GetDefaultDllList(
dwEncodingType,
pszFuncName,
NULL, // pwszDllList
&cchDllList)) goto GetDefaultDllListError;
__try {
pwszDllList = (LPWSTR) _alloca(cchDllList * sizeof(WCHAR));
} __except(EXCEPTION_EXECUTE_HANDLER) {
goto OutOfMemory;
}
if (!GetDefaultDllList(
dwEncodingType,
pszFuncName,
pwszDllList,
&cchDllList)) goto GetDefaultDllListError;
// Remove entries following the first empty entry
assert(AdjustDefaultListLength(pwszDllList) <= cchDllList);
cchDllList = AdjustDefaultListLength(pwszDllList);
// Search the DllList for a match
pwszDelete = pwszDllList;
while (cchDelete = wcslen(pwszDelete)) {
if (0 == _wcsicmp(pwszDll, pwszDelete))
break;
pwszDelete += cchDelete + 1;
}
if (0 == cchDelete) goto DllNotFound;
cchDelete++;
assert(cchDelete == cchDll);
// Move all the Dll entries that follow.
//
// Note, there must be at least the final zero terminator at
// pwszDllList[cchDllList - 1].
pwszMove = pwszDelete + cchDelete;
assert(pwszMove < pwszDllList + cchDllList);
if (pwszMove >= pwszDllList + cchDllList)
goto BadRegMultiSzError;
cchRemain = (DWORD)((pwszDllList + cchDllList) - pwszMove);
assert(cchRemain);
while (cchRemain--)
*pwszDelete++ = *pwszMove++;
if (!CryptSetOIDFunctionValue(
dwEncodingType,
pszFuncName,
CRYPT_DEFAULT_OID,
CRYPT_OID_REG_DLL_VALUE_NAME,
REG_MULTI_SZ,
(BYTE *) pwszDllList,
(cchDllList - cchDelete) * sizeof(WCHAR))) goto SetDllListError;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(DllNotFound, ERROR_FILE_NOT_FOUND)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
SET_ERROR(BadRegMultiSzError, E_INVALIDARG)
TRACE_ERROR(GetDefaultDllListError)
TRACE_ERROR(SetDllListError)
}
#define MAX_SUBKEY_LEN 128
STATIC HKEY GetNextRegSubKey(
IN HKEY hKey,
IN OUT DWORD *piSubKey,
IN LPCSTR pszFuncNameMatch,
OUT char szSubKeyName[MAX_SUBKEY_LEN]
)
{
HKEY hSubKey;
if (pszFuncNameMatch && *pszFuncNameMatch) {
if ((*piSubKey)++ > 0 || strlen(pszFuncNameMatch) >= MAX_SUBKEY_LEN)
return NULL;
strcpy(szSubKeyName, pszFuncNameMatch);
} else {
if (ERROR_SUCCESS != RegEnumKeyA(
hKey,
(*piSubKey)++,
szSubKeyName,
MAX_SUBKEY_LEN))
return NULL;
}
if (ERROR_SUCCESS == RegOpenKeyExA(
hKey,
szSubKeyName,
0, // dwReserved
KEY_READ,
&hSubKey))
return hSubKey;
else
return NULL;
}
STATIC BOOL GetRegValues(
IN HKEY hKey,
OUT void **ppvAlloc,
OUT DWORD *pcValue,
OUT DWORD **ppdwValueType,
OUT LPWSTR **pppwszValueName,
OUT BYTE ***pppbValueData,
OUT DWORD **ppcbValueData
)
{
BOOL fResult;
LONG lStatus;
void *pvAlloc = NULL;
DWORD cValue;
DWORD iValue;
DWORD cchMaxName;
DWORD cbMaxData;
DWORD cbAlignData = 0;
DWORD *pdwValueType;
LPWSTR *ppwszValueName;
BYTE **ppbValueData;
DWORD *pcbValueData;
LPWSTR pwszName;
BYTE *pbData;
if (ERROR_SUCCESS != (lStatus = RegQueryInfoKeyU(
hKey,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cValue,
&cchMaxName,
&cbMaxData,
NULL,
NULL
))) goto RegQueryInfoKeyError;
// Do a single allocation for all the arrays, value names and
// value data. Update the array pointers.
if (cValue > 0) {
BYTE *pbAlloc;
DWORD cbAlloc;
// Include NULL terminator for the name and align the data length
// Also, include two NULL terminators to be added for the data.
// Ensures REG_MULTI_SZ is always NULL terminated.
cchMaxName++;
if (4 > cbMaxData)
cbMaxData = 4;
cbAlignData = LEN_ALIGN(cbMaxData + 2 * sizeof(WCHAR));
cbAlloc = (sizeof(DWORD) + sizeof(LPWSTR) + sizeof(BYTE *) +
sizeof(DWORD) + cchMaxName * sizeof(WCHAR) + cbAlignData) * cValue;
if (NULL == (pvAlloc = PkiNonzeroAlloc(cbAlloc)))
goto OutOfMemory;
pbAlloc = (BYTE *) pvAlloc;
ppwszValueName = (LPWSTR *) pbAlloc;
pbAlloc += sizeof(LPWSTR) * cValue;
ppbValueData = (BYTE **) pbAlloc;
pbAlloc += sizeof(BYTE *) * cValue;
pdwValueType = (DWORD *) pbAlloc;
pbAlloc += sizeof(DWORD) * cValue;
pcbValueData = (DWORD *) pbAlloc;
pbAlloc += sizeof(DWORD) * cValue;
pbData = pbAlloc;
pbAlloc += cbAlignData * cValue;
pwszName = (LPWSTR) pbAlloc;
assert(((BYTE *) pvAlloc) + cbAlloc ==
pbAlloc + (cchMaxName * sizeof(WCHAR)) * cValue);
} else {
ppwszValueName = NULL;
ppbValueData = NULL;
pdwValueType = NULL;
pcbValueData = NULL;
pbData = NULL;
pwszName = NULL;
}
for (iValue = 0; iValue < cValue;
iValue++, pwszName += cchMaxName, pbData += cbAlignData) {
DWORD cchName = cchMaxName;
DWORD cbData = cbMaxData;
DWORD dwType;
if (ERROR_SUCCESS != (lStatus = RegEnumValueU(
hKey,
iValue,
pwszName,
&cchName,
NULL, // pdwReserved
&dwType,
pbData,
&cbData
)))
goto RegEnumValueError;
// Ensure the data has two NULL terminators for REG_MULTI_SZ
// Note cbAlignData >= cbMaxData + 2 * sizeof(WCHAR)
memset(pbData + cbData, 0, 2 * sizeof(WCHAR));
pdwValueType[iValue] = dwType;
ppwszValueName[iValue] = pwszName;
ppbValueData[iValue] = pbData;
pcbValueData[iValue] = cbData;
}
fResult = TRUE;
CommonReturn:
*ppvAlloc = pvAlloc;
*pcValue = cValue;
*ppdwValueType = pdwValueType;
*pppwszValueName = ppwszValueName;
*pppbValueData = ppbValueData;
*ppcbValueData = pcbValueData;
return fResult;
ErrorReturn:
if (pvAlloc) {
PkiFree(pvAlloc);
pvAlloc = NULL;
}
cValue = 0;
pdwValueType = NULL;
ppwszValueName = NULL;
ppbValueData = NULL;
pcbValueData = NULL;
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR_VAR(RegQueryInfoKeyError, lStatus)
SET_ERROR_VAR(RegEnumValueError, lStatus)
}
//+-------------------------------------------------------------------------
// Enumerate the OID functions identified by their encoding type,
// function name and OID.
//
// pfnEnumOIDFunc is called for each registry key matching the input
// parameters. Setting dwEncodingType to CRYPT_MATCH_ANY_ENCODING_TYPE matches
// any. Setting pszFuncName or pszOID to NULL matches any.
//
// Set pszOID == CRYPT_DEFAULT_OID to restrict the enumeration to only the
// DEFAULT functions
//
// String types are UNICODE.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptEnumOIDFunction(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CRYPT_ENUM_OID_FUNC pfnEnumOIDFunc
)
{
HKEY hRegKey;
LPSTR pszEncodingType = NULL;
char szOID[34];
if (CRYPT_MATCH_ANY_ENCODING_TYPE != dwEncodingType) {
dwEncodingType = GetEncodingType(dwEncodingType);
if (NULL == (pszEncodingType = EncodingTypeToRegName(dwEncodingType)))
return FALSE;
}
if (pszOID && (DWORD_PTR) pszOID <= 0xFFFF) {
szOID[0] = CONST_OID_STR_PREFIX_CHAR;
_ltoa((DWORD) ((DWORD_PTR)pszOID), szOID + 1, 10);
pszOID = szOID;
}
if (ERROR_SUCCESS == RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
CRYPT_OID_REGPATH,
0, // dwReserved
KEY_READ,
&hRegKey)) {
// Enumerate and optionally match encoding type
HKEY hEncodingTypeKey;
DWORD iEncodingType = 0;
char szRegEncodingType[MAX_SUBKEY_LEN];
while (hEncodingTypeKey = GetNextRegSubKey(hRegKey,
&iEncodingType, pszEncodingType, szRegEncodingType)) {
// Convert the EncodingType string and validate
DWORD dwRegEncodingType;
if (RegNameToEncodingType(szRegEncodingType, &dwRegEncodingType)) {
// Enumerate and optionally match FuncName, for example,
// ("CryptDllEncodeObject")
HKEY hFuncName;
DWORD iFuncName = 0;
char szRegFuncName[MAX_SUBKEY_LEN];
while (hFuncName = GetNextRegSubKey(hEncodingTypeKey,
&iFuncName, pszFuncName, szRegFuncName)) {
// Enumerate and optionally match OID string ("1.2.3.4")
HKEY hOID;
DWORD iOID = 0;
char szRegOID[MAX_SUBKEY_LEN];
while (hOID = GetNextRegSubKey(hFuncName, &iOID, pszOID,
szRegOID)) {
// Read and allocate the registry values
void *pvAlloc;
DWORD cValue;
DWORD *pdwValueType;
LPWSTR *ppwszValueName;
BYTE **ppbValueData;
DWORD *pcbValueData;
if (GetRegValues(
hOID,
&pvAlloc,
&cValue,
&pdwValueType,
&ppwszValueName,
&ppbValueData,
&pcbValueData)) {
pfnEnumOIDFunc(
dwRegEncodingType,
szRegFuncName,
szRegOID,
cValue,
pdwValueType,
(LPCWSTR *) ppwszValueName,
(const BYTE **) ppbValueData,
pcbValueData,
pvArg);
if (pvAlloc)
PkiFree(pvAlloc);
}
RegCloseKey(hOID);
}
RegCloseKey(hFuncName);
}
}
RegCloseKey(hEncodingTypeKey);
}
RegCloseKey(hRegKey);
}
if (pszEncodingType)
PkiFree(pszEncodingType);
return TRUE;
}
//+=========================================================================
// Registry and Dll Load Functions
//==========================================================================
// Note, returned Dll element isn't AddRef'ed
STATIC PDLL_ELEMENT FindDll(
IN LPCWSTR pwszDll // not expanded
)
{
LPWSTR pwszExpandDll; // _alloca'ed
WCHAR rgch[4];
DWORD cchDll;
PDLL_ELEMENT pDll;
if (0 == (cchDll = ExpandEnvironmentStringsU(
pwszDll,
rgch, // lpszDest, NON_NULL for win95
sizeof(rgch)/sizeof(rgch[0])))) // cchDest
return NULL;
__try {
pwszExpandDll = (LPWSTR) _alloca(cchDll * sizeof(WCHAR));
} __except(EXCEPTION_EXECUTE_HANDLER) {
return NULL;
}
if (0 == ExpandEnvironmentStringsU(
pwszDll,
pwszExpandDll,
cchDll))
return NULL;
LockOIDFunc();
// Check if we already have an entry
for (pDll = pDllHead; pDll; pDll = pDll->pNext) {
if (0 == _wcsicmp(pwszExpandDll, pDll->pwszDll))
break;
}
if (NULL == pDll) {
// Need to create a new DLL entry and add to our list
if (pDll = (PDLL_ELEMENT) PkiZeroAlloc(
sizeof(DLL_ELEMENT) + cchDll * sizeof(WCHAR))) {
LPWSTR pwszEleDll;
pDll->dwOIDType = DLL_OID_TYPE;
pwszEleDll = (LPWSTR) ((BYTE *) pDll + sizeof(DLL_ELEMENT));
memcpy(pwszEleDll, pwszExpandDll, cchDll * sizeof(WCHAR));
pDll->pwszDll = pwszEleDll;
pDll->pNext = pDllHead;
pDllHead = pDll;
}
}
UnlockOIDFunc();
return pDll;
}
// Upon entry/exit OIDFunc is locked
STATIC PDLL_PROC_ELEMENT AddDllProc(
IN LPCSTR pszFuncName,
IN LPCWSTR pwszDll
)
{
PDLL_PROC_ELEMENT pProcEle = NULL;
PDLL_ELEMENT pDll;
DWORD cchFuncName;
DWORD cbEle;
LPSTR psz;
cchFuncName = strlen(pszFuncName) + 1;
cbEle = sizeof(DLL_PROC_ELEMENT) + cchFuncName;
if (NULL == (pProcEle = (PDLL_PROC_ELEMENT) PkiZeroAlloc(cbEle)))
goto OutOfMemory;
if (NULL == (pDll = FindDll(pwszDll)))
goto FindDllError;
pProcEle->pNext = pDll->pProcHead;
pDll->pProcHead = pProcEle;
pProcEle->pDll = pDll;
psz = (LPSTR) ((BYTE *) pProcEle + sizeof(DLL_PROC_ELEMENT));
memcpy(psz, pszFuncName, cchFuncName);
pProcEle->pszName = psz;
pProcEle->pvAddr = NULL;
CommonReturn:
return pProcEle;
ErrorReturn:
PkiFree(pProcEle);
pProcEle = NULL;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(FindDllError)
}
// Upon entry/exit OIDFunc is locked
STATIC void AddRegOIDFunc(
IN DWORD dwEncodingType,
IN OUT PFUNC_SET pFuncSet,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN LPCWSTR pwszDll,
IN DWORD dwCryptFlags
)
{
PREG_OID_FUNC_ELEMENT pOIDEle = NULL;
PDLL_PROC_ELEMENT pProcEle; // not allocated, doesn't need to be free'ed
DWORD cchOID;
DWORD cbEle;
LPSTR psz;
if (0xFFFF < (DWORD_PTR) pszOID)
cchOID = strlen(pszOID) + 1;
else
cchOID = 0;
cbEle = sizeof(REG_OID_FUNC_ELEMENT) + cchOID;
if (NULL == (pOIDEle = (PREG_OID_FUNC_ELEMENT) PkiZeroAlloc(cbEle)))
goto OutOfMemory;
if (NULL == (pProcEle = AddDllProc(pszFuncName, pwszDll)))
goto AddDllProcError;
pOIDEle->dwEncodingType = dwEncodingType;
if (dwCryptFlags & CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG) {
pOIDEle->pNext = pFuncSet->pRegBeforeOIDFuncHead;
pFuncSet->pRegBeforeOIDFuncHead = pOIDEle;
} else {
pOIDEle->pNext = pFuncSet->pRegAfterOIDFuncHead;
pFuncSet->pRegAfterOIDFuncHead = pOIDEle;
}
if (cchOID) {
psz = (LPSTR) ((BYTE *) pOIDEle + sizeof(REG_OID_FUNC_ELEMENT));
memcpy(psz, pszOID, cchOID);
pOIDEle->pszOID = psz;
} else
pOIDEle->dwOID = (DWORD_PTR) pszOID;
pOIDEle->pDllProc = pProcEle;
CommonReturn:
return;
ErrorReturn:
PkiFree(pOIDEle);
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(AddDllProcError)
}
// Upon entry/exit OIDFunc is locked
STATIC void AddDefaultDllList(
IN DWORD dwEncodingType,
IN OUT PFUNC_SET pFuncSet,
IN LPCWSTR pwszInDllList,
IN DWORD cchInDllList
)
{
LPWSTR pwszDllList; // _alloca'ed
LPWSTR pwsz;
DWORD cchDllList;
DWORD cchDll;
DWORD cDll;
DWORD i;
PDEFAULT_REG_ELEMENT pEle = NULL;
DWORD cbEle;
LPWSTR *ppwszEleDll;
PDLL_PROC_ELEMENT *ppEleDllProc;
LPWSTR pwszEleDllList;
// Ensure cchDllList has 2 terminating NULL characters
assert(cchInDllList && pwszInDllList);
cchDllList = cchInDllList + 2;
__try {
pwszDllList = (LPWSTR) _alloca(cchDllList * sizeof(WCHAR));
} __except(EXCEPTION_EXECUTE_HANDLER) {
goto OutOfMemory;
}
memcpy(pwszDllList, pwszInDllList, cchInDllList * sizeof(WCHAR));
pwszDllList[cchInDllList] = L'\0';
pwszDllList[cchInDllList + 1] = L'\0';
// Get count of null terminated Dlls
cDll = 0;
for (pwsz = pwszDllList; 0 != (cchDll = wcslen(pwsz)); pwsz += cchDll + 1)
cDll++;
if (0 == cDll)
goto NoDll;
cbEle = sizeof(DEFAULT_REG_ELEMENT) +
cDll * sizeof(LPWSTR) +
cDll * sizeof(PDLL_PROC_ELEMENT) +
cchDllList * sizeof(WCHAR)
;
if (NULL == (pEle = (PDEFAULT_REG_ELEMENT) PkiZeroAlloc(cbEle)))
goto OutOfMemory;
ppwszEleDll = (LPWSTR *) ((BYTE *) pEle + sizeof(DEFAULT_REG_ELEMENT));
ppEleDllProc = (PDLL_PROC_ELEMENT *) ((BYTE *) ppwszEleDll +
cDll * sizeof(LPWSTR));
pwszEleDllList = (LPWSTR) ((BYTE *) ppEleDllProc +
cDll * sizeof(PDLL_PROC_ELEMENT));
assert((BYTE *) pwszEleDllList + cchDllList * sizeof(WCHAR) ==
(BYTE *) pEle + cbEle);
pEle->dwEncodingType = dwEncodingType;
// pEle->pNext =
memcpy(pwszEleDllList, pwszDllList, cchDllList * sizeof(WCHAR));
pEle->pwszDllList = pwszEleDllList;
pEle->cchDllList = cchDllList;
pEle->cDll = cDll;
pEle->rgpwszDll = ppwszEleDll;
pEle->rgpDllProc = ppEleDllProc;
for (pwsz = pwszEleDllList, i = 0;
0 != (cchDll = wcslen(pwsz)); pwsz += cchDll + 1, i++) {
ppwszEleDll[i] = pwsz;
if (NULL == (ppEleDllProc[i] = AddDllProc(
pFuncSet->pszFuncName, pwsz)))
goto AddDllProcError;
}
assert (i == cDll);
pEle->pNext = pFuncSet->pDefaultRegHead;
pFuncSet->pDefaultRegHead = pEle;
CommonReturn:
return;
ErrorReturn:
PkiFree(pEle);
goto CommonReturn;
TRACE_ERROR(NoDll);
TRACE_ERROR(OutOfMemory);
TRACE_ERROR(AddDllProcError);
}
//+-------------------------------------------------------------------------
// Called by CryptEnumOIDFunction to enumerate through all the
// registered OID functions.
//
// Called with OIDFunc locked
//--------------------------------------------------------------------------
STATIC BOOL WINAPI EnumRegFuncCallback(
IN DWORD dwEncodingType,
IN LPCSTR pszFuncName,
IN LPCSTR pszOID,
IN DWORD cValue,
IN const DWORD rgdwValueType[],
IN LPCWSTR const rgpwszValueName[],
IN const BYTE * const rgpbValueData[],
IN const DWORD rgcbValueData[],
IN void *pvArg
)
{
PFUNC_SET pFuncSet = (PFUNC_SET) pvArg;
BOOL fDefaultDllList = FALSE;
LPCWSTR pwszDll = NULL; // not allocated
DWORD cchDll = 0;
LPCWSTR pwszOverrideFuncName = NULL; // not allocated
DWORD dwCryptFlags = 0;
assert(pFuncSet);
if (CONST_OID_STR_PREFIX_CHAR == *pszOID) {
// Convert "#<number>" string to its corresponding constant OID value
pszOID = (LPCSTR)(DWORD_PTR) atol(pszOID + 1);
if (0xFFFF < (DWORD_PTR) pszOID)
// Invalid OID. Skip it.
goto InvalidOID;
} else if (0 == _stricmp(CRYPT_DEFAULT_OID, pszOID))
fDefaultDllList = TRUE;
while (cValue--) {
LPCWSTR pwszValueName = rgpwszValueName[cValue];
DWORD dwValueType = rgdwValueType[cValue];
const BYTE *pbValueData = rgpbValueData[cValue];
DWORD cbValueData = rgcbValueData[cValue];
if (0 == _wcsicmp(pwszValueName, CRYPT_OID_REG_DLL_VALUE_NAME)) {
if (REG_SZ == dwValueType || REG_EXPAND_SZ == dwValueType ||
(fDefaultDllList && REG_MULTI_SZ == dwValueType)) {
pwszDll = (LPCWSTR) pbValueData;
cchDll = cbValueData / sizeof(WCHAR);
} else
// Invalid "Dll" value.
goto InvalidDll;
} else if (0 == _wcsicmp(pwszValueName,
CRYPT_OID_REG_FUNC_NAME_VALUE_NAME)) {
if (REG_SZ == dwValueType) {
LPCWSTR pwszValue = (LPCWSTR) pbValueData;
if (L'\0' != *pwszValue)
pwszOverrideFuncName = pwszValue;
} else
// Invalid "FuncName" value.
goto InvalidFuncName;
} else if (0 == _wcsicmp(pwszValueName,
CRYPT_OID_REG_FLAGS_VALUE_NAME)) {
if (REG_DWORD == dwValueType &&
cbValueData >= sizeof(dwCryptFlags))
memcpy(&dwCryptFlags, pbValueData, sizeof(dwCryptFlags));
// else
// Ignore invalid CryptFlags value type
}
}
if (0 == cchDll || L'\0' == *pwszDll)
goto NoDll;
if (fDefaultDllList)
AddDefaultDllList(
dwEncodingType,
pFuncSet,
pwszDll,
cchDll
);
else {
BYTE rgb[_MAX_PATH];
if (pwszOverrideFuncName) {
if (!MkMBStr(rgb, _MAX_PATH, pwszOverrideFuncName,
(LPSTR *) &pszFuncName))
goto MkMBStrError;
}
AddRegOIDFunc(
dwEncodingType,
pFuncSet,
pszFuncName,
pszOID,
pwszDll,
dwCryptFlags
);
if (pwszOverrideFuncName)
FreeMBStr(rgb, (LPSTR) pszFuncName);
}
CommonReturn:
return TRUE;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(InvalidOID)
TRACE_ERROR(InvalidDll)
TRACE_ERROR(InvalidFuncName)
TRACE_ERROR(NoDll)
TRACE_ERROR(MkMBStrError)
}
STATIC void LoadRegFunc(
IN OUT PFUNC_SET pFuncSet
)
{
LockOIDFunc();
if (pFuncSet->fRegLoaded)
goto CommonReturn;
CryptEnumOIDFunction(
CRYPT_MATCH_ANY_ENCODING_TYPE,
pFuncSet->pszFuncName,
NULL, // pszOID
0, // dwFlags
(void *) pFuncSet, // pvArg
EnumRegFuncCallback
);
pFuncSet->fRegLoaded = TRUE;
CommonReturn:
UnlockOIDFunc();
return;
}
// Upon entry/exit OIDFunc is locked
STATIC void RemoveFreeDll(
IN PDLL_ELEMENT pDll
)
{
// Remove Dll from free list
if (pDll->pFreeNext)
pDll->pFreeNext->pFreePrev = pDll->pFreePrev;
if (pDll->pFreePrev)
pDll->pFreePrev->pFreeNext = pDll->pFreeNext;
else if (pDll == pFreeDllHead)
pFreeDllHead = pDll->pFreeNext;
// else
// Not on any list
pDll->pFreeNext = NULL;
pDll->pFreePrev = NULL;
assert(dwFreeDllCnt);
if (dwFreeDllCnt)
dwFreeDllCnt--;
}
// Upon entry/exit OIDFunc is locked
STATIC void AddRefDll(
IN PDLL_ELEMENT pDll
)
{
pDll->dwRefCnt++;
if (pDll->dwFreeCnt) {
pDll->dwFreeCnt = 0;
RemoveFreeDll(pDll);
}
}
// Note, MUST NOT HOLD OID LOCK WHILE CALLING FreeLibrary()!!
//
// Therefore, will put the Dll's to be freed on a list while holding the
// OID LOCK. After releasing the OID LOCK, will iterate through the
// list and call FreeLibrary().
STATIC VOID NTAPI FreeDllWaitForCallback(
PVOID Context,
BOOLEAN fWaitOrTimedOut // ???
)
{
PDLL_ELEMENT pFreeDll;
HMODULE *phFreeLibrary = NULL; // _alloca'ed
DWORD cFreeLibrary = 0;
LockOIDFunc();
if (dwFreeDllCnt) {
DWORD dwOrigFreeDllCnt = dwFreeDllCnt;
__try {
phFreeLibrary = (HMODULE *) _alloca(
dwOrigFreeDllCnt * sizeof(HMODULE));
} __except(EXCEPTION_EXECUTE_HANDLER) {
goto OutOfMemory;
}
pFreeDll = pFreeDllHead;
assert(pFreeDll);
while (pFreeDll) {
PDLL_ELEMENT pDll = pFreeDll;
pFreeDll = pFreeDll->pFreeNext;
assert(pDll->dwFreeCnt);
if (0 == --pDll->dwFreeCnt) {
RemoveFreeDll(pDll);
assert(pDll->fLoaded);
if (!pDll->fLoaded)
continue;
if (NULL == pDll->pfnDllCanUnloadNow ||
S_OK == pDll->pfnDllCanUnloadNow()) {
assert(cFreeLibrary < dwOrigFreeDllCnt);
if (cFreeLibrary < dwOrigFreeDllCnt) {
PDLL_PROC_ELEMENT pEle;
// Loop and NULL all proc addresses
for (pEle = pDll->pProcHead; pEle; pEle = pEle->pNext)
pEle->pvAddr = NULL;
pDll->pfnDllCanUnloadNow = NULL;
// Add to array to be freed after releasing lock!!
assert(pDll->hDll);
phFreeLibrary[cFreeLibrary++] = pDll->hDll;
pDll->hDll = NULL;
pDll->fLoaded = FALSE;
}
}
}
}
} else {
assert(NULL == pFreeDllHead);
}
if (NULL == pFreeDllHead) {
assert(0 == dwFreeDllCnt);
// Do interlock to guard against a potential race condition at
// PROCESS_DETACH. Note, PROCESS_DETACH doesn't do a LockOIDFunc().
if (InterlockedExchange(&lFreeDll, 0)) {
HANDLE hRegWaitFor;
HMODULE hDllLibModule;
hRegWaitFor = hFreeDllRegWaitFor;
hFreeDllRegWaitFor = NULL;
hDllLibModule = hFreeDllLibModule;
hFreeDllLibModule = NULL;
UnlockOIDFunc();
while (cFreeLibrary--)
FreeLibrary(phFreeLibrary[cFreeLibrary]);
assert(hRegWaitFor);
ILS_ExitWait(hRegWaitFor, hDllLibModule);
assert(FALSE);
return;
}
}
CommonReturn:
UnlockOIDFunc();
while (cFreeLibrary--)
FreeLibrary(phFreeLibrary[cFreeLibrary]);
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(OutOfMemory);
}
STATIC void ReleaseDll(
IN PDLL_ELEMENT pDll
)
{
LockOIDFunc();
assert(pDll->dwRefCnt);
if (0 == --pDll->dwRefCnt) {
assert(pDll->fLoaded);
if (!pDll->fLoaded)
goto CommonReturn;
assert(0 == pDll->dwFreeCnt);
if (pDll->dwFreeCnt)
goto CommonReturn;
if (0 == lFreeDll) {
assert(NULL == hFreeDllRegWaitFor);
assert(NULL == hFreeDllLibModule);
// Inhibit crypt32.dll from being unloaded until this thread
// exits.
hFreeDllLibModule = DuplicateLibrary(hOidInfoInst);
if (!ILS_RegisterWaitForSingleObject(
&hFreeDllRegWaitFor,
NULL, // hObject
FreeDllWaitForCallback,
NULL, // Context
FREE_DLL_TIMEOUT,
0 // dwFlags
)) {
hFreeDllRegWaitFor = NULL;
if (hFreeDllLibModule) {
FreeLibrary(hFreeDllLibModule);
hFreeDllLibModule = NULL;
}
goto RegisterWaitForError;
}
lFreeDll = 1;
}
assert(NULL == pDll->pFreeNext);
assert(NULL == pDll->pFreePrev);
pDll->dwFreeCnt = 2;
if (pFreeDllHead) {
pFreeDllHead->pFreePrev = pDll;
pDll->pFreeNext = pFreeDllHead;
}
pFreeDllHead = pDll;
dwFreeDllCnt++;
}
CommonReturn:
UnlockOIDFunc();
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(RegisterWaitForError)
}
// Upon entry/exit OIDFunc must NOT be locked!!
STATIC BOOL LoadDll(
IN PDLL_ELEMENT pDll
)
{
BOOL fResult;
HMODULE hDll = NULL;
LPFNCANUNLOADNOW pfnDllCanUnloadNow = NULL;
LockOIDFunc();
if (pDll->fLoaded)
AddRefDll(pDll);
else {
UnlockOIDFunc();
// NO LoadLibrary() or GetProcAddress() while holding OID lock!!
hDll = LoadLibraryExU(pDll->pwszDll, NULL, 0);
if (hDll)
pfnDllCanUnloadNow = (LPFNCANUNLOADNOW) GetProcAddress(
hDll, "DllCanUnloadNow");
LockOIDFunc();
AddRefDll(pDll);
if (!pDll->fLoaded) {
assert(1 == pDll->dwRefCnt);
assert(0 == pDll->dwFreeCnt);
assert(pDll->pwszDll);
assert(NULL == pDll->hDll);
if (NULL == (pDll->hDll = hDll)) {
pDll->dwRefCnt = 0;
goto LoadLibraryError;
}
hDll = NULL;
pDll->fLoaded = TRUE;
assert(NULL == pDll->pfnDllCanUnloadNow);
pDll->pfnDllCanUnloadNow = pfnDllCanUnloadNow;
}
}
fResult = TRUE;
CommonReturn:
UnlockOIDFunc();
if (hDll) {
// Dll was loaded by another thread.
DWORD dwErr = GetLastError();
FreeLibrary(hDll);
SetLastError(dwErr);
}
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(LoadLibraryError);
}
// Upon entry/exit OIDFunc must NOT be locked!!
STATIC BOOL GetDllProcAddr(
IN PDLL_PROC_ELEMENT pEle,
OUT void **ppvFuncAddr,
OUT HCRYPTOIDFUNCADDR *phFuncAddr
)
{
BOOL fResult;
void *pvAddr;
PDLL_ELEMENT pDll;
LockOIDFunc();
pDll = pEle->pDll;
assert(pDll);
if (pvAddr = pEle->pvAddr)
AddRefDll(pDll);
else {
UnlockOIDFunc();
// NO LoadLibrary() or GetProcAddress() while holding OID lock!!
fResult = LoadDll(pDll);
if (fResult) {
assert(pDll->hDll);
pvAddr = GetProcAddress(pDll->hDll, pEle->pszName);
}
LockOIDFunc();
if (!fResult)
goto LoadDllError;
if (pvAddr)
pEle->pvAddr = pvAddr;
else {
ReleaseDll(pDll);
goto GetProcAddressError;
}
}
fResult = TRUE;
CommonReturn:
*ppvFuncAddr = pvAddr;
*phFuncAddr = (HCRYPTOIDFUNCADDR) pDll;
UnlockOIDFunc();
return fResult;
ErrorReturn:
fResult = FALSE;
pDll = NULL;
pvAddr = NULL;
goto CommonReturn;
TRACE_ERROR(LoadDllError)
TRACE_ERROR(GetProcAddressError)
}
// Upon entry/exit OIDFunc must NOT be locked!!
STATIC BOOL GetRegOIDFunctionAddress(
IN PREG_OID_FUNC_ELEMENT pRegEle,
IN DWORD dwEncodingType,
IN LPCSTR pszOID,
OUT void **ppvFuncAddr,
OUT HCRYPTOIDFUNCADDR *phFuncAddr
)
{
for (; pRegEle; pRegEle = pRegEle->pNext) {
if (dwEncodingType != pRegEle->dwEncodingType)
continue;
if (0xFFFF >= (DWORD_PTR) pszOID) {
if (pszOID != pRegEle->pszOID)
continue;
} else {
if (0xFFFF >= (DWORD_PTR) pRegEle->pszOID ||
0 != _stricmp(pszOID, pRegEle->pszOID))
continue;
}
return GetDllProcAddr(
pRegEle->pDllProc,
ppvFuncAddr,
phFuncAddr
);
}
*ppvFuncAddr = NULL;
*phFuncAddr = NULL;
return FALSE;
}
// Upon entry/exit OIDFunc must NOT be locked!!
STATIC BOOL GetDefaultRegOIDFunctionAddress(
IN PFUNC_SET pFuncSet,
IN DWORD dwEncodingType,
IN LPCWSTR pwszDll,
OUT void **ppvFuncAddr,
OUT HCRYPTOIDFUNCADDR *phFuncAddr
)
{
PDEFAULT_REG_ELEMENT pRegEle = pFuncSet->pDefaultRegHead;
PDLL_ELEMENT pDll;
for (; pRegEle; pRegEle = pRegEle->pNext) {
if (dwEncodingType != pRegEle->dwEncodingType)
continue;
for (DWORD i = 0; i < pRegEle->cDll; i++) {
if (0 == _wcsicmp(pwszDll, pRegEle->rgpwszDll[i]))
return GetDllProcAddr(
pRegEle->rgpDllProc[i],
ppvFuncAddr,
phFuncAddr
);
}
}
if (pDll = FindDll(pwszDll)) {
if (LoadDll(pDll)) {
if (*ppvFuncAddr = GetProcAddress(pDll->hDll,
pFuncSet->pszFuncName)) {
*phFuncAddr = (HCRYPTOIDFUNCADDR) pDll;
return TRUE;
} else
ReleaseDll(pDll);
}
}
*ppvFuncAddr = NULL;
*phFuncAddr = NULL;
return FALSE;
}
//+-------------------------------------------------------------------------
// Search the list of installed functions for an OID and EncodingType match.
// If not found, search the registry.
//
// For success, returns TRUE with *ppvFuncAddr updated with the function's
// address and *phFuncAddr updated with the function address's handle.
// The function's handle is AddRef'ed. CryptFreeOIDFunctionAddress needs to
// be called to release it.
//
// For a registry match, the Dll containing the function is loaded.
//
// By default, both the registered and installed function lists are searched.
// Set CRYPT_GET_INSTALLED_OID_FUNC_FLAG to only search the installed list
// of functions. This flag would be set by a registered function to get
// the address of a pre-installed function it was replacing. For example,
// the registered function might handle a new special case and call the
// pre-installed function to handle the remaining cases.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptGetOIDFunctionAddress(
IN HCRYPTOIDFUNCSET hFuncSet,
IN DWORD dwEncodingType,
IN LPCSTR pszOID,
IN DWORD dwFlags,
OUT void **ppvFuncAddr,
OUT HCRYPTOIDFUNCADDR *phFuncAddr
)
{
PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
DWORD_PTR dwOID;
dwEncodingType = GetEncodingType(dwEncodingType);
if (0xFFFF < (DWORD_PTR) pszOID && CONST_OID_STR_PREFIX_CHAR == *pszOID) {
// Convert "#<number>" string to its corresponding constant OID value
pszOID = (LPCSTR)(DWORD_PTR) atol(pszOID + 1);
if (0xFFFF < (DWORD_PTR) pszOID) {
SetLastError((DWORD) E_INVALIDARG);
*ppvFuncAddr = NULL;
*phFuncAddr = NULL;
return FALSE;
}
}
if (!pFuncSet->fRegLoaded)
LoadRegFunc(pFuncSet);
if (0 == (dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG) &&
pFuncSet->pRegBeforeOIDFuncHead) {
if (GetRegOIDFunctionAddress(
pFuncSet->pRegBeforeOIDFuncHead,
dwEncodingType,
pszOID,
ppvFuncAddr,
phFuncAddr
))
return TRUE;
}
if (0xFFFF >= (dwOID = (DWORD_PTR) pszOID)) {
PCONST_OID_FUNC_ELEMENT pConstEle = pFuncSet->pConstOIDFuncHead;
while (pConstEle) {
if (dwEncodingType == pConstEle->dwEncodingType &&
dwOID >= pConstEle->dwLowOID &&
dwOID <= pConstEle->dwHighOID) {
*ppvFuncAddr = pConstEle->rgpvFuncAddr[
dwOID - pConstEle->dwLowOID];
*phFuncAddr = (HCRYPTOIDFUNCADDR) pConstEle;
return TRUE;
}
pConstEle = pConstEle->pNext;
}
} else {
PSTR_OID_FUNC_ELEMENT pStrEle = pFuncSet->pStrOIDFuncHead;
while (pStrEle) {
if (dwEncodingType == pStrEle->dwEncodingType &&
0 == _stricmp(pszOID, pStrEle->pszOID)) {
*ppvFuncAddr = pStrEle->pvFuncAddr;
*phFuncAddr = (HCRYPTOIDFUNCADDR) pStrEle;
return TRUE;
}
pStrEle = pStrEle->pNext;
}
}
if (0 == (dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG) &&
pFuncSet->pRegAfterOIDFuncHead) {
if (GetRegOIDFunctionAddress(
pFuncSet->pRegAfterOIDFuncHead,
dwEncodingType,
pszOID,
ppvFuncAddr,
phFuncAddr
))
return TRUE;
}
SetLastError((DWORD) ERROR_FILE_NOT_FOUND);
*ppvFuncAddr = NULL;
*phFuncAddr = NULL;
return FALSE;
}
//+-------------------------------------------------------------------------
// Get the list of registered default Dll entries for the specified
// function set and encoding type.
//
// The returned list consists of none, one or more null terminated Dll file
// names. The list is terminated with an empty (L"\0") Dll file name.
// For example: L"first.dll" L"\0" L"second.dll" L"\0" L"\0"
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptGetDefaultOIDDllList(
IN HCRYPTOIDFUNCSET hFuncSet,
IN DWORD dwEncodingType,
OUT LPWSTR pwszDllList,
IN OUT DWORD *pcchDllList
)
{
BOOL fResult;
PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
PDEFAULT_REG_ELEMENT pRegEle;
DWORD cchRegDllList = 2;
LPWSTR pwszRegDllList = L"\0\0";
if (!pFuncSet->fRegLoaded)
LoadRegFunc(pFuncSet);
dwEncodingType = GetEncodingType(dwEncodingType);
pRegEle = pFuncSet->pDefaultRegHead;
for (; pRegEle; pRegEle = pRegEle->pNext) {
if (dwEncodingType == pRegEle->dwEncodingType) {
cchRegDllList = pRegEle->cchDllList;
assert(cchRegDllList >= 2);
pwszRegDllList = pRegEle->pwszDllList;
break;
}
}
fResult = TRUE;
if (pwszDllList) {
if (cchRegDllList > *pcchDllList) {
SetLastError((DWORD) ERROR_MORE_DATA);
fResult = FALSE;
} else
memcpy(pwszDllList, pwszRegDllList, cchRegDllList * sizeof(WCHAR));
}
*pcchDllList = cchRegDllList;
return fResult;
}
//+-------------------------------------------------------------------------
// Either: get the first or next installed DEFAULT function OR
// load the Dll containing the DEFAULT function.
//
// If pwszDll is NULL, search the list of installed DEFAULT functions.
// *phFuncAddr must be set to NULL to get the first installed function.
// Successive installed functions are returned by setting *phFuncAddr
// to the hFuncAddr returned by the previous call.
//
// If pwszDll is NULL, the input *phFuncAddr
// is always CryptFreeOIDFunctionAddress'ed by this function, even for
// an error.
//
// If pwszDll isn't NULL, then, attempts to load the Dll and the DEFAULT
// function. *phFuncAddr is ignored upon entry and isn't
// CryptFreeOIDFunctionAddress'ed.
//
// For success, returns TRUE with *ppvFuncAddr updated with the function's
// address and *phFuncAddr updated with the function address's handle.
// The function's handle is AddRef'ed. CryptFreeOIDFunctionAddress needs to
// be called to release it or CryptGetDefaultOIDFunctionAddress can also
// be called for a NULL pwszDll.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptGetDefaultOIDFunctionAddress(
IN HCRYPTOIDFUNCSET hFuncSet,
IN DWORD dwEncodingType,
IN OPTIONAL LPCWSTR pwszDll,
IN DWORD dwFlags,
OUT void **ppvFuncAddr,
IN OUT HCRYPTOIDFUNCADDR *phFuncAddr
)
{
PFUNC_SET pFuncSet = (PFUNC_SET) hFuncSet;
if (!pFuncSet->fRegLoaded)
LoadRegFunc(pFuncSet);
dwEncodingType = GetEncodingType(dwEncodingType);
if (NULL == pwszDll) {
// Get from installed list
PSTR_OID_FUNC_ELEMENT pStrEle = (PSTR_OID_FUNC_ELEMENT) *phFuncAddr;
if (pStrEle && STR_OID_TYPE == pStrEle->dwOIDType)
pStrEle = pStrEle->pNext;
else
pStrEle = pFuncSet->pStrOIDFuncHead;
while (pStrEle) {
if (dwEncodingType == pStrEle->dwEncodingType &&
0 == _stricmp(CRYPT_DEFAULT_OID, pStrEle->pszOID)) {
*ppvFuncAddr = pStrEle->pvFuncAddr;
*phFuncAddr = (HCRYPTOIDFUNCADDR) pStrEle;
return TRUE;
}
pStrEle = pStrEle->pNext;
}
SetLastError(ERROR_FILE_NOT_FOUND);
*ppvFuncAddr = NULL;
*phFuncAddr = NULL;
return FALSE;
} else
return GetDefaultRegOIDFunctionAddress(
pFuncSet,
dwEncodingType,
pwszDll,
ppvFuncAddr,
phFuncAddr);
}
//+-------------------------------------------------------------------------
// Releases the handle AddRef'ed and returned by CryptGetOIDFunctionAddress
// or CryptGetDefaultOIDFunctionAddress.
//
// If a Dll was loaded for the function its unloaded. However, before doing
// the unload, the DllCanUnloadNow function exported by the loaded Dll is
// called. It should return S_FALSE to inhibit the unload or S_TRUE to enable
// the unload. If the Dll doesn't export DllCanUnloadNow, the Dll is unloaded.
//
// DllCanUnloadNow has the following signature:
// STDAPI DllCanUnloadNow(void);
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptFreeOIDFunctionAddress(
IN HCRYPTOIDFUNCADDR hFuncAddr,
IN DWORD dwFlags
)
{
PDLL_ELEMENT pDll = (PDLL_ELEMENT) hFuncAddr;
if (pDll && DLL_OID_TYPE == pDll->dwOIDType) {
DWORD dwErr = GetLastError();
ReleaseDll(pDll);
SetLastError(dwErr);
}
return TRUE;
}