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
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;
|
|
}
|