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.
 
 
 
 
 
 

11369 lines
357 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: logstor.cpp
//
// Contents: Registry Certificate Store Provider APIs
//
// Functions: I_RegStoreDllMain
// I_CertDllOpenRegStoreProv
// CertRegisterSystemStore
// CertRegisterPhysicalStore
// CertUnregisterSystemStore
// CertUnregisterPhysicalStore
// CertEnumSystemStoreLocation
// CertEnumSystemStore
// CertEnumPhysicalStore
// I_CertDllOpenSystemRegistryStoreProvW
// I_CertDllOpenSystemRegistryStoreProvA
// I_CertDllOpenSystemStoreProvW
// I_CertDllOpenSystemStoreProvA
// I_CertDllOpenPhysicalStoreProvW
//
// History: 28-Dec-96 philh created
// 13-Aug-96 philh added change notify and resync support
// 24-Aug-96 philh added logical store support
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
// Note, this flag must not collide with CertControlStore dwFlags
#define REG_STORE_CTRL_CANCEL_NOTIFY_FLAG 0x80000000
// Pointer to an allocated LONG containing thread's enum recursion depth
static HCRYPTTLS hTlsEnumPhysicalStoreDepth;
#define MAX_ENUM_PHYSICAL_STORE_DEPTH 20
#define SYSTEM_STORE_REGPATH L"Software\\Microsoft\\SystemCertificates"
#define PHYSICAL_STORES_SUBKEY_NAME L"PhysicalStores"
#define CONST_OID_STR_PREFIX_CHAR '#'
#define SERVICES_REGPATH L"Software\\Microsoft\\Cryptography\\Services"
#define SYSTEM_CERTIFICATES_SUBKEY_NAME L"SystemCertificates"
#define GROUP_POLICY_STORE_REGPATH L"Software\\Policies\\Microsoft\\SystemCertificates"
#define ENTERPRISE_STORE_REGPATH L"Software\\Microsoft\\EnterpriseCertificates"
#define ROAMING_MY_STORE_SUBDIR L"Microsoft\\SystemCertificates\\My"
#define ROAMING_REQUEST_STORE_SUBDIR L"Microsoft\\SystemCertificates\\Request"
#define REGISTER_FLAGS_MASK (CERT_SYSTEM_STORE_MASK | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_CREATE_NEW_FLAG)
#define UNREGISTER_FLAGS_MASK (CERT_SYSTEM_STORE_MASK | \
CERT_STORE_DELETE_FLAG | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_OPEN_EXISTING_FLAG)
#define ENUM_FLAGS_MASK (CERT_SYSTEM_STORE_MASK | \
CERT_STORE_OPEN_EXISTING_FLAG | \
CERT_STORE_MAXIMUM_ALLOWED_FLAG | \
CERT_STORE_SHARE_CONTEXT_FLAG | \
CERT_STORE_SHARE_STORE_FLAG | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_READONLY_FLAG)
#define OPEN_REG_FLAGS_MASK (CERT_STORE_CREATE_NEW_FLAG | \
CERT_STORE_DELETE_FLAG | \
CERT_STORE_OPEN_EXISTING_FLAG | \
CERT_STORE_MAXIMUM_ALLOWED_FLAG | \
CERT_STORE_SHARE_CONTEXT_FLAG | \
CERT_STORE_SHARE_STORE_FLAG | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_READONLY_FLAG | \
CERT_STORE_MANIFOLD_FLAG | \
CERT_STORE_UPDATE_KEYID_FLAG | \
CERT_STORE_ENUM_ARCHIVED_FLAG | \
CERT_STORE_SET_LOCALIZED_NAME_FLAG | \
CERT_STORE_NO_CRYPT_RELEASE_FLAG | \
CERT_REGISTRY_STORE_REMOTE_FLAG | \
CERT_REGISTRY_STORE_SERIALIZED_FLAG | \
CERT_REGISTRY_STORE_ROAMING_FLAG | \
CERT_REGISTRY_STORE_CLIENT_GPT_FLAG | \
CERT_REGISTRY_STORE_MY_IE_DIRTY_FLAG | \
CERT_REGISTRY_STORE_LM_GPT_FLAG)
#define OPEN_SYS_FLAGS_MASK (CERT_SYSTEM_STORE_MASK | \
CERT_STORE_CREATE_NEW_FLAG | \
CERT_STORE_DELETE_FLAG | \
CERT_STORE_OPEN_EXISTING_FLAG | \
CERT_STORE_MAXIMUM_ALLOWED_FLAG | \
CERT_STORE_SHARE_CONTEXT_FLAG | \
CERT_STORE_SHARE_STORE_FLAG | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_READONLY_FLAG | \
CERT_STORE_MANIFOLD_FLAG | \
CERT_STORE_UPDATE_KEYID_FLAG | \
CERT_STORE_ENUM_ARCHIVED_FLAG | \
CERT_STORE_SET_LOCALIZED_NAME_FLAG | \
CERT_STORE_NO_CRYPT_RELEASE_FLAG)
#define OPEN_PHY_FLAGS_MASK (CERT_SYSTEM_STORE_MASK | \
CERT_STORE_DELETE_FLAG | \
CERT_STORE_OPEN_EXISTING_FLAG | \
CERT_STORE_MAXIMUM_ALLOWED_FLAG | \
CERT_STORE_SHARE_CONTEXT_FLAG | \
CERT_STORE_SHARE_STORE_FLAG | \
CERT_STORE_BACKUP_RESTORE_FLAG | \
CERT_STORE_READONLY_FLAG | \
CERT_STORE_MANIFOLD_FLAG | \
CERT_STORE_UPDATE_KEYID_FLAG | \
CERT_STORE_ENUM_ARCHIVED_FLAG | \
CERT_STORE_SET_LOCALIZED_NAME_FLAG | \
CERT_STORE_NO_CRYPT_RELEASE_FLAG)
//+-------------------------------------------------------------------------
// Common, global logical store critical section. Used by:
// GptStore, Win95Store, RoamingStore.
//--------------------------------------------------------------------------
static CRITICAL_SECTION ILS_CriticalSection;
//+-------------------------------------------------------------------------
// Registry Store Context SubKeys
//--------------------------------------------------------------------------
#define CONTEXT_COUNT 3
static const LPCWSTR rgpwszContextSubKeyName[CONTEXT_COUNT] = {
L"Certificates",
L"CRLs",
L"CTLs"
};
#define KEYID_CONTEXT_NAME L"Keys"
static DWORD rgdwContextTypeFlags[CONTEXT_COUNT] = {
CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
CERT_STORE_CRL_CONTEXT_FLAG,
CERT_STORE_CTL_CONTEXT_FLAG
};
#define MY_SYSTEM_INDEX 0
#define ROOT_SYSTEM_INDEX 1
#define TRUST_SYSTEM_INDEX 2
#define CA_SYSTEM_INDEX 3
#define USER_DS_SYSTEM_INDEX 4
#define TRUST_PUB_SYSTEM_INDEX 5
#define DISALLOWED_SYSTEM_INDEX 6
#define AUTH_ROOT_SYSTEM_INDEX 7
#define TRUST_PEOPLE_SYSTEM_INDEX 8
#define MY_SYSTEM_FLAG (1 << MY_SYSTEM_INDEX)
#define ROOT_SYSTEM_FLAG (1 << ROOT_SYSTEM_INDEX)
#define TRUST_SYSTEM_FLAG (1 << TRUST_SYSTEM_INDEX)
#define CA_SYSTEM_FLAG (1 << CA_SYSTEM_INDEX)
#define USER_DS_SYSTEM_FLAG (1 << USER_DS_SYSTEM_INDEX)
#define TRUST_PUB_SYSTEM_FLAG (1 << TRUST_PUB_SYSTEM_INDEX)
#define DISALLOWED_SYSTEM_FLAG (1 << DISALLOWED_SYSTEM_INDEX)
#define AUTH_ROOT_SYSTEM_FLAG (1 << AUTH_ROOT_SYSTEM_INDEX)
#define TRUST_PEOPLE_SYSTEM_FLAG (1 << TRUST_PEOPLE_SYSTEM_INDEX)
#define COMMON_SYSTEM_FLAGS ( \
MY_SYSTEM_FLAG | \
ROOT_SYSTEM_FLAG | \
TRUST_SYSTEM_FLAG | \
CA_SYSTEM_FLAG | \
TRUST_PUB_SYSTEM_FLAG | \
DISALLOWED_SYSTEM_FLAG | \
AUTH_ROOT_SYSTEM_FLAG | \
TRUST_PEOPLE_SYSTEM_FLAG \
)
#define wsz_MY_STORE L"My"
#define wsz_ROOT_STORE L"Root"
#define wsz_TRUST_STORE L"Trust"
#define wsz_CA_STORE L"CA"
#define wsz_USER_DS_STORE L"UserDS"
#define wsz_TRUST_PUB_STORE L"TrustedPublisher"
#define wsz_DISALLOWED_STORE L"Disallowed"
#define wsz_AUTH_ROOT_STORE L"AuthRoot"
#define wsz_TRUST_PEOPLE_STORE L"TrustedPeople"
static LPCWSTR rgpwszPredefinedSystemStore[] = {
wsz_MY_STORE,
wsz_ROOT_STORE,
wsz_TRUST_STORE,
wsz_CA_STORE,
wsz_USER_DS_STORE,
wsz_TRUST_PUB_STORE,
wsz_DISALLOWED_STORE,
wsz_AUTH_ROOT_STORE,
wsz_TRUST_PEOPLE_STORE
};
#define NUM_PREDEFINED_SYSTEM_STORE (sizeof(rgpwszPredefinedSystemStore) / \
sizeof(rgpwszPredefinedSystemStore[0]))
#define wsz_REQUEST_STORE L"Request"
#define DEFAULT_PHYSICAL_INDEX 0
#define AUTH_ROOT_PHYSICAL_INDEX 1
#define GROUP_POLICY_PHYSICAL_INDEX 2
#define LOCAL_MACHINE_PHYSICAL_INDEX 3
#define DS_USER_CERT_PHYSICAL_INDEX 4
#define LMGP_PHYSICAL_INDEX 5
#define ENTERPRISE_PHYSICAL_INDEX 6
#define NUM_PREDEFINED_PHYSICAL 7
#define DEFAULT_PHYSICAL_FLAG (1 << DEFAULT_PHYSICAL_INDEX)
#define AUTH_ROOT_PHYSICAL_FLAG (1 << AUTH_ROOT_PHYSICAL_INDEX)
#define GROUP_POLICY_PHYSICAL_FLAG (1 << GROUP_POLICY_PHYSICAL_INDEX)
#define LOCAL_MACHINE_PHYSICAL_FLAG (1 << LOCAL_MACHINE_PHYSICAL_INDEX)
#define DS_USER_CERT_PHYSICAL_FLAG (1 << DS_USER_CERT_PHYSICAL_INDEX)
#define LMGP_PHYSICAL_FLAG (1 << LMGP_PHYSICAL_INDEX)
#define ENTERPRISE_PHYSICAL_FLAG (1 << ENTERPRISE_PHYSICAL_INDEX)
static LPCWSTR rgpwszPredefinedPhysical[NUM_PREDEFINED_PHYSICAL] = {
CERT_PHYSICAL_STORE_DEFAULT_NAME,
CERT_PHYSICAL_STORE_AUTH_ROOT_NAME,
CERT_PHYSICAL_STORE_GROUP_POLICY_NAME,
CERT_PHYSICAL_STORE_LOCAL_MACHINE_NAME,
CERT_PHYSICAL_STORE_DS_USER_CERTIFICATE_NAME,
CERT_PHYSICAL_STORE_LOCAL_MACHINE_GROUP_POLICY_NAME,
CERT_PHYSICAL_STORE_ENTERPRISE_NAME,
};
#define NOT_IN_REGISTRY_SYSTEM_STORE_LOCATION_FLAG 0x1
#define REMOTABLE_SYSTEM_STORE_LOCATION_FLAG 0x2
#define SERIALIZED_SYSTEM_STORE_LOCATION_FLAG 0x4
#define LM_SYSTEM_STORE_LOCATION_FLAG 0x8
typedef struct _SYSTEM_STORE_LOCATION_INFO {
DWORD dwFlags;
DWORD dwPredefinedSystemFlags;
DWORD dwPredefinedPhysicalFlags;
} SYSTEM_STORE_LOCATION_INFO, *PSYSTEM_STORE_LOCATION_INFO;
static const SYSTEM_STORE_LOCATION_INFO rgSystemStoreLocationInfo[] = {
// Not Defined 0
NOT_IN_REGISTRY_SYSTEM_STORE_LOCATION_FLAG,
0,
0,
// CERT_SYSTEM_STORE_CURRENT_USER_ID 1
0,
COMMON_SYSTEM_FLAGS | USER_DS_SYSTEM_FLAG,
DEFAULT_PHYSICAL_FLAG | GROUP_POLICY_PHYSICAL_FLAG |
LOCAL_MACHINE_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_LOCAL_MACHINE_ID 2
LM_SYSTEM_STORE_LOCATION_FLAG | REMOTABLE_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG | GROUP_POLICY_PHYSICAL_FLAG |
ENTERPRISE_PHYSICAL_FLAG,
// Not Defined 3
NOT_IN_REGISTRY_SYSTEM_STORE_LOCATION_FLAG,
0,
0,
// CERT_SYSTEM_STORE_CURRENT_SERVICE_ID 4
LM_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG | LOCAL_MACHINE_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_SERVICES_ID 5
LM_SYSTEM_STORE_LOCATION_FLAG | REMOTABLE_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG | LOCAL_MACHINE_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_USERS_ID 6
REMOTABLE_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG | LOCAL_MACHINE_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID 7
//SERIALIZED_SYSTEM_STORE_LOCATION_FLAG,
0,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID 8
//SERIALIZED_SYSTEM_STORE_LOCATION_FLAG |
LM_SYSTEM_STORE_LOCATION_FLAG | REMOTABLE_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG,
// CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID 9
LM_SYSTEM_STORE_LOCATION_FLAG | REMOTABLE_SYSTEM_STORE_LOCATION_FLAG,
COMMON_SYSTEM_FLAGS,
DEFAULT_PHYSICAL_FLAG
};
#define NUM_SYSTEM_STORE_LOCATION (sizeof(rgSystemStoreLocationInfo) / \
sizeof(rgSystemStoreLocationInfo[0]))
#define CURRENT_USER_ROOT_PHYSICAL_FLAGS ( \
DEFAULT_PHYSICAL_FLAG | \
LOCAL_MACHINE_PHYSICAL_FLAG \
)
#define LOCAL_MACHINE_ROOT_PHYSICAL_FLAGS ( \
DEFAULT_PHYSICAL_FLAG | \
AUTH_ROOT_PHYSICAL_FLAG | \
GROUP_POLICY_PHYSICAL_FLAG | \
ENTERPRISE_PHYSICAL_FLAG \
)
#define USERS_ROOT_PHYSICAL_FLAGS ( \
LOCAL_MACHINE_PHYSICAL_FLAG \
)
#define MY_PHYSICAL_FLAGS ( \
DEFAULT_PHYSICAL_FLAG \
)
#define USER_DS_PHYSICAL_FLAGS ( \
DS_USER_CERT_PHYSICAL_FLAG \
)
#define CURRENT_USER_TRUST_PUB_PHYSICAL_FLAGS ( \
DEFAULT_PHYSICAL_FLAG | \
LOCAL_MACHINE_PHYSICAL_FLAG | \
GROUP_POLICY_PHYSICAL_FLAG \
)
#define LOCAL_MACHINE_TRUST_PUB_PHYSICAL_FLAGS ( \
DEFAULT_PHYSICAL_FLAG | \
GROUP_POLICY_PHYSICAL_FLAG | \
ENTERPRISE_PHYSICAL_FLAG \
)
#define sz_CRYPTNET_DLL "cryptnet.dll"
#define sz_GetUserDsStoreUrl "I_CryptNetGetUserDsStoreUrl"
typedef BOOL (WINAPI *PFN_GET_USER_DS_STORE_URL)(
IN LPWSTR pwszUserAttribute,
OUT LPWSTR* ppwszUrl
);
#define wsz_USER_CERTIFICATE_ATTR L"userCertificate"
#define PHYSICAL_NAME_INDEX 0
#define SYSTEM_NAME_INDEX 1
#define SERVICE_NAME_INDEX 2
#define USER_NAME_INDEX 2
#define COMPUTER_NAME_INDEX 3
#define SYSTEM_NAME_PATH_COUNT 4
#define DEFAULT_USER_NAME L".Default"
typedef struct _SYSTEM_NAME_INFO {
LPWSTR rgpwszName[SYSTEM_NAME_PATH_COUNT];
// non-NULL for relocated store. Note hKeyBase isn't opened and
// doesn't need to be closed
HKEY hKeyBase;
} SYSTEM_NAME_INFO, *PSYSTEM_NAME_INFO;
typedef struct _REG_STORE REG_STORE, *PREG_STORE;
typedef struct _ILS_RESYNC_ENTRY {
HANDLE hOrigEvent;
// hDupEvent is NULL for CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG
HANDLE hDupEvent;
PREG_STORE pRegStore;
} ILS_RESYNC_ENTRY, *PILS_RESYNC_ENTRY;
#define REG_CHANGE_INFO_TYPE 1
#define CU_GPT_CHANGE_INFO_TYPE 2
#define LM_GPT_CHANGE_INFO_TYPE 3
typedef struct _REGISTRY_STORE_CHANGE_INFO {
// REG_CHANGE_INFO_TYPE
DWORD dwType;
HANDLE hChange;
HANDLE hRegWaitFor;
DWORD cNotifyEntry;
PILS_RESYNC_ENTRY rgNotifyEntry;
} REGISTRY_STORE_CHANGE_INFO, *PREGISTRY_STORE_CHANGE_INFO;
typedef struct _GPT_STORE_CHANGE_INFO {
// CU_GPT_CHANGE_INFO_TYPE or LM_GPT_CHANGE_INFO_TYPE
DWORD dwType;
HKEY hKeyBase; // not duplicated
PREG_STORE pRegStore; // NULL for LM_GPT_CHANGE_INFO_TYPE
HKEY hPoliciesKey;
HANDLE hPoliciesEvent;
HANDLE hRegWaitFor;
HANDLE hGPNotificationEvent;
DWORD cNotifyEntry;
PILS_RESYNC_ENTRY rgNotifyEntry;
} GPT_STORE_CHANGE_INFO, *PGPT_STORE_CHANGE_INFO;
//+-------------------------------------------------------------------------
// Registry Store Provider handle information
//
// hMyNotifyChange is our internal NotifyChange event handle.
//--------------------------------------------------------------------------
struct _REG_STORE {
HCERTSTORE hCertStore; // not duplicated
CRITICAL_SECTION CriticalSection;
HANDLE hMyNotifyChange;
BOOL fResync; // when set, ignore callback deletes
HKEY hKey;
DWORD dwFlags;
// Following field is applicable to the CurrentUser "Root" store
BOOL fProtected;
// Following field is applicable when
// CERT_REGISTRY_STORE_SERIALIZED_FLAG is set in dwFlags
BOOL fTouched; // set for write, delete or set property
union {
// Following field is applicable when
// CERT_REGISTRY_STORE_CLIENT_GPT_FLAG is set in dwFlags
CERT_REGISTRY_STORE_CLIENT_GPT_PARA GptPara;
// Following field is applicable when
// CERT_REGISTRY_STORE_ROAMING_FLAG is set in dwFlags
LPWSTR pwszStoreDirectory;
};
union {
// Following field is applicable for change notify of registry or
// roaming file store
PREGISTRY_STORE_CHANGE_INFO pRegistryStoreChangeInfo;
// Following field is applicable for change notify of CU GPT store
PGPT_STORE_CHANGE_INFO pGptStoreChangeInfo;
};
};
typedef struct _ENUM_SYSTEM_STORE_LOCATION_INFO {
DWORD dwFlags;
LPCWSTR pwszLocation;
} ENUM_SYSTEM_STORE_LOCATION_INFO, *PENUM_SYSTEM_STORE_LOCATION_INFO;
// Predefined crypt32.dll locations. MUST NOT BE REGISTERED!!!
static const ENUM_SYSTEM_STORE_LOCATION_INFO rgEnumSystemStoreLocationInfo[] = {
CERT_SYSTEM_STORE_CURRENT_USER, L"CurrentUser",
CERT_SYSTEM_STORE_LOCAL_MACHINE, L"LocalMachine",
CERT_SYSTEM_STORE_CURRENT_SERVICE, L"CurrentService",
CERT_SYSTEM_STORE_SERVICES, L"Services",
CERT_SYSTEM_STORE_USERS, L"Users",
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY, L"CurrentUserGroupPolicy",
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, L"LocalMachineGroupPolicy",
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, L"LocalMachineEnterprise"
};
#define ENUM_SYSTEM_STORE_LOCATION_CNT \
(sizeof(rgEnumSystemStoreLocationInfo) / \
sizeof(rgEnumSystemStoreLocationInfo[0]))
#define OPEN_SYSTEM_STORE_PROV_FUNC_SET 0
#define REGISTER_SYSTEM_STORE_FUNC_SET 1
#define UNREGISTER_SYSTEM_STORE_FUNC_SET 2
#define ENUM_SYSTEM_STORE_FUNC_SET 3
#define REGISTER_PHYSICAL_STORE_FUNC_SET 4
#define UNREGISTER_PHYSICAL_STORE_FUNC_SET 5
#define ENUM_PHYSICAL_STORE_FUNC_SET 6
#define FUNC_SET_COUNT 7
static HCRYPTOIDFUNCSET rghFuncSet[FUNC_SET_COUNT];
static const LPCSTR rgpszFuncName[FUNC_SET_COUNT] = {
CRYPT_OID_OPEN_SYSTEM_STORE_PROV_FUNC,
CRYPT_OID_REGISTER_SYSTEM_STORE_FUNC,
CRYPT_OID_UNREGISTER_SYSTEM_STORE_FUNC,
CRYPT_OID_ENUM_SYSTEM_STORE_FUNC,
CRYPT_OID_REGISTER_PHYSICAL_STORE_FUNC,
CRYPT_OID_UNREGISTER_PHYSICAL_STORE_FUNC,
CRYPT_OID_ENUM_PHYSICAL_STORE_FUNC
};
typedef BOOL (WINAPI *PFN_REGISTER_SYSTEM_STORE)(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN PCERT_SYSTEM_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved
);
typedef BOOL (WINAPI *PFN_UNREGISTER_SYSTEM_STORE)(
IN const void *pvSystemStore,
IN DWORD dwFlags
);
typedef BOOL (WINAPI *PFN_ENUM_SYSTEM_STORE)(
IN DWORD dwFlags,
IN OPTIONAL void *pvSystemStoreLocationPara,
IN void *pvArg,
IN PFN_CERT_ENUM_SYSTEM_STORE pfnEnum
);
typedef BOOL (WINAPI *PFN_REGISTER_PHYSICAL_STORE)(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN LPCWSTR pwszStoreName,
IN PCERT_PHYSICAL_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved
);
typedef BOOL (WINAPI *PFN_UNREGISTER_PHYSICAL_STORE)(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN LPCWSTR pwszStoreName
);
typedef BOOL (WINAPI *PFN_ENUM_PHYSICAL_STORE)(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum
);
//+-------------------------------------------------------------------------
// Registry Store Provider Functions.
//--------------------------------------------------------------------------
STATIC void WINAPI RegStoreProvClose(
IN HCERTSTOREPROV hStoreProv,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvReadCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pStoreCertContext,
IN DWORD dwFlags,
OUT PCCERT_CONTEXT *ppProvCertContext
);
STATIC BOOL WINAPI RegStoreProvWriteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvDeleteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvSetCertProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
);
STATIC BOOL WINAPI RegStoreProvReadCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pStoreCrlContext,
IN DWORD dwFlags,
OUT PCCRL_CONTEXT *ppProvCrlContext
);
STATIC BOOL WINAPI RegStoreProvWriteCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvDeleteCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvSetCrlProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
);
STATIC BOOL WINAPI RegStoreProvReadCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pStoreCtlContext,
IN DWORD dwFlags,
OUT PCCTL_CONTEXT *ppProvCtlContext
);
STATIC BOOL WINAPI RegStoreProvWriteCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvDeleteCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RegStoreProvSetCtlProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
);
STATIC BOOL WINAPI RegStoreProvControl(
IN HCERTSTOREPROV hStoreProv,
IN DWORD dwFlags,
IN DWORD dwCtrlType,
IN void const *pvCtrlPara
);
static void * const rgpvRegStoreProvFunc[] = {
// CERT_STORE_PROV_CLOSE_FUNC 0
RegStoreProvClose,
// CERT_STORE_PROV_READ_CERT_FUNC 1
RegStoreProvReadCert,
// CERT_STORE_PROV_WRITE_CERT_FUNC 2
RegStoreProvWriteCert,
// CERT_STORE_PROV_DELETE_CERT_FUNC 3
RegStoreProvDeleteCert,
// CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC 4
RegStoreProvSetCertProperty,
// CERT_STORE_PROV_READ_CRL_FUNC 5
RegStoreProvReadCrl,
// CERT_STORE_PROV_WRITE_CRL_FUNC 6
RegStoreProvWriteCrl,
// CERT_STORE_PROV_DELETE_CRL_FUNC 7
RegStoreProvDeleteCrl,
// CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC 8
RegStoreProvSetCrlProperty,
// CERT_STORE_PROV_READ_CTL_FUNC 9
RegStoreProvReadCtl,
// CERT_STORE_PROV_WRITE_CTL_FUNC 10
RegStoreProvWriteCtl,
// CERT_STORE_PROV_DELETE_CTL_FUNC 11
RegStoreProvDeleteCtl,
// CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC 12
RegStoreProvSetCtlProperty,
// CERT_STORE_PROV_CONTROL_FUNC 13
RegStoreProvControl
};
#define REG_STORE_PROV_FUNC_COUNT (sizeof(rgpvRegStoreProvFunc) / \
sizeof(rgpvRegStoreProvFunc[0]))
STATIC BOOL WINAPI RootStoreProvWriteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
);
STATIC BOOL WINAPI RootStoreProvDeleteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
);
static void * const rgpvRootStoreProvFunc[] = {
// CERT_STORE_PROV_CLOSE_FUNC 0
RegStoreProvClose,
// CERT_STORE_PROV_READ_CERT_FUNC 1
RegStoreProvReadCert,
// CERT_STORE_PROV_WRITE_CERT_FUNC 2
RootStoreProvWriteCert,
// CERT_STORE_PROV_DELETE_CERT_FUNC 3
RootStoreProvDeleteCert,
// CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC 4
RegStoreProvSetCertProperty,
// CERT_STORE_PROV_READ_CRL_FUNC 5
RegStoreProvReadCrl,
// CERT_STORE_PROV_WRITE_CRL_FUNC 6
RegStoreProvWriteCrl,
// CERT_STORE_PROV_DELETE_CRL_FUNC 7
RegStoreProvDeleteCrl,
// CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC 8
RegStoreProvSetCrlProperty,
// CERT_STORE_PROV_READ_CTL_FUNC 9
RegStoreProvReadCtl,
// CERT_STORE_PROV_WRITE_CTL_FUNC 10
RegStoreProvWriteCtl,
// CERT_STORE_PROV_DELETE_CTL_FUNC 11
RegStoreProvDeleteCtl,
// CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC 12
RegStoreProvSetCtlProperty,
// CERT_STORE_PROV_CONTROL_FUNC 13
RegStoreProvControl
};
#define ROOT_STORE_PROV_FUNC_COUNT (sizeof(rgpvRootStoreProvFunc) / \
sizeof(rgpvRootStoreProvFunc[0]))
//+-------------------------------------------------------------------------
// Add the serialized store to the store.
//
// from newstor.cpp
//--------------------------------------------------------------------------
extern BOOL WINAPI I_CertAddSerializedStore(
IN HCERTSTORE hCertStore,
IN BYTE *pbStore,
IN DWORD cbStore
);
LPWSTR ILS_AllocAndCopyString(
IN LPCWSTR pwszSrc,
IN LONG cchSrc
)
{
LPWSTR pwszDst;
if (cchSrc < 0)
cchSrc = wcslen(pwszSrc);
if (NULL == (pwszDst = (LPWSTR) PkiNonzeroAlloc(
(cchSrc + 1) * sizeof(WCHAR))))
return NULL;
if (0 < cchSrc)
memcpy((BYTE *) pwszDst, (BYTE *) pwszSrc, cchSrc * sizeof(WCHAR));
pwszDst[cchSrc] = L'\0';
return pwszDst;
}
extern
BOOL
WINAPI
I_ProtectedRootDllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved);
//+=========================================================================
// Register WaitFor Forward Function References
//==========================================================================
STATIC void RegWaitForProcessAttach();
STATIC void RegWaitForProcessDetach();
//+=========================================================================
// Client "GPT" Store Forward Function References
//==========================================================================
STATIC void GptStoreProcessAttach();
STATIC void GptStoreProcessDetach();
STATIC BOOL OpenAllFromGptRegistry(
IN PREG_STORE pRegStore,
IN HCERTSTORE hCertStore
);
STATIC BOOL CommitAllToGptRegistry(
IN PREG_STORE pRegStore,
IN DWORD dwFlags
);
STATIC void GptStoreSignalAndFreeRegStoreResyncEntries(
IN PREG_STORE pRegStore
);
STATIC void FreeGptStoreChangeInfo(
IN OUT PGPT_STORE_CHANGE_INFO *ppInfo
);
STATIC BOOL RegGptStoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
);
static inline BOOL IsClientGptStore(
IN PSYSTEM_NAME_INFO pInfo,
IN DWORD dwFlags
)
{
DWORD dwStoreLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
if (!(CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY == dwStoreLocation ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY == dwStoreLocation))
return FALSE;
if (dwFlags & (CERT_SYSTEM_STORE_RELOCATE_FLAG | CERT_STORE_DELETE_FLAG))
return FALSE;
return TRUE;
}
//+=========================================================================
// Win95 Notify Store Forward Function References
//==========================================================================
// Following is created at ProcessAttach for Win95 clients
static HANDLE hWin95NotifyEvent = NULL;
STATIC void Win95StoreProcessAttach();
STATIC void Win95StoreProcessDetach();
STATIC void Win95StoreSignalAndFreeRegStoreResyncEntries(
IN PREG_STORE pRegStore
);
STATIC BOOL RegWin95StoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
);
//+=========================================================================
// Roaming Store Forward Function References
//==========================================================================
STATIC void RoamingStoreProcessAttach();
STATIC void RoamingStoreProcessDetach();
LPWSTR
ILS_GetRoamingStoreDirectory(
IN LPCWSTR pwszStoreName
);
BOOL
ILS_WriteElementToFile(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_CREATE_NEW_FLAG or
// CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
);
BOOL
ILS_ReadElementFromFile(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
);
BOOL
ILS_DeleteElementFromDirectory(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags
);
typedef BOOL (*PFN_ILS_OPEN_ELEMENT)(
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN const BYTE *pbElement,
IN DWORD cbElement,
IN void *pvArg
);
BOOL
ILS_OpenAllElementsFromDirectory(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_ILS_OPEN_ELEMENT pfnOpenElement
);
//+=========================================================================
// Registry or Roaming Store Change Notify Functions
//==========================================================================
STATIC BOOL RegRegistryStoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
);
STATIC void FreeRegistryStoreChange(
IN PREG_STORE pRegStore
);
//+-------------------------------------------------------------------------
// Dll initialization
//--------------------------------------------------------------------------
BOOL
WINAPI
I_RegStoreDllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fRet;
DWORD i;
if (!I_ProtectedRootDllMain(hInst, ulReason, lpReserved))
return FALSE;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
for (i = 0; i < FUNC_SET_COUNT; i++) {
if (NULL == (rghFuncSet[i] = CryptInitOIDFunctionSet(
rgpszFuncName[i], 0)))
goto CryptInitOIDFunctionSetError;
}
if (!Pki_InitializeCriticalSection(&ILS_CriticalSection))
goto InitCritSectionError;
if (NULL == (hTlsEnumPhysicalStoreDepth = I_CryptAllocTls())) {
DeleteCriticalSection(&ILS_CriticalSection);
goto CryptAllocTlsError;
}
RegWaitForProcessAttach();
GptStoreProcessAttach();
Win95StoreProcessAttach();
RoamingStoreProcessAttach();
break;
case DLL_PROCESS_DETACH:
RoamingStoreProcessDetach();
Win95StoreProcessDetach();
GptStoreProcessDetach();
RegWaitForProcessDetach();
DeleteCriticalSection(&ILS_CriticalSection);
I_CryptFreeTls(hTlsEnumPhysicalStoreDepth, PkiFree);
break;
case DLL_THREAD_DETACH:
PkiFree(I_CryptDetachTls(hTlsEnumPhysicalStoreDepth));
break;
default:
break;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
I_ProtectedRootDllMain(hInst, DLL_PROCESS_DETACH, NULL);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(InitCritSectionError)
TRACE_ERROR(CryptInitOIDFunctionSetError)
TRACE_ERROR(CryptAllocTlsError)
}
//+-------------------------------------------------------------------------
// Converts the bytes into UNICODE ASCII HEX
//
// Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
//--------------------------------------------------------------------------
void ILS_BytesToWStr(DWORD cb, void* pv, LPWSTR wsz)
{
BYTE* pb = (BYTE*) pv;
for (DWORD i = 0; i<cb; i++) {
int b;
b = (*pb & 0xF0) >> 4;
*wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
b = *pb & 0x0F;
*wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
pb++;
}
*wsz++ = 0;
}
//+-------------------------------------------------------------------------
// Converts the UNICODE ASCII HEX to an array of bytes
//--------------------------------------------------------------------------
STATIC void WStrToBytes(
IN const WCHAR wsz[MAX_HASH_NAME_LEN],
OUT BYTE rgb[MAX_HASH_LEN],
OUT DWORD *pcb
)
{
BOOL fUpperNibble = TRUE;
DWORD cb = 0;
LPCWSTR pwsz = wsz;
WCHAR wch;
while (cb < MAX_HASH_LEN && (wch = *pwsz++)) {
BYTE b;
// only convert ascii hex characters 0..9, a..f, A..F
// silently ignore all others
if (wch >= L'0' && wch <= L'9')
b = (BYTE) (wch - L'0');
else if (wch >= L'a' && wch <= L'f')
b = (BYTE) (10 + wch - L'a');
else if (wch >= L'A' && wch <= L'F')
b = (BYTE) (10 + wch - L'A');
else
continue;
if (fUpperNibble) {
rgb[cb] = (BYTE)( b << 4);
fUpperNibble = FALSE;
} else {
rgb[cb] = (BYTE)( rgb[cb] | b);
cb++;
fUpperNibble = TRUE;
}
}
*pcb = cb;
}
//+-------------------------------------------------------------------------
// Lock and unlock registry functions
//--------------------------------------------------------------------------
static inline void LockRegStore(IN PREG_STORE pRegStore)
{
EnterCriticalSection(&pRegStore->CriticalSection);
}
static inline void UnlockRegStore(IN PREG_STORE pRegStore)
{
LeaveCriticalSection(&pRegStore->CriticalSection);
}
//+-------------------------------------------------------------------------
// Checks if current thread is doing a Resync. Other threads block until
// the resync completes
//--------------------------------------------------------------------------
STATIC BOOL IsInResync(IN PREG_STORE pRegStore)
{
BOOL fResync;
LockRegStore(pRegStore);
fResync = pRegStore->fResync;
UnlockRegStore(pRegStore);
return fResync;
}
//+=========================================================================
// Low level context support functions
//==========================================================================
//+-------------------------------------------------------------------------
// Get the certificate's registry value name by formatting its SHA1 hash as
// UNICODE hex.
//--------------------------------------------------------------------------
STATIC BOOL GetCertRegValueName(
IN PCCERT_CONTEXT pCertContext,
OUT WCHAR wszRegName[MAX_CERT_REG_VALUE_NAME_LEN]
)
{
BYTE rgbHash[MAX_HASH_LEN];
DWORD cbHash = MAX_HASH_LEN;
// get the thumbprint
if(!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbHash))
return FALSE;
// convert to a string
ILS_BytesToWStr(cbHash, rgbHash, wszRegName);
return TRUE;
}
//+-------------------------------------------------------------------------
// Get the CRL's registry value name by formatting its SHA1 hash as
// UNICODE hex.
//--------------------------------------------------------------------------
STATIC BOOL GetCrlRegValueName(
IN PCCRL_CONTEXT pCrlContext,
OUT WCHAR wszRegName[MAX_CERT_REG_VALUE_NAME_LEN]
)
{
BYTE rgbHash[MAX_HASH_LEN];
DWORD cbHash = MAX_HASH_LEN;
// get the thumbprint
if(!CertGetCRLContextProperty(
pCrlContext,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbHash))
return FALSE;
// convert to a string
ILS_BytesToWStr(cbHash, rgbHash, wszRegName);
return TRUE;
}
//+-------------------------------------------------------------------------
// Get the CTL's registry value name by formatting its SHA1 hash as
// UNICODE hex.
//--------------------------------------------------------------------------
STATIC BOOL GetCtlRegValueName(
IN PCCTL_CONTEXT pCtlContext,
OUT WCHAR wszRegName[MAX_CERT_REG_VALUE_NAME_LEN]
)
{
BYTE rgbHash[MAX_HASH_LEN];
DWORD cbHash = MAX_HASH_LEN;
// get the thumbprint
if(!CertGetCTLContextProperty(
pCtlContext,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbHash))
return FALSE;
// convert to a string
ILS_BytesToWStr(cbHash, rgbHash, wszRegName);
return TRUE;
}
//+-------------------------------------------------------------------------
// Convert's the context's SHA1 hash to UNICODE hex. Returns TRUE if the
// same as the specified Uniocde reg name.
//--------------------------------------------------------------------------
STATIC BOOL IsValidRegValueNameForContext(
IN DWORD dwContextType,
IN const void *pvContext,
IN const WCHAR wszRegName[MAX_CERT_REG_VALUE_NAME_LEN]
)
{
BOOL fResult;
WCHAR wszContextHash[MAX_CERT_REG_VALUE_NAME_LEN];
switch (dwContextType) {
case CERT_STORE_CERTIFICATE_CONTEXT:
fResult = GetCertRegValueName(
(PCCERT_CONTEXT) pvContext, wszContextHash);
break;
case CERT_STORE_CRL_CONTEXT:
fResult = GetCrlRegValueName(
(PCCRL_CONTEXT) pvContext, wszContextHash);
break;
case CERT_STORE_CTL_CONTEXT:
fResult = GetCtlRegValueName(
(PCCTL_CONTEXT) pvContext, wszContextHash);
break;
default:
goto InvalidContext;
}
if (!fResult)
goto GetContextHashError;
if (0 != _wcsicmp(wszRegName, wszContextHash))
goto InvalidRegValueNameForContext;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidContext, E_UNEXPECTED)
TRACE_ERROR(GetContextHashError)
SET_ERROR(InvalidRegValueNameForContext, ERROR_BAD_PATHNAME)
}
//+-------------------------------------------------------------------------
// Deletes the context from the store.
//--------------------------------------------------------------------------
STATIC void DeleteContextFromStore(
IN DWORD dwContextType,
IN const void *pvContext
)
{
switch (dwContextType) {
case CERT_STORE_CERTIFICATE_CONTEXT:
CertDeleteCertificateFromStore((PCCERT_CONTEXT) pvContext);
break;
case CERT_STORE_CRL_CONTEXT:
CertDeleteCRLFromStore((PCCRL_CONTEXT) pvContext);
break;
case CERT_STORE_CTL_CONTEXT:
CertDeleteCTLFromStore((PCCTL_CONTEXT) pvContext);
break;
default:
break;
}
}
//+-------------------------------------------------------------------------
// Frees the context.
//--------------------------------------------------------------------------
STATIC void FreeContext(
IN DWORD dwContextType,
IN const void *pvContext
)
{
switch (dwContextType) {
case CERT_STORE_CERTIFICATE_CONTEXT:
CertFreeCertificateContext((PCCERT_CONTEXT) pvContext);
break;
case CERT_STORE_CRL_CONTEXT:
CertFreeCRLContext((PCCRL_CONTEXT) pvContext);
break;
case CERT_STORE_CTL_CONTEXT:
CertFreeCTLContext((PCCTL_CONTEXT) pvContext);
break;
default:
break;
}
}
//+=========================================================================
// Low level registry support functions
//==========================================================================
//+-------------------------------------------------------------------------
// For CERT_STORE_BACKUP_RESTORE_FLAG, enable backup and restore
// privileges.
//--------------------------------------------------------------------------
void ILS_EnableBackupRestorePrivileges()
{
IPR_EnableSecurityPrivilege(SE_BACKUP_NAME);
IPR_EnableSecurityPrivilege(SE_RESTORE_NAME);
}
// LastError can get globbered when doing remote registry access
void
ILS_CloseRegistryKey(
IN HKEY hKey
)
{
if (hKey) {
DWORD dwErr = GetLastError();
LONG RegCloseKeyStatus;
RegCloseKeyStatus = RegCloseKey(hKey);
assert(ERROR_SUCCESS == RegCloseKeyStatus);
SetLastError(dwErr);
}
}
// Ensure LastError is preserved
void
ILS_CloseHandle(
IN HANDLE h
)
{
if (h) {
DWORD dwErr = GetLastError();
CloseHandle(h);
SetLastError(dwErr);
}
}
STATIC BOOL WriteDWORDValueToRegistry(
IN HKEY hKey,
IN LPCWSTR pwszValueName,
IN DWORD dwValue
)
{
LONG err;
if (ERROR_SUCCESS == (err = RegSetValueExU(
hKey,
pwszValueName,
0, // dwReserved
REG_DWORD,
(BYTE *) &dwValue,
sizeof(DWORD))))
return TRUE;
else {
SetLastError((DWORD) err);
return FALSE;
}
}
BOOL
ILS_ReadDWORDValueFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszValueName,
IN DWORD *pdwValue
)
{
BOOL fResult;
LONG err;
DWORD dwType;
DWORD dwValue;
DWORD cbValue = sizeof(DWORD);
if (ERROR_SUCCESS != (err = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // pdwReserved
&dwType,
(BYTE *) &dwValue,
&cbValue))) goto RegQueryValueError;
if (dwType != REG_DWORD || cbValue != sizeof(DWORD))
goto InvalidRegistryValue;
fResult = TRUE;
CommonReturn:
*pdwValue = dwValue;
return fResult;
ErrorReturn:
dwValue = 0;
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
}
// Ensure a binary value that may contain a LPCWSTR is NULL terminated.
// Always adds a NULL terminator not included in the returned cbValue.
//
// May return an allocated pbValue with a cbValue = 0.
BOOL
ILS_ReadBINARYValueFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszValueName,
OUT BYTE **ppbValue,
OUT DWORD *pcbValue
)
{
BOOL fResult;
LONG err;
DWORD dwType;
BYTE *pbValue = NULL;
DWORD cbValue = 0;
DWORD cbAllocValue;
err = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // pdwReserved
&dwType,
NULL, // lpData
&cbValue);
// For Win95 Remote Registry Access:: returns ERROR_MORE_DATA
if (!(ERROR_SUCCESS == err || ERROR_MORE_DATA == err))
goto RegQueryValueError;
if (dwType != REG_BINARY)
goto InvalidRegistryValue;
cbAllocValue = cbValue + 3;
if (NULL == (pbValue = (BYTE *) PkiNonzeroAlloc(cbAllocValue)))
goto OutOfMemory;
if (0 < cbValue) {
if (ERROR_SUCCESS != (err = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // pdwReserved
&dwType,
pbValue,
&cbValue))) goto RegQueryValueError;
}
assert(cbAllocValue >= cbValue + 3);
// Ensure an LPWSTR is null terminated
memset(pbValue + cbValue, 0, 3);
fResult = TRUE;
CommonReturn:
*ppbValue = pbValue;
*pcbValue = cbValue;
return fResult;
ErrorReturn:
fResult = FALSE;
PkiFree(pbValue);
pbValue = NULL;
cbValue = 0;
goto CommonReturn;
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
TRACE_ERROR(OutOfMemory)
}
//+-------------------------------------------------------------------------
// Get and allocate the REG_SZ value
//--------------------------------------------------------------------------
LPWSTR ILS_ReadSZValueFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszValueName
)
{
LONG err;
DWORD dwType;
LPWSTR pwszValue = NULL;
DWORD cbValue = 0;
err = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // pdwReserved
&dwType,
NULL, // lpData
&cbValue);
// For Win95 Remote Registry Access:: returns ERROR_MORE_DATA
if (!(ERROR_SUCCESS == err || ERROR_MORE_DATA == err))
goto RegQueryValueError;
if (dwType != REG_SZ || cbValue < sizeof(WCHAR))
goto InvalidRegistryValue;
// Ensure NULL terminated
if (NULL == (pwszValue = (LPWSTR) PkiNonzeroAlloc(cbValue + sizeof(WCHAR))))
goto OutOfMemory;
if (ERROR_SUCCESS != (err = RegQueryValueExU(
hKey,
pwszValueName,
NULL, // pdwReserved
&dwType,
(BYTE *) pwszValue,
&cbValue))) goto RegQueryValueError;
pwszValue[cbValue / sizeof(WCHAR)] = L'\0';
CommonReturn:
return pwszValue;
ErrorReturn:
PkiFree(pwszValue);
pwszValue = NULL;
goto CommonReturn;
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
TRACE_ERROR(OutOfMemory)
}
LPSTR ILS_ReadSZValueFromRegistry(
IN HKEY hKey,
IN LPCSTR pszValueName
)
{
LONG err;
DWORD dwType;
LPSTR pszValue = NULL;
DWORD cbValue = 0;
err = RegQueryValueExA(
hKey,
pszValueName,
NULL, // pdwReserved
&dwType,
NULL, // lpData
&cbValue);
// For Win95 Remote Registry Access:: returns ERROR_MORE_DATA
if (!(ERROR_SUCCESS == err || ERROR_MORE_DATA == err))
goto RegQueryValueError;
if (dwType != REG_SZ || cbValue == 0)
goto InvalidRegistryValue;
// Ensure NULL terminated
if (NULL == (pszValue = (LPSTR) PkiNonzeroAlloc(cbValue + sizeof(CHAR))))
goto OutOfMemory;
if (ERROR_SUCCESS != (err = RegQueryValueExA(
hKey,
pszValueName,
NULL, // pdwReserved
&dwType,
(BYTE *) pszValue,
&cbValue))) goto RegQueryValueError;
pszValue[cbValue / sizeof(CHAR)] = '\0';
CommonReturn:
return pszValue;
ErrorReturn:
PkiFree(pszValue);
pszValue = NULL;
goto CommonReturn;
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
TRACE_ERROR(OutOfMemory)
}
STATIC BOOL GetSubKeyInfo(
IN HKEY hKey,
OUT OPTIONAL DWORD *pcSubKeys,
OUT OPTIONAL DWORD *pcchMaxSubKey = NULL
)
{
BOOL fResult;
LONG err;
// I have seen a couple of stress failures where the following returns
// ERROR_SUCCESS without updating *pcSubKeys
if (pcSubKeys)
*pcSubKeys = 0;
if (pcchMaxSubKey)
*pcchMaxSubKey = 0;
if (ERROR_SUCCESS != (err = RegQueryInfoKeyU(
hKey,
NULL, // lpszClass
NULL, // lpcchClass
NULL, // lpdwReserved
pcSubKeys,
pcchMaxSubKey,
NULL, // lpcchMaxClass
NULL, // lpcValues
NULL, // lpcchMaxValuesName
NULL, // lpcbMaxValueData
NULL, // lpcbSecurityDescriptor
NULL // lpftLastWriteTime
))) goto RegQueryInfoKeyError;
fResult = TRUE;
CommonReturn:
// For Win95 Remote Registry Access:: returns half of the cch
if (pcchMaxSubKey && *pcchMaxSubKey)
*pcchMaxSubKey = (*pcchMaxSubKey + 1) * 2 + 2;
return fResult;
ErrorReturn:
fResult = FALSE;
if (pcSubKeys)
*pcSubKeys = 0;
if (pcchMaxSubKey)
*pcchMaxSubKey = 0;
goto CommonReturn;
SET_ERROR_VAR(RegQueryInfoKeyError, err)
}
//+-------------------------------------------------------------------------
// Open the SubKey with support for backup/restore
//--------------------------------------------------------------------------
STATIC LONG WINAPI OpenHKCUKeyExU (
HKEY hKey,
IN LPCWSTR pwszSubKeyName,
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
REGSAM samDesired,
PHKEY phkResult
)
{
LONG err;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) {
DWORD dwDisposition;
err = RegCreateHKCUKeyExU(
hKey,
pwszSubKeyName,
NULL,
NULL,
REG_OPTION_BACKUP_RESTORE,
samDesired,
NULL,
phkResult,
&dwDisposition
);
} else {
err = RegOpenHKCUKeyExU(
hKey,
pwszSubKeyName,
0, // dwReserved
samDesired,
phkResult
);
}
return err;
}
//+-------------------------------------------------------------------------
// Open the SubKey.
//
// dwFlags:
// CERT_STORE_READONLY_FLAG
// CERT_STORE_OPEN_EXISTING_FLAG
// CERT_STORE_CREATE_NEW_FLAG
// CERT_STORE_BACKUP_RESTORE_FLAG
//--------------------------------------------------------------------------
STATIC HKEY OpenSubKey(
IN HKEY hKey,
IN LPCWSTR pwszSubKeyName,
IN DWORD dwFlags
)
{
LONG err;
HKEY hSubKey;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) {
DWORD dwDisposition;
REGSAM samDesired;
if (dwFlags & CERT_STORE_READONLY_FLAG)
samDesired = KEY_READ;
else
samDesired = KEY_ALL_ACCESS;
if (NULL == pwszSubKeyName)
pwszSubKeyName = L"";
if (ERROR_SUCCESS != (err = RegCreateHKCUKeyExU(
hKey,
pwszSubKeyName,
0, // dwReserved
NULL, // lpClass
REG_OPTION_BACKUP_RESTORE,
samDesired,
NULL, // lpSecurityAttributes
&hSubKey,
&dwDisposition))) {
if (dwFlags &
(CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG))
err = ERROR_FILE_NOT_FOUND;
goto RegCreateBackupRestoreKeyError;
}
if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) {
if (REG_CREATED_NEW_KEY != dwDisposition) {
RegCloseKey(hSubKey);
goto ExistingSubKey;
}
}
goto CommonReturn;
}
if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) {
// First check if SubKey already exists
if (hSubKey = OpenSubKey(
hKey,
pwszSubKeyName,
(dwFlags & ~CERT_STORE_CREATE_NEW_FLAG) |
CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_READONLY_FLAG
)) {
RegCloseKey(hSubKey);
goto ExistingSubKey;
} else if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenNewSubKeyError;
}
if (dwFlags & (CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG)) {
REGSAM samDesired;
if (dwFlags & CERT_STORE_READONLY_FLAG)
samDesired = KEY_READ;
else
samDesired = KEY_ALL_ACCESS;
if (ERROR_SUCCESS != (err = RegOpenHKCUKeyExU(
hKey,
pwszSubKeyName,
0, // dwReserved
samDesired,
&hSubKey)))
goto RegOpenKeyError;
} else {
DWORD dwDisposition;
if (ERROR_SUCCESS != (err = RegCreateHKCUKeyExU(
hKey,
pwszSubKeyName,
0, // dwReserved
NULL, // lpClass
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL, // lpSecurityAttributes
&hSubKey,
&dwDisposition)))
goto RegCreateKeyError;
}
CommonReturn:
return hSubKey;
ErrorReturn:
hSubKey = NULL;
goto CommonReturn;
SET_ERROR_VAR(RegCreateBackupRestoreKeyError, err)
SET_ERROR(ExistingSubKey, ERROR_FILE_EXISTS)
TRACE_ERROR(OpenNewSubKeyError)
SET_ERROR_VAR(RegOpenKeyError, err)
SET_ERROR_VAR(RegCreateKeyError, err)
}
STATIC BOOL RecursiveDeleteSubKey(
IN HKEY hKey,
IN LPCWSTR pwszSubKeyName,
IN DWORD dwFlags // CERT_STORE_BACKUP_RESTORE_FLAG may be set
)
{
BOOL fResult;
LONG err;
while (TRUE) {
HKEY hSubKey;
DWORD cSubKeys;
DWORD cchMaxSubKey;
BOOL fDidDelete;
if (ERROR_SUCCESS != OpenHKCUKeyExU(
hKey,
pwszSubKeyName,
dwFlags,
KEY_ALL_ACCESS,
&hSubKey))
break;
GetSubKeyInfo(
hSubKey,
&cSubKeys,
&cchMaxSubKey
);
fDidDelete = FALSE;
if (cSubKeys && cchMaxSubKey) {
LPWSTR pwszEnumSubKeyName;
cchMaxSubKey++;
if (pwszEnumSubKeyName = (LPWSTR) PkiNonzeroAlloc(
cchMaxSubKey * sizeof(WCHAR))) {
if (ERROR_SUCCESS == RegEnumKeyExU(
hSubKey,
0,
pwszEnumSubKeyName,
&cchMaxSubKey,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
))
fDidDelete = RecursiveDeleteSubKey(
hSubKey, pwszEnumSubKeyName, dwFlags);
PkiFree(pwszEnumSubKeyName);
}
}
RegCloseKey(hSubKey);
if (!fDidDelete)
break;
}
if (ERROR_SUCCESS != (err = RegDeleteKeyU(hKey, pwszSubKeyName)))
goto RegDeleteKeyError;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegDeleteKeyError, err)
}
//+=========================================================================
// Trusted Publisher Registry Functions
//==========================================================================
STATIC BOOL OpenKeyAndReadDWORDValueFromRegistry(
IN BOOL fMachine,
IN LPCWSTR pwszRegPath,
IN LPCWSTR pwszValueName,
OUT DWORD *pdwValue
)
{
BOOL fResult;
HKEY hKey = NULL;
LONG err;
if (ERROR_SUCCESS != (err = RegOpenHKCUKeyExU(
fMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
pwszRegPath,
0, // dwReserved
KEY_READ,
&hKey
)))
goto OpenKeyForDWORDValueError;
if (!ILS_ReadDWORDValueFromRegistry(
hKey,
pwszValueName,
pdwValue
)) goto ReadDWORDValueError;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hKey);
return fResult;
ErrorReturn:
*pdwValue = 0;
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(OpenKeyForDWORDValueError, err)
TRACE_ERROR(ReadDWORDValueError)
}
//+-------------------------------------------------------------------------
// On the Nth iteration these Safer Grade School programmers decided that the
// value should be the 'OR' of the 3 different locations: HKLM\GPO, HKCU\GPO,
// HKLM\Registry.
//--------------------------------------------------------------------------
BOOL
I_CryptReadTrustedPublisherDWORDValueFromRegistry(
IN LPCWSTR pwszValueName,
OUT DWORD *pdwValue
)
{
BOOL fResult = FALSE;
DWORD dwValue = 0;
DWORD dwRegValue = 0;
if (OpenKeyAndReadDWORDValueFromRegistry(
TRUE, // fMachine
CERT_TRUST_PUB_SAFER_GROUP_POLICY_REGPATH,
pwszValueName,
&dwRegValue
)) {
fResult = TRUE;
dwValue |= dwRegValue;
}
if (OpenKeyAndReadDWORDValueFromRegistry(
FALSE, // fMachine
CERT_TRUST_PUB_SAFER_GROUP_POLICY_REGPATH,
pwszValueName,
&dwRegValue
)) {
fResult = TRUE;
dwValue |= dwRegValue;
}
if (OpenKeyAndReadDWORDValueFromRegistry(
TRUE, // fMachine
CERT_TRUST_PUB_SAFER_LOCAL_MACHINE_REGPATH,
pwszValueName,
&dwRegValue
)) {
fResult = TRUE;
dwValue |= dwRegValue;
}
*pdwValue = dwValue;
return fResult;
}
//+=========================================================================
// Win95 Registry Functions
//
// Note, as of 10/17/97 the following is also done on NT to allow
// registry hive roaming from NT to Win95 systems.
//
// Certs, CRLs and CTLs are stored in SubKeys instead of as Key values.
//
// Note: Win95 has the following registry limitations:
// - Max single key value is 16K
// - Max total values per key is 64K
//
// For WIN95, write each cert, CRL, CTL to its own key when the
// above limitations are exceeded. If encoded blob exceeds 12K, partition
// and write to multiple SubKeys. Blobs are written to values named
// "Blob". Partitioned blobs, have "BlobCount" and "BlobLength" values and
// SubKeys named "Blob0", "Blob1", "Blob2" ... .
//
// The IE4.0 version of crypt32 wrote the blob to a "File" if the blob
// exceeded 12K. For backwards compatibility, continue to read "File" based
// blobs. On write enabled, non-remote opens, "File" blobs are moved to
// "Blob0", ... SubKeys and the file is deleted.
//
// If CERT_REGISTRY_STORE_SERIALIZED_FLAG is set when the registry store
// is opened, then, the entire store resides in a partitioned blob under the
// "Serialized" subkey.
//==========================================================================
#define KEY_BLOB_VALUE_NAME L"Blob"
#define KEY_FILE_VALUE_NAME L"File"
#define KEY_BLOB_COUNT_VALUE_NAME L"BlobCount"
#define KEY_BLOB_LENGTH_VALUE_NAME L"BlobLength"
#define KEY_BLOB_N_SUBKEY_PREFIX "Blob"
#define KEY_BLOB_N_SUBKEY_PREFIX_LENGTH 4
#define SYSTEM_STORE_SUBDIR L"SystemCertificates"
#define FILETIME_ASCII_HEX_LEN (2 * sizeof(FILETIME) + 1)
#define MAX_KEY_BLOB_VALUE_LEN 0x3000
#define MAX_NEW_FILE_CREATE_ATTEMPTS 100
#define SERIALIZED_SUBKEY_NAME L"Serialized"
//+-------------------------------------------------------------------------
// Read and allocate the element bytes by reading the file pointed to
// by the SubKey's "File" value
//--------------------------------------------------------------------------
STATIC BOOL ReadKeyFileElementFromRegistry(
IN HKEY hSubKey,
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
BOOL fResult;
LPWSTR pwszFilename = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cbBytesRead;
BYTE *pbElement = NULL;
DWORD cbElement;
if (NULL == (pwszFilename = ILS_ReadSZValueFromRegistry(
hSubKey, KEY_FILE_VALUE_NAME)))
goto GetKeyFilenameError;
if (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
pwszFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // lpsa
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
FILE_FLAG_BACKUP_SEMANTICS : 0),
NULL // hTemplateFile
)))
goto CreateFileError;
cbElement = GetFileSize(hFile, NULL);
if (0xFFFFFFFF == cbElement) goto FileError;
if (0 == cbElement) goto EmptyFile;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
if (!ReadFile(
hFile,
pbElement,
cbElement,
&cbBytesRead,
NULL // lpOverlapped
)) goto FileError;
fResult = TRUE;
CommonReturn:
PkiFree(pwszFilename);
if (INVALID_HANDLE_VALUE != hFile)
ILS_CloseHandle(hFile);
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
fResult = FALSE;
PkiFree(pbElement);
pbElement = NULL;
cbElement = 0;
goto CommonReturn;
TRACE_ERROR(GetKeyFilenameError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(CreateFileError)
TRACE_ERROR(FileError)
SET_ERROR(EmptyFile, CRYPT_E_FILE_ERROR)
}
//+-------------------------------------------------------------------------
// Read as multiple SubKeys containing the element bytes. The SubKeys
// are named Blob0, Blob1, Blob2, ... BlobN.
// Each BlobN SubKey has a value named "Blob" containing the bytes to be read.
//
// The passed in SubKey is expected to have 2 values:
// BlobCount - # of BlobN SubKeys
// BlobLength - total length of all the concatenated Blob Subkey bytes
//
// A single allocated element byte array is returned.
//--------------------------------------------------------------------------
STATIC BOOL ReadMultipleKeyBlobsFromRegistry(
IN HKEY hSubKey,
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
BOOL fResult;
LONG err;
HKEY hBlobKey = NULL;
BYTE *pbElement = NULL;
DWORD cbElement;
DWORD BlobCount;
DWORD BlobLength;
DWORD i;
char szBlobN[KEY_BLOB_N_SUBKEY_PREFIX_LENGTH + 33];
ILS_ReadDWORDValueFromRegistry(
hSubKey,
KEY_BLOB_COUNT_VALUE_NAME,
&BlobCount
);
ILS_ReadDWORDValueFromRegistry(
hSubKey,
KEY_BLOB_LENGTH_VALUE_NAME,
&BlobLength
);
if (0 == BlobCount || 0 == BlobLength)
goto NoMultipleKeyBlobs;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(BlobLength)))
goto OutOfMemory;
cbElement = 0;
strcpy(szBlobN, KEY_BLOB_N_SUBKEY_PREFIX);
for (i = 0; i < BlobCount; i++) {
DWORD cbData;
DWORD dwType;
_ltoa((long) i, szBlobN + KEY_BLOB_N_SUBKEY_PREFIX_LENGTH, 10);
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) {
DWORD dwDisposition;
if (ERROR_SUCCESS != (err = RegCreateKeyExA(
hSubKey,
szBlobN,
0, // dwReserved
NULL, // lpClass
REG_OPTION_BACKUP_RESTORE,
KEY_READ,
NULL, // lpSecurityAttributes
&hBlobKey,
&dwDisposition)))
goto OpenBackupRestoreBlobNError;
} else {
if (ERROR_SUCCESS != (err = RegOpenKeyExA(
hSubKey,
szBlobN,
0, // dwReserved
KEY_READ,
&hBlobKey)))
goto OpenBlobNError;
}
cbData = BlobLength - cbElement;
if (0 == cbData)
goto ExtraMultipleKeyBlobs;
if (ERROR_SUCCESS != (err = RegQueryValueExU(
hBlobKey,
KEY_BLOB_VALUE_NAME,
NULL, // pdwReserved
&dwType,
pbElement + cbElement,
&cbData)))
goto RegQueryValueError;
if (dwType != REG_BINARY)
goto InvalidRegistryValue;
cbElement += cbData;
if (cbElement > BlobLength)
goto UnexpectedError;
RegCloseKey(hBlobKey);
hBlobKey = NULL;
}
if (cbElement != BlobLength)
goto MissingMultipleKeyBlobsBytes;
assert(NULL == hBlobKey);
fResult = TRUE;
CommonReturn:
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
PkiFree(pbElement);
ILS_CloseRegistryKey(hBlobKey);
fResult = FALSE;
pbElement = NULL;
cbElement = 0;
goto CommonReturn;
SET_ERROR(NoMultipleKeyBlobs, ERROR_FILE_NOT_FOUND)
TRACE_ERROR(OutOfMemory)
SET_ERROR_VAR(OpenBlobNError, err)
SET_ERROR_VAR(OpenBackupRestoreBlobNError, err)
SET_ERROR(UnexpectedError, E_UNEXPECTED)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
SET_ERROR(ExtraMultipleKeyBlobs, CRYPT_E_FILE_ERROR)
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(MissingMultipleKeyBlobsBytes, CRYPT_E_FILE_ERROR)
}
//+-------------------------------------------------------------------------
// Write as multiple BlobN SubKeys containing the element bytes.
//
// See ReadMultipleKeyBlobsFromRegistry() for details.
//--------------------------------------------------------------------------
STATIC BOOL WriteMultipleKeyBlobsToRegistry(
IN HKEY hSubKey,
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
LONG err;
HKEY hBlobKey = NULL;
DWORD BlobCount = 0;
DWORD BlobLength;
DWORD i;
DWORD dwErr;
char szBlobN[KEY_BLOB_N_SUBKEY_PREFIX_LENGTH + 33];
if (0 == cbElement)
goto UnexpectedError;
BlobCount = cbElement / MAX_KEY_BLOB_VALUE_LEN;
if (cbElement % MAX_KEY_BLOB_VALUE_LEN)
BlobCount++;
BlobLength = 0;
strcpy(szBlobN, KEY_BLOB_N_SUBKEY_PREFIX);
for (i = 0; i < BlobCount; i++) {
DWORD cbData;
DWORD dwDisposition;
_ltoa((long) i, szBlobN + KEY_BLOB_N_SUBKEY_PREFIX_LENGTH, 10);
if (ERROR_SUCCESS != (err = RegCreateKeyExA(
hSubKey,
szBlobN,
0, // dwReserved
NULL, // lpClass
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
REG_OPTION_BACKUP_RESTORE : REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL, // lpSecurityAttributes
&hBlobKey,
&dwDisposition))) goto RegCreateKeyError;
assert(cbElement > BlobLength);
cbData = cbElement - BlobLength;
if (cbData > MAX_KEY_BLOB_VALUE_LEN)
cbData = MAX_KEY_BLOB_VALUE_LEN;
if (ERROR_SUCCESS != (err = RegSetValueExU(
hBlobKey,
KEY_BLOB_VALUE_NAME,
NULL,
REG_BINARY,
pbElement + BlobLength,
cbData))) goto RegSetValueError;
BlobLength += cbData;
RegCloseKey(hBlobKey);
hBlobKey = NULL;
}
assert(BlobLength == cbElement);
if (!WriteDWORDValueToRegistry(
hSubKey,
KEY_BLOB_COUNT_VALUE_NAME,
BlobCount))
goto WriteDWORDError;
if (!WriteDWORDValueToRegistry(
hSubKey,
KEY_BLOB_LENGTH_VALUE_NAME,
BlobLength))
goto WriteDWORDError;
assert(NULL == hBlobKey);
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
dwErr = GetLastError();
ILS_CloseRegistryKey(hBlobKey);
for (i = 0; i < BlobCount; i++) {
_ltoa((long) i, szBlobN + KEY_BLOB_N_SUBKEY_PREFIX_LENGTH, 10);
RegDeleteKeyA(hSubKey, szBlobN);
}
RegDeleteValueU(hSubKey, KEY_BLOB_COUNT_VALUE_NAME);
RegDeleteValueU(hSubKey, KEY_BLOB_LENGTH_VALUE_NAME);
fResult = FALSE;
SetLastError(dwErr);
goto CommonReturn;
SET_ERROR(UnexpectedError, E_UNEXPECTED)
SET_ERROR_VAR(RegCreateKeyError, err)
SET_ERROR_VAR(RegSetValueError, err)
TRACE_ERROR(WriteDWORDError)
}
//+-------------------------------------------------------------------------
// If the SubKey has a "File" value, delete the file.
//
// This is only applicable to obscure IE 4.0 cases.
//--------------------------------------------------------------------------
STATIC void DeleteKeyFile(
IN HKEY hKey,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN DWORD dwFlags // CERT_STORE_BACKUP_RESTORE_FLAG may be set
)
{
HKEY hSubKey = NULL;
if (ERROR_SUCCESS == OpenHKCUKeyExU(
hKey,
wszSubKeyName,
dwFlags,
KEY_ALL_ACCESS,
&hSubKey
)) {
LPWSTR pwszFilename;
if (pwszFilename = ILS_ReadSZValueFromRegistry(hSubKey,
KEY_FILE_VALUE_NAME)) {
SetFileAttributesU(pwszFilename, FILE_ATTRIBUTE_NORMAL);
DeleteFileU(pwszFilename);
PkiFree(pwszFilename);
}
RegDeleteValueU(hSubKey, KEY_FILE_VALUE_NAME);
RegCloseKey(hSubKey);
}
}
//+-------------------------------------------------------------------------
// Get the context by either getting the SubKey's "Blob" value or getting
// the SubKey's "BlobCount" and "BlobLength" values and then
// reading and concatenating multiple Blob<N> SubKeys containing the bytes or
// reading the file pointed to by the SubKey's "File" value.
//
// If the "File" value is found and used, then, migrate to being stored
// in the registry using multiple Blob<N> SubKeys.
//
// If CERT_REGISTRY_STORE_REMOTE_FLAG is set, then, don't attempt to read
// from the file.
//
// If CERT_STORE_READONLY_FLAG is set, don't attempt to migrate from the
// "File".
//--------------------------------------------------------------------------
STATIC BOOL ReadKeyElementFromRegistry(
IN HKEY hKey,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN DWORD dwFlags,
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
LONG err;
BOOL fResult;
BYTE *pbElement = NULL;
DWORD cbElement;
HKEY hSubKey = NULL;
if (ERROR_SUCCESS != (err = OpenHKCUKeyExU(
hKey,
wszSubKeyName,
dwFlags,
KEY_READ,
&hSubKey)))
goto OpenHKCUKeyError;
fResult = ILS_ReadBINARYValueFromRegistry(hSubKey, KEY_BLOB_VALUE_NAME,
&pbElement, &cbElement);
if (!fResult || 0 == cbElement) {
PkiFree(pbElement);
fResult = ReadMultipleKeyBlobsFromRegistry(hSubKey, dwFlags, &pbElement,
&cbElement);
if (!fResult && 0 == (dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG)) {
// For backwards compatibility with IE4.0. See if it exists
// in a file
fResult = ReadKeyFileElementFromRegistry(hSubKey, dwFlags,
&pbElement, &cbElement);
if (fResult && 0 == (dwFlags & CERT_STORE_READONLY_FLAG)) {
// Move from the file back to the registry.
if (WriteMultipleKeyBlobsToRegistry(hSubKey, dwFlags, pbElement,
cbElement))
DeleteKeyFile(hKey, wszSubKeyName, dwFlags);
}
}
if (!fResult)
goto ReadKeyElementError;
}
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
fResult = FALSE;
PkiFree(pbElement);
pbElement = NULL;
cbElement = 0;
goto CommonReturn;
SET_ERROR_VAR(OpenHKCUKeyError, err)
TRACE_ERROR(ReadKeyElementError)
}
STATIC BOOL ReadKeyFromRegistry(
IN HKEY hKey,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN HCERTSTORE hCertStore,
IN DWORD dwContextTypeFlags,
IN DWORD dwFlags
)
{
BOOL fResult;
BYTE *pbElement = NULL;
DWORD cbElement;
DWORD dwContextType = 0;
const void *pvContext = NULL;
if (!ReadKeyElementFromRegistry(
hKey,
wszSubKeyName,
dwFlags,
&pbElement,
&cbElement
))
goto ErrorReturn;
if (!CertAddSerializedElementToStore(
hCertStore,
pbElement,
cbElement,
CERT_STORE_ADD_ALWAYS,
0, // dwFlags
dwContextTypeFlags,
&dwContextType,
&pvContext
))
goto AddSerializedElementError;
if (IsValidRegValueNameForContext(
dwContextType,
pvContext,
wszSubKeyName
))
FreeContext(dwContextType, pvContext);
else {
DeleteContextFromStore(dwContextType, pvContext);
goto InvalidRegValueNameForContext;
}
CertPerfIncrementRegElementReadCount();
fResult = TRUE;
CommonReturn:
PkiFree(pbElement);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(AddSerializedElementError)
TRACE_ERROR(InvalidRegValueNameForContext)
}
//+-------------------------------------------------------------------------
// Get the Certificates, CRLs or CTLs from the registry by reading as
// SubKeys and not Key values as done by OpenFromRegistry.
//
// If CERT_STORE_DELETE_FLAG is set, delete the file, if stored there.
//
// If CERT_REGISTRY_STORE_REMOTE_FLAG is set, then, don't attempt to read
// from the file.
//
// If CERT_STORE_READONLY_FLAG is set, don't attempt to migrate from the
// "File".
//--------------------------------------------------------------------------
STATIC BOOL OpenKeysFromRegistry(
IN HCERTSTORE hCertStore,
IN HKEY hKey,
IN DWORD dwFlags
)
{
BOOL fResult;
LONG err;
DWORD cSubKeys;
DWORD i;
// see how many SubKeys in the registry
if (!GetSubKeyInfo(hKey, &cSubKeys))
goto GetSubKeyInfoError;
for (i = 0; i < cSubKeys; i++) {
WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN];
DWORD cchSubKeyName = MAX_CERT_REG_VALUE_NAME_LEN;
err = RegEnumKeyExU(
hKey,
i,
wszSubKeyName,
&cchSubKeyName,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
);
if (ERROR_SUCCESS != err) {
if (ERROR_NO_MORE_ITEMS == err)
break;
else
continue;
} else if (dwFlags & CERT_STORE_DELETE_FLAG) {
if (0 == (dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG))
DeleteKeyFile(hKey, wszSubKeyName, dwFlags);
} else
// Ignore any read errors
ReadKeyFromRegistry(
hKey,
wszSubKeyName,
hCertStore,
CERT_STORE_ALL_CONTEXT_FLAG,
dwFlags
);
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetSubKeyInfoError)
}
#if 0
//
// The following was done in IE4.0 on Win95
//
//+-------------------------------------------------------------------------
// Create the filename to contain the encoded element. The filename will
// be something like:
// C:\Windows\SystemCertificates\
// 00112233445566778899AABBCCDDEEFF00112233.0011223344556677
// Where:
// C:\Windows - obtained via GetWindowsDirectory
// SystemCertificates - subdirectory containing all file elements
// 00112233445566778899AABBCCDDEEFF00112233
// - wszSubKeyName (ascii hex sha1)
// 0011223344556677 - ascii hex of current filetime
//
//
// In addition to creating the filename, also creates the
// "SystemCertificates" directory under C:\Windows.
//--------------------------------------------------------------------------
STATIC LPWSTR CreateKeyFilename(
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN LPFILETIME pft
)
{
LPWSTR pwszWindowsDir = NULL;
DWORD cchWindowsDir;
WCHAR rgwc[1];
BYTE rgbft[sizeof(FILETIME)];
WCHAR wszft[FILETIME_ASCII_HEX_LEN];
LPWSTR pwszFilename = NULL;
DWORD cchFilename;
if (0 == (cchWindowsDir = GetWindowsDirectoryU(rgwc, 1)))
goto GetWindowsDirError;
cchWindowsDir++; // bump to include null terminator
if (NULL == (pwszWindowsDir = (LPWSTR) PkiNonzeroAlloc(
cchWindowsDir * sizeof(WCHAR))))
goto OutOfMemory;
if (0 == GetWindowsDirectoryU(pwszWindowsDir, cchWindowsDir))
goto GetWindowsDirError;
// Convert filetime to ascii hex. First reverse the filetime bytes.
memcpy(rgbft, pft, sizeof(rgbft));
PkiAsn1ReverseBytes(rgbft, sizeof(rgbft));
ILS_BytesToWStr(sizeof(rgbft), rgbft, wszft);
// Get total length of filename and allocate
cchFilename = cchWindowsDir + 1 +
wcslen(SYSTEM_STORE_SUBDIR) + 1 +
MAX_CERT_REG_VALUE_NAME_LEN + 1 +
FILETIME_ASCII_HEX_LEN + 1;
if (NULL == (pwszFilename = (LPWSTR) PkiNonzeroAlloc(
cchFilename * sizeof(WCHAR))))
goto OutOfMemory;
// Create C:\Windows\SystemCertificates directory if it doesn't already
// exist
wcscpy(pwszFilename, pwszWindowsDir);
cchWindowsDir = wcslen(pwszWindowsDir);
if (cchWindowsDir && L'\\' != pwszWindowsDir[cchWindowsDir - 1])
wcscat(pwszFilename, L"\\");
wcscat(pwszFilename, SYSTEM_STORE_SUBDIR);
if (0xFFFFFFFF == GetFileAttributesU(pwszFilename)) {
if (!CreateDirectoryU(
pwszFilename,
NULL // lpsa
)) goto CreateDirError;
}
// Append \<AsciiHexSubKeyName>.<AsciiHexFileTime> to the above directory
// name to complete the filename string
wcscat(pwszFilename, L"\\");
wcscat(pwszFilename, wszSubKeyName);
wcscat(pwszFilename, L".");
wcscat(pwszFilename, wszft);
CommonReturn:
PkiFree(pwszWindowsDir);
return pwszFilename;
ErrorReturn:
PkiFree(pwszFilename);
pwszFilename = NULL;
goto CommonReturn;
TRACE_ERROR(GetWindowsDirError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(CreateDirError)
}
//+-------------------------------------------------------------------------
// Write the bytes to a a file and update the SubKey's "File" value to
// point to.
//
// This code is here to show what was done in IE4.0.
//--------------------------------------------------------------------------
STATIC BOOL WriteKeyFileElementToRegistry(
IN HKEY hSubKey,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
LONG err;
HANDLE hFile = INVALID_HANDLE_VALUE;
LPWSTR pwszFilename = NULL;
SYSTEMTIME st;
FILETIME ft;
DWORD i;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
for (i = 0; i < MAX_NEW_FILE_CREATE_ATTEMPTS; i++) {
DWORD cbBytesWritten;
if (NULL == (pwszFilename = CreateKeyFilename(wszSubKeyName, &ft)))
goto CreateKeyFilenameError;
if (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
pwszFilename,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL |
((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
FILE_FLAG_BACKUP_SEMANTICS : 0),
NULL // hTemplateFile
))) {
if (ERROR_FILE_EXISTS != GetLastError())
goto CreateFileError;
else {
PkiFree(pwszFilename);
pwszFilename = NULL;
*((_int64 *) &ft) += 1;
continue;
}
}
if (!WriteFile(
hFile,
pbElement,
cbElement,
&cbBytesWritten,
NULL // lpOverlapped
)) goto WriteFileError;
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
if (!SetFileAttributesU(pwszFilename,
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY ))
goto SetFileAttributesError;
if (ERROR_SUCCESS != (err = RegSetValueExU(
hSubKey,
KEY_FILE_VALUE_NAME,
NULL,
REG_SZ,
(BYTE *) pwszFilename,
(wcslen(pwszFilename) + 1) * sizeof(WCHAR))))
goto RegSetValueError;
else
goto SuccessReturn;
}
goto ExceededMaxFileCreateAttemptsError;
SuccessReturn:
fResult = TRUE;
CommonReturn:
if (INVALID_HANDLE_VALUE != hFile)
ILS_CloseHandle(hFile);
PkiFree(pwszFilename);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegSetValueError, err)
TRACE_ERROR(CreateKeyFilenameError)
TRACE_ERROR(CreateFileError)
TRACE_ERROR(WriteFileError)
TRACE_ERROR(SetFileAttributesError)
SET_ERROR(ExceededMaxFileCreateAttemptsError, CRYPT_E_FILE_ERROR)
}
#endif // end of IE4.0 "File" support
//+-------------------------------------------------------------------------
// If the length of the element is <= MAX_KEY_BLOB_VALUE_LEN, then,
// write it as the SubKey's "Blob" value. Otherwise, write it as multiple
// SubKeys each containing a "Blob" value no larger than
// MAX_KEY_BLOB_VALUE_LEN.
//--------------------------------------------------------------------------
STATIC BOOL WriteKeyToRegistry(
IN HKEY hKey,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
LONG err;
HKEY hSubKey = NULL;
DWORD dwDisposition;
if (ERROR_SUCCESS != (err = RegCreateHKCUKeyExU(
hKey,
wszSubKeyName,
NULL,
NULL,
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
REG_OPTION_BACKUP_RESTORE : REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hSubKey,
&dwDisposition))) goto RegCreateKeyError;
if (MAX_KEY_BLOB_VALUE_LEN >= cbElement) {
// Write as a single "Blob" value
if (ERROR_SUCCESS != (err = RegSetValueExU(
hSubKey,
KEY_BLOB_VALUE_NAME,
NULL,
REG_BINARY,
pbElement,
cbElement))) goto RegSetValueError;
} else {
// Write as a multiple Blob<N> SubKeys
if (!WriteMultipleKeyBlobsToRegistry(
hSubKey, dwFlags, pbElement, cbElement))
goto WriteMultipleKeyBlobsError;
// if (!WriteKeyFileElementToRegistry(wszSubKeyName, hSubKey, dwFlags, pbElement, cbElement))
// goto ErrorReturn;
}
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegCreateKeyError, err)
SET_ERROR_VAR(RegSetValueError, err)
TRACE_ERROR(WriteMultipleKeyBlobsError)
}
//+=========================================================================
// Registry Functions
//==========================================================================
//+-------------------------------------------------------------------------
// First attempt to read as Key's value. If that fails for Win95, then,
// read as a value in one or more SubKeys or as a
// file with a SubKey pointing to it.
//
// If CERT_REGISTRY_STORE_REMOTE_FLAG is set, then, don't attempt to read
// from the file.
//
// If CERT_STORE_READONLY_FLAG is set, don't attempt to migrate from the
// "File".
//--------------------------------------------------------------------------
BOOL
ILS_ReadElementFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags,
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
LONG err;
BOOL fResult;
HKEY hSubKey = NULL;
DWORD dwType;
BYTE *pbElement = NULL;
DWORD cbElement;
if (pwszContextName) {
if (NULL == (hSubKey = OpenSubKey(
hKey,
pwszContextName,
dwFlags | CERT_STORE_READONLY_FLAG
)))
goto OpenSubKeyError;
} else
hSubKey = hKey;
err = RegQueryValueExU(
hSubKey,
wszHashName,
NULL, // pdwReserved
&dwType,
NULL, // lpData
&cbElement);
// For Win95 Remote Registry Access:: returns ERROR_MORE_DATA
if (!(ERROR_SUCCESS == err || ERROR_MORE_DATA == err)) {
fResult = ReadKeyElementFromRegistry(
hSubKey,
wszHashName,
dwFlags,
&pbElement,
&cbElement
);
goto CommonReturn;
}
if (dwType != REG_BINARY || cbElement == 0)
goto InvalidRegistryValue;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
if (ERROR_SUCCESS != (err = RegQueryValueExU(
hSubKey,
wszHashName,
NULL, // pdwReserved
&dwType,
pbElement,
&cbElement))) goto RegQueryValueError;
fResult = TRUE;
CommonReturn:
if (pwszContextName)
ILS_CloseRegistryKey(hSubKey);
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
fResult = FALSE;
PkiFree(pbElement);
pbElement = NULL;
cbElement = 0;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
SET_ERROR_VAR(RegQueryValueError, err)
SET_ERROR(InvalidRegistryValue, CRYPT_E_FILE_ERROR)
TRACE_ERROR(OutOfMemory)
}
//+-------------------------------------------------------------------------
// First delete as the Key's value. Then, for Win95 also delete as the
// Key's SubKey and possibly file.
//--------------------------------------------------------------------------
BOOL
ILS_DeleteElementFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags
)
{
BOOL fResult;
HKEY hSubKey = NULL;
if (NULL == (hSubKey = OpenSubKey(
hKey,
pwszContextName,
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG
)))
goto OpenSubKeyError;
RegDeleteValueU(hSubKey, wszHashName);
if (0 == (dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG))
DeleteKeyFile(hSubKey, wszHashName, dwFlags);
fResult = RecursiveDeleteSubKey(hSubKey, wszHashName, dwFlags);
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
}
//+-------------------------------------------------------------------------
// If the length of the element is less than the maximum allowed Win95 value
// length, then, attempt to set the wszRegName SubKey's "Blob" value as
// a single registry API call. Versus, first doing registry deletes.
//--------------------------------------------------------------------------
STATIC BOOL AtomicUpdateRegistry(
IN HKEY hKey,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
LONG err;
HKEY hSubKey = NULL;
DWORD dwDisposition = 0;
if (MAX_KEY_BLOB_VALUE_LEN < cbElement)
return FALSE;
// In case the element still exists as a wszHashName value instead of as a
// wszHashName subkey
RegDeleteValueU(hKey, wszHashName);
if (ERROR_SUCCESS != (err = RegCreateHKCUKeyExU(
hKey,
wszHashName,
NULL,
NULL,
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
REG_OPTION_BACKUP_RESTORE : REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hSubKey,
&dwDisposition))) goto AtomicRegCreateKeyError;
if (REG_OPENED_EXISTING_KEY == dwDisposition) {
DWORD dwType;
DWORD cbData;
assert(hSubKey);
err = RegQueryValueExU(
hSubKey,
KEY_BLOB_VALUE_NAME,
NULL, // pdwReserved
&dwType,
NULL, // lpData
&cbData);
if (!(ERROR_SUCCESS == err || ERROR_MORE_DATA == err))
// Most likely persisted as partioned "Blob0", "Blob1" values.
// These can't be updated in a single atomic set value.
goto AtomicQueryValueError;
// "Blob" value exists. We can do an atomic update.
}
// else
// REG_CREATED_NEW_KEY
assert(hSubKey);
// Either update or create the "Blob" value
if (ERROR_SUCCESS != (err = RegSetValueExU(
hSubKey,
KEY_BLOB_VALUE_NAME,
NULL,
REG_BINARY,
pbElement,
cbElement))) goto AtomicRegSetValueError;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(AtomicRegCreateKeyError, err)
SET_ERROR_VAR(AtomicQueryValueError, err)
SET_ERROR_VAR(AtomicRegSetValueError, err)
}
//+-------------------------------------------------------------------------
// First attempt as an atomic registry update of the wszRegName's "Blob"
// value. If that fails, then, delete everything and write as either a
// single or partitioned blob value under the wszRegName's subkey.
//--------------------------------------------------------------------------
BOOL
ILS_WriteElementToRegistry(
IN HKEY hKey,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_REGISTRY_STORE_REMOTE_FLAG or
// CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
HKEY hSubKey = NULL;
if (NULL == (hSubKey = OpenSubKey(
hKey,
pwszContextName,
dwFlags
)))
goto OpenSubKeyError;
// See if we can do the update as a single, atomic, set registry value API
// call.
if (AtomicUpdateRegistry(
hSubKey,
wszHashName,
dwFlags,
pbElement,
cbElement
)) {
fResult = TRUE;
goto CommonReturn;
}
// If any version exists for this guy, get rid of it.
ILS_DeleteElementFromRegistry(hKey, pwszContextName, wszHashName,
dwFlags);
#if 1
fResult = WriteKeyToRegistry(hSubKey, wszHashName, dwFlags,
pbElement, cbElement);
#else
if (ERROR_SUCCESS != (err = RegSetValueExU(
hSubKey,
wszHashName,
NULL,
REG_BINARY,
pbElement,
cbElement))) {
// Win95 returns:
// ERROR_INVALID_PARAMETER if exceeded single SubKey value byte
// limitation
// ERROR_OUTOFMEMORY if exceeded total SubKey values byte
// limitation
if (ERROR_INVALID_PARAMETER == err ||
ERROR_OUTOFMEMORY == err ||
MAX_KEY_BLOB_VALUE_LEN < cbElement)
return WriteKeyToRegistry(hSubKey, wszHashName, dwFlags,
pbElement, cbElement);
goto RegSetValueError;
}
fResult = TRUE;
#endif
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
#if 1
#else
SET_ERROR_VAR(RegSetValueError, err)
#endif
}
BOOL
ILS_OpenAllElementsFromRegistry(
IN HKEY hKey,
IN LPCWSTR pwszContextName,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_ILS_OPEN_ELEMENT pfnOpenElement
)
{
BOOL fResult;
HKEY hSubKey = NULL;
LONG err;
DWORD cSubKeys;
DWORD i;
dwFlags |= CERT_STORE_READONLY_FLAG;
if (NULL == (hSubKey = OpenSubKey(
hKey,
pwszContextName,
dwFlags
)))
goto OpenSubKeyError;
// see how many SubKeys in the registry
if (!GetSubKeyInfo(hSubKey, &cSubKeys))
goto GetSubKeyInfoError;
for (i = 0; i < cSubKeys; i++) {
WCHAR wszHashName[MAX_HASH_NAME_LEN];
DWORD cchHashName = MAX_HASH_NAME_LEN;
BYTE *pbElement;
DWORD cbElement;
err = RegEnumKeyExU(
hSubKey,
i,
wszHashName,
&cchHashName,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
);
if (ERROR_SUCCESS != err) {
if (ERROR_NO_MORE_ITEMS == err)
break;
else
continue;
}
if (ILS_ReadElementFromRegistry(
hSubKey,
NULL, // pwszContextName
wszHashName,
dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG,
&pbElement,
&cbElement
)) {
fResult = pfnOpenElement(
wszHashName,
pbElement,
cbElement,
pvArg
);
PkiFree(pbElement);
if (!fResult)
goto CommonReturn;
}
}
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetSubKeyInfoError)
TRACE_ERROR(OpenSubKeyError)
}
//+-------------------------------------------------------------------------
// Get the Certificates, CRLs or CTLs from the registry
//
// If CERT_REGISTRY_STORE_REMOTE_FLAG is set, then, don't attempt to read
// from the file.
//
// If CERT_STORE_READONLY_FLAG is set, don't attempt to migrate from the
// "File".
//
// If any contexts are persisted as values instead of as subkeys, then,
// if not READONLY, migrate from values to subkeys.
//--------------------------------------------------------------------------
STATIC BOOL OpenFromRegistry(
IN HCERTSTORE hCertStore,
IN HKEY hKeyT,
IN DWORD dwFlags
)
{
BOOL fOK = TRUE;
LONG err;
DWORD cValues, cchValuesNameMax, cbValuesMax;
WCHAR * wszValueName = NULL;
DWORD i, dwType, cchHash;
BYTE * pbElement = NULL;
DWORD cbElement;
// see how many and how big the registry is
if (ERROR_SUCCESS != (err = RegQueryInfoKeyU(
hKeyT,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cValues,
&cchValuesNameMax,
&cbValuesMax,
NULL,
NULL))) goto RegQueryInfoKeyError;
if (cValues && cbValuesMax) {
// allocate the memory needed to read the reg
// Remote Registry calls on Win95 includes the NULL terminator, that's
// why we add +2 and not just +1
if (NULL == (wszValueName = (WCHAR *) PkiNonzeroAlloc(
(cchValuesNameMax+2) * sizeof(WCHAR))))
goto OutOfMemory;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbValuesMax)))
goto OutOfMemory;
// enum the registry getting certs, CRLs or CTLs
for (i=0; i<cValues; i++ ) {
cbElement = cbValuesMax;
// Remote Registry calls on Win95 includes the NULL terminator
cchHash = cchValuesNameMax + 2;
err = RegEnumValueU( hKeyT,
i,
wszValueName,
&cchHash,
NULL,
&dwType,
pbElement,
&cbElement);
// any error get it set
// but we want to continue to get all good certs
if( err != ERROR_SUCCESS )
continue;
else {
fOK &= CertAddSerializedElementToStore(
hCertStore,
pbElement,
cbElement,
CERT_STORE_ADD_ALWAYS,
0, // dwFlags
CERT_STORE_ALL_CONTEXT_FLAG,
NULL, // pdwContextType
NULL); // ppvContext
CertPerfIncrementRegElementReadCount();
}
}
}
fOK &= OpenKeysFromRegistry(hCertStore, hKeyT, dwFlags);
if (cValues && cbValuesMax && fOK &&
0 == (dwFlags & CERT_STORE_READONLY_FLAG)) {
// Migrate from values to subkeys. This allows registry roaming
// from NT to Win95 without exceeding the Win95 registry
// limitations
HKEY hSubKey = NULL;
while (TRUE) {
if (NULL == (hSubKey = OpenSubKey(
hKeyT,
NULL, // pwszSubKey
CERT_STORE_OPEN_EXISTING_FLAG |
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
)))
break;
cbElement = cbValuesMax;
// Remote Registry calls on Win95 includes the NULL terminator
cchHash = cchValuesNameMax + 2;
if (ERROR_SUCCESS != RegEnumValueU(
hSubKey,
0, // iValue
wszValueName,
&cchHash,
NULL,
&dwType,
pbElement,
&cbElement))
break;
if (!WriteKeyToRegistry(hSubKey, wszValueName, dwFlags,
pbElement, cbElement))
break;
if (ERROR_SUCCESS != RegDeleteValueU(hSubKey, wszValueName))
break;
RegCloseKey(hSubKey);
}
if (hSubKey)
RegCloseKey(hSubKey);
}
CommonReturn:
// done with our memory
PkiFree(wszValueName);
PkiFree(pbElement);
return fOK;
ErrorReturn:
fOK = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegQueryInfoKeyError, err)
TRACE_ERROR(OutOfMemory)
}
STATIC BOOL MoveFromRegistryToRoamingFiles(
IN HKEY hSubKey,
IN LPCWSTR pwszStoreDirectory,
IN LPCWSTR pwszContextName,
IN DWORD dwFlags // CERT_STORE_BACKUP_RESTORE_FLAG may be set
)
{
BYTE *pbElement = NULL;
DWORD cbElement;
while (TRUE) {
WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN];
DWORD cchSubKeyName = MAX_CERT_REG_VALUE_NAME_LEN;
if (ERROR_SUCCESS != RegEnumKeyExU(
hSubKey,
0,
wszSubKeyName,
&cchSubKeyName,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
))
break;
if (!ILS_ReadElementFromRegistry(
hSubKey,
NULL, // pwszContextName
wszSubKeyName,
CERT_STORE_READONLY_FLAG |
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG),
&pbElement,
&cbElement
))
goto ReadElementFromRegistryError;
if (!ILS_WriteElementToFile(
pwszStoreDirectory,
pwszContextName,
wszSubKeyName,
CERT_STORE_CREATE_NEW_FLAG |
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG),
pbElement,
cbElement
)) {
if (ERROR_FILE_EXISTS != GetLastError())
goto WriteElementToFileError;
}
PkiFree(pbElement);
pbElement = NULL;
if (!RecursiveDeleteSubKey(
hSubKey,
wszSubKeyName,
dwFlags
))
goto DeleteSubKeyError;
}
CommonReturn:
return TRUE;
ErrorReturn:
PkiFree(pbElement);
goto CommonReturn;
TRACE_ERROR(ReadElementFromRegistryError)
TRACE_ERROR(WriteElementToFileError)
TRACE_ERROR(DeleteSubKeyError)
}
typedef struct _READ_CONTEXT_CALLBACK_ARG {
BOOL fOK;
HCERTSTORE hCertStore;
} READ_CONTEXT_CALLBACK_ARG, *PREAD_CONTEXT_CALLBACK_ARG;
STATIC BOOL ReadContextCallback(
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN const BYTE *pbElement,
IN DWORD cbElement,
IN void *pvArg
)
{
BOOL fResult;
PREAD_CONTEXT_CALLBACK_ARG pReadContextArg =
(PREAD_CONTEXT_CALLBACK_ARG) pvArg;
DWORD dwContextType = 0;
const void *pvContext = NULL;
fResult = CertAddSerializedElementToStore(
pReadContextArg->hCertStore,
pbElement,
cbElement,
CERT_STORE_ADD_ALWAYS,
0, // dwFlags
CERT_STORE_ALL_CONTEXT_FLAG,
&dwContextType,
&pvContext
);
if (fResult) {
if (IsValidRegValueNameForContext(
dwContextType,
pvContext,
wszHashName
))
FreeContext(dwContextType, pvContext);
else {
DeleteContextFromStore(dwContextType, pvContext);
pReadContextArg->fOK = FALSE;
}
} else
pReadContextArg->fOK = FALSE;
CertPerfIncrementRegElementReadCount();
return TRUE;
}
//+-------------------------------------------------------------------------
// Get all the Certificates, CRLs and CTLs from the registry
//--------------------------------------------------------------------------
STATIC BOOL OpenAllFromRegistry(
IN PREG_STORE pRegStore,
IN HCERTSTORE hCertStore
)
{
BOOL fResult;
HKEY hSubKey = NULL;
DWORD i;
for (i = 0; i < CONTEXT_COUNT; i++) {
if (pRegStore->hKey) {
if (NULL == (hSubKey = OpenSubKey(
pRegStore->hKey,
rgpwszContextSubKeyName[i],
pRegStore->dwFlags
))) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenSubKeyError;
} else {
// Ignore any registry errors
OpenFromRegistry(hCertStore, hSubKey, pRegStore->dwFlags);
}
}
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) {
READ_CONTEXT_CALLBACK_ARG ReadContextArg;
ReadContextArg.fOK = TRUE;
ReadContextArg.hCertStore = hCertStore;
if (!ILS_OpenAllElementsFromDirectory(
pRegStore->pwszStoreDirectory,
rgpwszContextSubKeyName[i],
pRegStore->dwFlags,
(void *) &ReadContextArg,
ReadContextCallback
)) {
DWORD dwErr = GetLastError();
if (!(ERROR_PATH_NOT_FOUND == dwErr ||
ERROR_FILE_NOT_FOUND == dwErr))
goto OpenRoamingFilesError;
}
// Ignore any read context errors
if (hSubKey &&
0 == (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)) {
MoveFromRegistryToRoamingFiles(
hSubKey,
pRegStore->pwszStoreDirectory,
rgpwszContextSubKeyName[i],
pRegStore->dwFlags
);
}
}
if (hSubKey) {
ILS_CloseRegistryKey(hSubKey);
hSubKey = NULL;
}
}
if ((pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) &&
pRegStore->hKey &&
0 == (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)) {
// Move the Key Identifiers from the registry to roaming files
if (hSubKey = OpenSubKey(
pRegStore->hKey,
KEYID_CONTEXT_NAME,
pRegStore->dwFlags
)) {
MoveFromRegistryToRoamingFiles(
hSubKey,
pRegStore->pwszStoreDirectory,
KEYID_CONTEXT_NAME,
pRegStore->dwFlags
);
ILS_CloseRegistryKey(hSubKey);
hSubKey = NULL;
}
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
ILS_CloseRegistryKey(hSubKey);
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
TRACE_ERROR(OpenRoamingFilesError)
}
//+-------------------------------------------------------------------------
// Delete all the Certificates, CRLs and CTLs context subkeys. For Win95
// also delete context files.
//
// Also, if it exists, delete the "Serialized" subkey.
//--------------------------------------------------------------------------
STATIC BOOL DeleteAllFromRegistry(
IN HKEY hKey,
IN DWORD dwFlags // CERT_REGISTRY_STORE_REMOTE_FLAG or
// CERT_STORE_BACKUP_RESTORE_FLAG may be set
)
{
BOOL fResult;
DWORD i;
for (i = 0; i < CONTEXT_COUNT; i++) {
LPCWSTR pwszSubKeyName = rgpwszContextSubKeyName[i];
if (0 == (dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG)) {
// For WIN95, if a context is stored in a file, delete the
// file
HKEY hSubKey;
if (NULL == (hSubKey = OpenSubKey(
hKey,
pwszSubKeyName,
CERT_STORE_OPEN_EXISTING_FLAG |
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
))) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenContextSubKeyError;
continue;
}
fResult = OpenKeysFromRegistry(
NULL, // hCertStore
hSubKey,
dwFlags
);
ILS_CloseRegistryKey(hSubKey);
if (!fResult)
goto DeleteKeysError;
}
if (!RecursiveDeleteSubKey(hKey, pwszSubKeyName, dwFlags)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto DeleteSubKeyError;
}
}
if (!RecursiveDeleteSubKey(hKey, SERIALIZED_SUBKEY_NAME, dwFlags)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto DeleteSubKeyError;
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenContextSubKeyError)
TRACE_ERROR(DeleteKeysError)
TRACE_ERROR(DeleteSubKeyError)
}
//+=========================================================================
// Serialized Registry Functions
//==========================================================================
static inline BOOL IsReadSerializedRegistry(
IN PREG_STORE pRegStore
)
{
return (pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG);
}
static inline BOOL IsWriteSerializedRegistry(
IN PREG_STORE pRegStore
)
{
if (0 == (pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG))
return FALSE;
pRegStore->fTouched = TRUE;
return TRUE;
}
//+-------------------------------------------------------------------------
// Get all the Certificates, CRLs and CTLs from a single serialized
// partitioned "blob" stored in the registry. The "blob" is stored under
// the "Serialized" subkey.
//
// Either called during initial open or with RegStore locked.
//--------------------------------------------------------------------------
STATIC BOOL OpenAllFromSerializedRegistry(
IN PREG_STORE pRegStore,
IN HCERTSTORE hCertStore
)
{
BOOL fResult;
HKEY hSubKey = NULL;
BYTE *pbStore = NULL;
DWORD cbStore;
assert(pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG);
if (NULL == (hSubKey = OpenSubKey(
pRegStore->hKey,
SERIALIZED_SUBKEY_NAME,
pRegStore->dwFlags
)))
goto OpenSubKeyError;
if (!ReadMultipleKeyBlobsFromRegistry(
hSubKey,
pRegStore->dwFlags,
&pbStore,
&cbStore
))
goto ReadError;
if (!I_CertAddSerializedStore(
hCertStore,
pbStore,
cbStore
))
goto AddError;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
PkiFree(pbStore);
return fResult;
ErrorReturn:
if (ERROR_FILE_NOT_FOUND == GetLastError())
fResult = TRUE;
else
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
TRACE_ERROR(ReadError)
TRACE_ERROR(AddError)
}
//+=========================================================================
// Serialized Control Functions
//==========================================================================
STATIC BOOL IsEmptyStore(
IN HCERTSTORE hCertStore
)
{
PCCERT_CONTEXT pCert;
PCCRL_CONTEXT pCrl;
PCCTL_CONTEXT pCtl;
if (pCert = CertEnumCertificatesInStore(hCertStore, NULL)) {
CertFreeCertificateContext(pCert);
return FALSE;
}
if (pCrl = CertEnumCRLsInStore(hCertStore, NULL)) {
CertFreeCRLContext(pCrl);
return FALSE;
}
if (pCtl = CertEnumCTLsInStore(hCertStore, NULL)) {
CertFreeCTLContext(pCtl);
return FALSE;
}
return TRUE;
}
STATIC BOOL CommitAllToSerializedRegistry(
IN PREG_STORE pRegStore,
IN DWORD dwFlags
)
{
BOOL fResult;
BOOL fTouched;
CRYPT_DATA_BLOB SerializedData = {0, NULL};
HKEY hSubKey = NULL;
LockRegStore(pRegStore);
assert(pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG);
if (dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG)
fTouched = TRUE;
else if (dwFlags & CERT_STORE_CTRL_COMMIT_CLEAR_FLAG)
fTouched = FALSE;
else
fTouched = pRegStore->fTouched;
if (fTouched) {
BOOL fEmpty;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
fEmpty = IsEmptyStore(pRegStore->hCertStore);
if (!fEmpty) {
if (!CertSaveStore(
pRegStore->hCertStore,
0, // dwEncodingType
CERT_STORE_SAVE_AS_STORE,
CERT_STORE_SAVE_TO_MEMORY,
&SerializedData,
0)) // dwFlags
goto SaveStoreError;
assert(SerializedData.cbData);
if (NULL == (SerializedData.pbData = (BYTE *) PkiNonzeroAlloc(
SerializedData.cbData)))
goto OutOfMemory;
if (!CertSaveStore(
pRegStore->hCertStore,
0, // dwEncodingType
CERT_STORE_SAVE_AS_STORE,
CERT_STORE_SAVE_TO_MEMORY,
&SerializedData,
0)) // dwFlags
goto SaveStoreError;
}
if (!RecursiveDeleteSubKey(
pRegStore->hKey, SERIALIZED_SUBKEY_NAME, pRegStore->dwFlags)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto DeleteSubKeyError;
}
if (!fEmpty) {
if (NULL == (hSubKey = OpenSubKey(
pRegStore->hKey,
SERIALIZED_SUBKEY_NAME,
pRegStore->dwFlags
)))
goto OpenSubKeyError;
if (!WriteMultipleKeyBlobsToRegistry(
hSubKey,
pRegStore->dwFlags,
SerializedData.pbData,
SerializedData.cbData
))
goto WriteStoreError;
}
}
pRegStore->fTouched = FALSE;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
PkiFree(SerializedData.pbData);
UnlockRegStore(pRegStore);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(SaveStoreError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(DeleteSubKeyError)
TRACE_ERROR(OpenSubKeyError)
TRACE_ERROR(WriteStoreError)
}
//+-------------------------------------------------------------------------
// Open the registry's store by reading its serialized certificates,
// CRLs and CTLs and adding to the specified certificate store.
//
// Note for an error return, the caller will free any certs, CRLs or CTLs
// successfully added to the store.
//
// Only return HKEY for success. For a CertOpenStore error the caller
// will close the HKEY.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenRegStoreProv(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
HKEY hKey = (HKEY) pvPara;
PREG_STORE pRegStore = NULL;
DWORD dwErr;
assert(hKey);
if (dwFlags & ~OPEN_REG_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (dwFlags & CERT_STORE_DELETE_FLAG) {
if (DeleteAllFromRegistry(hKey, dwFlags)) {
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_DELETED_FLAG;
return TRUE;
} else
return FALSE;
}
if (NULL == (pRegStore = (PREG_STORE) PkiZeroAlloc(sizeof(REG_STORE))))
goto OutOfMemory;
if (!Pki_InitializeCriticalSection(&pRegStore->CriticalSection)) {
PkiFree(pRegStore);
pRegStore = NULL;
goto OutOfMemory;
}
pRegStore->hCertStore = hCertStore;
pRegStore->dwFlags = dwFlags;
CertPerfIncrementStoreRegTotalCount();
CertPerfIncrementStoreRegCurrentCount();
if (dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
PCERT_REGISTRY_STORE_CLIENT_GPT_PARA pGptPara =
(PCERT_REGISTRY_STORE_CLIENT_GPT_PARA) pvPara;
DWORD cbRegPath = (wcslen(pGptPara->pwszRegPath) + 1) * sizeof(WCHAR);
if (NULL == (pRegStore->GptPara.pwszRegPath =
(LPWSTR) PkiNonzeroAlloc(cbRegPath)))
goto OutOfMemory;
memcpy(pRegStore->GptPara.pwszRegPath, pGptPara->pwszRegPath,
cbRegPath);
// Make a copy of the base hKey
// BUG in NT4.0 and NT5.0. Doesn't support opening of the HKLM with
// a NULL pwszSubKey
if (HKEY_LOCAL_MACHINE == pGptPara->hKeyBase)
pRegStore->GptPara.hKeyBase = HKEY_LOCAL_MACHINE;
else if (NULL == (pRegStore->GptPara.hKeyBase = OpenSubKey(
pGptPara->hKeyBase,
NULL, // pwszSubKey
(dwFlags & ~CERT_STORE_CREATE_NEW_FLAG) |
CERT_STORE_OPEN_EXISTING_FLAG
)))
goto OpenSubKeyError;
fResult = OpenAllFromGptRegistry(pRegStore,
pRegStore->hCertStore);
#if 1
// For subsequent opens, allow subkey create if it doesn't already
// exist.
pRegStore->dwFlags &= ~(CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_CREATE_NEW_FLAG);
#else
// For subsequent opens, allow subkey create if it doesn't already
// exist. However, preserve open existing.
pRegStore->dwFlags &= ~CERT_STORE_CREATE_NEW_FLAG;
#endif
} else if (dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) {
PCERT_REGISTRY_STORE_ROAMING_PARA pRoamingPara =
(PCERT_REGISTRY_STORE_ROAMING_PARA) pvPara;
DWORD cbDir = (wcslen(pRoamingPara->pwszStoreDirectory) + 1) *
sizeof(WCHAR);
if (NULL == (pRegStore->pwszStoreDirectory = (LPWSTR) PkiNonzeroAlloc(
cbDir)))
goto OutOfMemory;
memcpy(pRegStore->pwszStoreDirectory, pRoamingPara->pwszStoreDirectory,
cbDir);
dwFlags &= ~CERT_STORE_CREATE_NEW_FLAG;
dwFlags |= CERT_STORE_OPEN_EXISTING_FLAG;
pRegStore->dwFlags = dwFlags;
if (pRoamingPara->hKey) {
// Make a copy of the input hKey
if (NULL == (pRegStore->hKey = OpenSubKey(
pRoamingPara->hKey,
NULL, // pwszSubKey
dwFlags
)))
goto OpenSubKeyError;
}
fResult = OpenAllFromRegistry(pRegStore, pRegStore->hCertStore);
} else {
// Make a copy of the input hKey
if (NULL == (pRegStore->hKey = OpenSubKey(
hKey,
NULL, // pwszSubKey
(dwFlags & ~CERT_STORE_CREATE_NEW_FLAG) |
CERT_STORE_OPEN_EXISTING_FLAG
)))
goto OpenSubKeyError;
if (dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG)
fResult = OpenAllFromSerializedRegistry(pRegStore,
pRegStore->hCertStore);
else
fResult = OpenAllFromRegistry(pRegStore, pRegStore->hCertStore);
// For subsequent opens, allow subkey create if it doesn't already
// exist.
pRegStore->dwFlags &= ~(CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_CREATE_NEW_FLAG);
}
if (!fResult)
goto OpenAllError;
pStoreProvInfo->cStoreProvFunc = REG_STORE_PROV_FUNC_COUNT;
pStoreProvInfo->rgpvStoreProvFunc = (void **) rgpvRegStoreProvFunc;
pStoreProvInfo->hStoreProv = (HCERTSTOREPROV) pRegStore;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
dwErr = GetLastError();
RegStoreProvClose((HCERTSTOREPROV) pRegStore, 0);
SetLastError(dwErr);
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(OpenSubKeyError)
TRACE_ERROR(OpenAllError)
}
//+-------------------------------------------------------------------------
// Close the registry's store by closing its opened registry subkeys
//--------------------------------------------------------------------------
STATIC void WINAPI RegStoreProvClose(
IN HCERTSTOREPROV hStoreProv,
IN DWORD dwFlags
)
{
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
if (pRegStore) {
CertPerfDecrementStoreRegCurrentCount();
FreeRegistryStoreChange(pRegStore);
if (hWin95NotifyEvent)
Win95StoreSignalAndFreeRegStoreResyncEntries(pRegStore);
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
if (pRegStore->fTouched)
CommitAllToGptRegistry(
pRegStore,
0 // dwFlags
);
FreeGptStoreChangeInfo(&pRegStore->pGptStoreChangeInfo);
GptStoreSignalAndFreeRegStoreResyncEntries(pRegStore);
PkiFree(pRegStore->GptPara.pwszRegPath);
// BUG in NT4.0 and NT5.0. Doesn't support opening of the HKLM with
// a NULL pwszSubKey
if (pRegStore->GptPara.hKeyBase &&
HKEY_LOCAL_MACHINE != pRegStore->GptPara.hKeyBase)
RegCloseKey(pRegStore->GptPara.hKeyBase);
} else if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) {
PkiFree(pRegStore->pwszStoreDirectory);
} else if (pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG) {
if (pRegStore->fTouched)
CommitAllToSerializedRegistry(
pRegStore,
0 // dwFlags
);
}
if (pRegStore->hKey)
RegCloseKey(pRegStore->hKey);
if (pRegStore->hMyNotifyChange)
CloseHandle(pRegStore->hMyNotifyChange);
DeleteCriticalSection(&pRegStore->CriticalSection);
PkiFree(pRegStore);
}
}
//+-------------------------------------------------------------------------
// Read the serialized copy of the context from either the registry or
// a roaming file and create a new context.
//--------------------------------------------------------------------------
STATIC BOOL ReadContext(
IN PREG_STORE pRegStore,
IN DWORD dwContextType,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
OUT const void **ppvContext
)
{
BOOL fResult;
BYTE *pbElement = NULL;
DWORD cbElement;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) {
if (!ILS_ReadElementFromFile(
pRegStore->pwszStoreDirectory,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags,
&pbElement,
&cbElement
))
goto ReadElementFromFileError;
} else {
HKEY hKey;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
if (NULL == (hKey = OpenSubKey(
pRegStore->GptPara.hKeyBase,
pRegStore->GptPara.pwszRegPath,
pRegStore->dwFlags
)))
goto OpenSubKeyError;
} else
hKey = pRegStore->hKey;
fResult = ILS_ReadElementFromRegistry(
hKey,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags,
&pbElement,
&cbElement
);
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
ILS_CloseRegistryKey(hKey);
}
if (!fResult)
goto ReadElementFromRegistryError;
}
if (!CertAddSerializedElementToStore(
NULL, // hCertStore,
pbElement,
cbElement,
CERT_STORE_ADD_ALWAYS,
0, // dwFlags
rgdwContextTypeFlags[dwContextType],
NULL, // pdwContextType
ppvContext))
goto AddSerializedElementError;
CertPerfIncrementRegElementReadCount();
fResult = TRUE;
CommonReturn:
PkiFree(pbElement);
return fResult;
ErrorReturn:
fResult = FALSE;
*ppvContext = NULL;
goto CommonReturn;
TRACE_ERROR(ReadElementFromFileError)
TRACE_ERROR(ReadElementFromRegistryError)
TRACE_ERROR(AddSerializedElementError)
TRACE_ERROR(OpenSubKeyError)
}
//+-------------------------------------------------------------------------
// Write the serialized context and its properties to
// the registry or a roaming file.
//
// Called before the context is written to the store.
//--------------------------------------------------------------------------
STATIC BOOL WriteSerializedContext(
IN PREG_STORE pRegStore,
IN DWORD dwContextType,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN],
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
CertPerfIncrementRegElementWriteCount();
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG)
fResult = ILS_WriteElementToFile(
pRegStore->pwszStoreDirectory,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags,
pbElement,
cbElement
);
else {
HKEY hKey;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
if (NULL == (hKey = OpenSubKey(
pRegStore->GptPara.hKeyBase,
pRegStore->GptPara.pwszRegPath,
pRegStore->dwFlags
)))
return FALSE;
} else
hKey = pRegStore->hKey;
fResult = ILS_WriteElementToRegistry(
hKey,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags,
pbElement,
cbElement
);
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
ILS_CloseRegistryKey(hKey);
}
if (hWin95NotifyEvent && fResult)
PulseEvent(hWin95NotifyEvent);
}
return fResult;
}
//+-------------------------------------------------------------------------
// Delete the context and its properties from the
// the registry or a roaming file.
//
// Called before the context is deleted from the store.
//--------------------------------------------------------------------------
STATIC BOOL DeleteContext(
IN PREG_STORE pRegStore,
IN DWORD dwContextType,
IN const WCHAR wszSubKeyName[MAX_CERT_REG_VALUE_NAME_LEN]
)
{
BOOL fResult;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG)
fResult = ILS_DeleteElementFromDirectory(
pRegStore->pwszStoreDirectory,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags
);
else {
HKEY hKey;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
if (NULL == (hKey = OpenSubKey(
pRegStore->GptPara.hKeyBase,
pRegStore->GptPara.pwszRegPath,
pRegStore->dwFlags
)))
return FALSE;
} else
hKey = pRegStore->hKey;
fResult = ILS_DeleteElementFromRegistry(
hKey,
rgpwszContextSubKeyName[dwContextType],
wszSubKeyName,
pRegStore->dwFlags
);
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
ILS_CloseRegistryKey(hKey);
}
if (hWin95NotifyEvent && fResult)
PulseEvent(hWin95NotifyEvent);
}
CertPerfIncrementRegElementDeleteCount();
if (!fResult) {
DWORD dwErr = GetLastError();
if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)
fResult = TRUE;
}
return fResult;
}
//+-------------------------------------------------------------------------
// Read the serialized copy of the certificate and its properties from
// the registry and create a new certificate context.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvReadCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pStoreCertContext,
IN DWORD dwFlags,
OUT PCCERT_CONTEXT *ppProvCertContext
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsReadSerializedRegistry(pRegStore))
goto UnexpectedReadError;
if (!GetCertRegValueName(pStoreCertContext, wsz))
goto GetRegValueNameError;
fResult = ReadContext(
pRegStore,
CERT_STORE_CERTIFICATE_CONTEXT - 1,
wsz,
(const void **) ppProvCertContext
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
*ppProvCertContext = NULL;
goto CommonReturn;
SET_ERROR(UnexpectedReadError, E_UNEXPECTED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Serialize the encoded certificate and its properties and write to
// the registry.
//
// Called before the certificate is written to the store.
//
// Note, don't set the IEDirtyFlag if setting a property.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvWriteCertEx(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags,
IN BOOL fSetProperty
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
BYTE *pbElement = NULL;
DWORD cbElement;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCertRegValueName(pCertContext, wsz))
goto GetRegValueNameError;
// get the size
if (!CertSerializeCertificateStoreElement(
pCertContext, 0, NULL, &cbElement))
goto SerializeStoreElementError;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
// put it into the buffer
if (!CertSerializeCertificateStoreElement(
pCertContext, 0, pbElement, &cbElement))
goto SerializeStoreElementError;
// write it to the registry or roaming file
fResult = WriteSerializedContext(
pRegStore,
CERT_STORE_CERTIFICATE_CONTEXT - 1,
wsz,
pbElement,
cbElement
);
CommonReturn:
PkiFree(pbElement);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(SerializeStoreElementError)
}
STATIC BOOL WINAPI RegStoreProvWriteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
)
{
return RegStoreProvWriteCertEx(
hStoreProv,
pCertContext,
dwFlags,
FALSE // fSetProperty
);
}
//+-------------------------------------------------------------------------
// Delete the specified certificate from the registry.
//
// Called before the certificate is deleted from the store.
//+-------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvDeleteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsInResync(pRegStore))
// Only delete from store cache, not from registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCertRegValueName(pCertContext, wsz))
goto GetRegValueNameError;
// delete this cert
fResult = DeleteContext(
pRegStore,
CERT_STORE_CERTIFICATE_CONTEXT - 1,
wsz
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Read the specified certificate from the registry and update its
// property.
//
// Note, ignore the CERT_SHA1_HASH_PROP_ID property which is implicitly
// set before we write the certificate to the registry. If we don't ignore,
// we will have indefinite recursion.
//
// Called before setting the property of the certificate in the store.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvSetCertProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
PCCERT_CONTEXT pProvCertContext = NULL;
// This property is implicitly written whenever we do a CertWrite.
if (CERT_SHA1_HASH_PROP_ID == dwPropId)
return TRUE;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
// Create a certificate context from the current serialized value stored
// in the registry.
if (!RegStoreProvReadCert(
hStoreProv,
pCertContext,
0, // dwFlags
&pProvCertContext)) goto ReadError;
// Set the property in the above created certificate context.
if (!CertSetCertificateContextProperty(
pProvCertContext,
dwPropId,
dwFlags,
pvData)) goto SetPropertyError;
// Serialize and write the above updated certificate back to the
// registry.
if (!RegStoreProvWriteCertEx(
hStoreProv,
pProvCertContext,
0, // dwFlags
TRUE // fSetProperty
))
goto WriteError;
fResult = TRUE;
CommonReturn:
CertFreeCertificateContext(pProvCertContext);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(ReadError)
TRACE_ERROR(SetPropertyError)
TRACE_ERROR(WriteError)
}
//+-------------------------------------------------------------------------
// Read the serialized copy of the CRL and its properties from
// the registry and create a new CRL context.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvReadCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pStoreCrlContext,
IN DWORD dwFlags,
OUT PCCRL_CONTEXT *ppProvCrlContext
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsReadSerializedRegistry(pRegStore))
goto UnexpectedReadError;
if (!GetCrlRegValueName(pStoreCrlContext, wsz))
goto GetRegValueNameError;
fResult = ReadContext(
pRegStore,
CERT_STORE_CRL_CONTEXT - 1,
wsz,
(const void **) ppProvCrlContext
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
*ppProvCrlContext = NULL;
goto CommonReturn;
SET_ERROR(UnexpectedReadError, E_UNEXPECTED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Serialize the encoded CRL and its properties and write to
// the registry.
//
// Called before the CRL is written to the store.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvWriteCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
BYTE *pbElement = NULL;
DWORD cbElement;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCrlRegValueName(pCrlContext, wsz))
goto GetRegValueNameError;
// get the size
if (!CertSerializeCRLStoreElement(pCrlContext, 0, NULL, &cbElement))
goto SerializeStoreElementError;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
// put it into the buffer
if (!CertSerializeCRLStoreElement(pCrlContext, 0, pbElement, &cbElement))
goto SerializeStoreElementError;
// write it to the registry or roaming file
fResult = WriteSerializedContext(
pRegStore,
CERT_STORE_CRL_CONTEXT - 1,
wsz,
pbElement,
cbElement
);
CommonReturn:
PkiFree(pbElement);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(SerializeStoreElementError)
}
//+-------------------------------------------------------------------------
// Delete the specified CRL from the registry.
//
// Called before the CRL is deleted from the store.
//+-------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvDeleteCrl(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsInResync(pRegStore))
// Only delete from store cache, not from registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCrlRegValueName(pCrlContext, wsz))
goto GetRegValueNameError;
// delete this CRL
fResult = DeleteContext(
pRegStore,
CERT_STORE_CRL_CONTEXT - 1,
wsz
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Read the specified CRL from the registry and update its
// property.
//
// Note, ignore the CERT_SHA1_HASH_PROP_ID property which is implicitly
// set before we write the CRL to the registry. If we don't ignore,
// we will have indefinite recursion.
//
// Called before setting the property of the CRL in the store.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvSetCrlProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCRL_CONTEXT pCrlContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
PCCRL_CONTEXT pProvCrlContext = NULL;
// This property is implicitly written whenever we do a CertWrite.
if (CERT_SHA1_HASH_PROP_ID == dwPropId)
return TRUE;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
// Create a certificate context from the current serialized value stored
// in the registry.
if (!RegStoreProvReadCrl(
hStoreProv,
pCrlContext,
0, // dwFlags
&pProvCrlContext)) goto ReadError;
// Set the property in the above created certificate context.
if (!CertSetCRLContextProperty(
pProvCrlContext,
dwPropId,
dwFlags,
pvData)) goto SetPropertyError;
// Serialize and write the above updated certificate back to the
// registry.
if (!RegStoreProvWriteCrl(
hStoreProv,
pProvCrlContext,
0)) //dwFlags
goto WriteError;
fResult = TRUE;
CommonReturn:
CertFreeCRLContext(pProvCrlContext);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(ReadError)
TRACE_ERROR(SetPropertyError)
TRACE_ERROR(WriteError)
}
//+-------------------------------------------------------------------------
// Read the serialized copy of the CTL and its properties from
// the registry and create a new CTL context.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvReadCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pStoreCtlContext,
IN DWORD dwFlags,
OUT PCCTL_CONTEXT *ppProvCtlContext
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsReadSerializedRegistry(pRegStore))
goto UnexpectedReadError;
if (!GetCtlRegValueName(pStoreCtlContext, wsz))
goto GetRegValueNameError;
fResult = ReadContext(
pRegStore,
CERT_STORE_CTL_CONTEXT - 1,
wsz,
(const void **) ppProvCtlContext
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
*ppProvCtlContext = NULL;
goto CommonReturn;
SET_ERROR(UnexpectedReadError, E_UNEXPECTED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Serialize the encoded CTL and its properties and write to
// the registry.
//
// Called before the CTL is written to the store.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvWriteCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
BYTE *pbElement = NULL;
DWORD cbElement;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCtlRegValueName(pCtlContext, wsz))
goto GetRegValueNameError;
// get the size
if (!CertSerializeCTLStoreElement(pCtlContext, 0, NULL, &cbElement))
goto SerializeStoreElementError;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
// put it into the buffer
if (!CertSerializeCTLStoreElement(pCtlContext, 0, pbElement, &cbElement))
goto SerializeStoreElementError;
// write it to the registry or roaming file
fResult = WriteSerializedContext(
pRegStore,
CERT_STORE_CTL_CONTEXT - 1,
wsz,
pbElement,
cbElement
);
CommonReturn:
PkiFree(pbElement);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(SerializeStoreElementError)
}
//+-------------------------------------------------------------------------
// Delete the specified CTL from the registry.
//
// Called before the CTL is deleted from the store.
//+-------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvDeleteCtl(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
WCHAR wsz[MAX_CERT_REG_VALUE_NAME_LEN];
assert(pRegStore);
if (IsInResync(pRegStore))
// Only delete from store cache, not from registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
if (!GetCtlRegValueName(pCtlContext, wsz))
goto GetRegValueNameError;
// delete this CTL
fResult = DeleteContext(
pRegStore,
CERT_STORE_CTL_CONTEXT - 1,
wsz
);
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(GetRegValueNameError)
}
//+-------------------------------------------------------------------------
// Read the specified CTL from the registry and update its
// property.
//
// Note, ignore the CERT_SHA1_HASH_PROP_ID property which is implicitly
// set before we write the CTL to the registry. If we don't ignore,
// we will have indefinite recursion.
//
// Called before setting the property of the CTL in the store.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RegStoreProvSetCtlProperty(
IN HCERTSTOREPROV hStoreProv,
IN PCCTL_CONTEXT pCtlContext,
IN DWORD dwPropId,
IN DWORD dwFlags,
IN const void *pvData
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
PCCTL_CONTEXT pProvCtlContext = NULL;
// This property is implicitly written whenever we do a CertWrite.
if (CERT_SHA1_HASH_PROP_ID == dwPropId)
return TRUE;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only update the store cache, don't write back to registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (IsWriteSerializedRegistry(pRegStore))
return TRUE;
// Create a CTL context from the current serialized value stored
// in the registry.
if (!RegStoreProvReadCtl(
hStoreProv,
pCtlContext,
0, // dwFlags
&pProvCtlContext)) goto ReadError;
// Set the property in the above created certificate context.
if (!CertSetCTLContextProperty(
pProvCtlContext,
dwPropId,
dwFlags,
pvData)) goto SetPropertyError;
// Serialize and write the above updated certificate back to the
// registry.
if (!RegStoreProvWriteCtl(
hStoreProv,
pProvCtlContext,
0)) //dwFlags
goto WriteError;
fResult = TRUE;
CommonReturn:
CertFreeCTLContext(pProvCtlContext);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(ReadError)
TRACE_ERROR(SetPropertyError)
TRACE_ERROR(WriteError)
}
//+=========================================================================
// Control functions
//==========================================================================
STATIC BOOL RegNotifyChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
)
{
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG)
return RegRegistryStoreChange(pRegStore, hEvent, dwFlags);
else if (hWin95NotifyEvent)
return RegWin95StoreChange(pRegStore, hEvent, dwFlags);
else if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG)
return RegGptStoreChange(pRegStore, hEvent, dwFlags);
else
return RegRegistryStoreChange(pRegStore, hEvent, dwFlags);
}
STATIC BOOL ResyncFromRegistry(
IN PREG_STORE pRegStore,
IN OPTIONAL HANDLE hEvent,
IN DWORD dwFlags
)
{
BOOL fResult;
HCERTSTORE hNewStore = NULL;
HANDLE hMyNotifyChange;
// Serialize resyncs
LockRegStore(pRegStore);
if (hEvent) {
// Re-arm the specified event
if (!RegNotifyChange(pRegStore, hEvent, dwFlags))
goto NotifyChangeError;
}
hMyNotifyChange = pRegStore->hMyNotifyChange;
if (hMyNotifyChange) {
// Check if any changes since last resync
if (WAIT_TIMEOUT == WaitForSingleObjectEx(
hMyNotifyChange,
0, // dwMilliseconds
FALSE // bAlertable
)) {
// No change
fResult = TRUE;
goto CommonReturn;
} else {
// Re-arm our event handle
if (!RegNotifyChange(pRegStore, hMyNotifyChange,
CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG))
goto NotifyChangeError;
}
}
if (NULL == (hNewStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
0, // dwEncodingType
0, // hCryptProv
CERT_STORE_SHARE_CONTEXT_FLAG,
NULL // pvPara
)))
goto OpenMemoryStoreError;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG) {
fResult = OpenAllFromGptRegistry(pRegStore, hNewStore);
pRegStore->fTouched = FALSE;
} else if (pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG) {
fResult = OpenAllFromSerializedRegistry(pRegStore, hNewStore);
pRegStore->fTouched = FALSE;
} else
fResult = OpenAllFromRegistry(pRegStore, hNewStore);
if (!fResult) {
if (ERROR_KEY_DELETED == GetLastError())
fResult = TRUE;
}
if (fResult) {
if (pRegStore->fProtected) {
BOOL fProtected;
// For the "Root" delete any roots that aren't in the protected root
// list.
if (!IPR_DeleteUnprotectedRootsFromStore(
hNewStore,
&fProtected
)) goto DeleteUnprotectedRootsError;
}
// Set fResync to inhibit the sync from writing back to the registry.
pRegStore->fResync = TRUE;
I_CertSyncStore(pRegStore->hCertStore, hNewStore);
pRegStore->fResync = FALSE;
}
CommonReturn:
UnlockRegStore(pRegStore);
if (hNewStore)
CertCloseStore(hNewStore, 0);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(NotifyChangeError)
TRACE_ERROR(OpenMemoryStoreError)
TRACE_ERROR(DeleteUnprotectedRootsError)
}
STATIC BOOL RegistryNotifyChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
)
{
BOOL fResult;
HANDLE hMyNotifyChange;
BOOL fFirstNotify;
LockRegStore(pRegStore);
hMyNotifyChange = pRegStore->hMyNotifyChange;
if (NULL == hMyNotifyChange) {
// Create "my" event and register it to be signaled for any changes
if (NULL == (hMyNotifyChange = CreateEvent(
NULL, // lpsa
FALSE, // fManualReset
FALSE, // fInitialState
NULL))) // lpszEventName
goto CreateEventError;
// For the first notification, want to ensure the store is in sync.
// Also does a RegNotifyChange
if (!ResyncFromRegistry(pRegStore, hMyNotifyChange,
CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG)) {
DWORD dwErr = GetLastError();
// Bug 484023 Certificate store event handle closed before
// being removed from list.
RegNotifyChange(pRegStore, hMyNotifyChange,
REG_STORE_CTRL_CANCEL_NOTIFY_FLAG);
CloseHandle(hMyNotifyChange);
SetLastError(dwErr);
goto ResyncFromRegistryError;
}
// Note, must update after making the above Resync call to
// force the store to be resync'ed
pRegStore->hMyNotifyChange = hMyNotifyChange;
fFirstNotify = TRUE;
} else
fFirstNotify = FALSE;
if (hEvent) {
if (fFirstNotify ||
0 != (dwFlags & REG_STORE_CTRL_CANCEL_NOTIFY_FLAG)) {
if (!RegNotifyChange(pRegStore, hEvent, dwFlags))
goto NotifyChangeError;
} else {
// For subsequent notification, want to ensure the store
// is in sync. Also does a RegNotifyChange.
if (!ResyncFromRegistry(pRegStore, hEvent, dwFlags))
goto ResyncFromRegistryError;
}
}
fResult = TRUE;
CommonReturn:
UnlockRegStore(pRegStore);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateEventError)
TRACE_ERROR(ResyncFromRegistryError)
TRACE_ERROR(NotifyChangeError)
}
STATIC BOOL WINAPI RegStoreProvControl(
IN HCERTSTOREPROV hStoreProv,
IN DWORD dwFlags,
IN DWORD dwCtrlType,
IN void const *pvCtrlPara
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
switch (dwCtrlType) {
case CERT_STORE_CTRL_RESYNC:
{
HANDLE *phEvent = (HANDLE *) pvCtrlPara;
HANDLE hEvent = phEvent ? *phEvent : NULL;
fResult = ResyncFromRegistry(pRegStore, hEvent, dwFlags);
}
break;
case CERT_STORE_CTRL_NOTIFY_CHANGE:
{
HANDLE *phEvent = (HANDLE *) pvCtrlPara;
HANDLE hEvent = phEvent ? *phEvent : NULL;
fResult = RegistryNotifyChange(pRegStore, hEvent, dwFlags);
}
break;
case CERT_STORE_CTRL_COMMIT:
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_CLIENT_GPT_FLAG)
fResult = CommitAllToGptRegistry(pRegStore, dwFlags);
else if (pRegStore->dwFlags & CERT_REGISTRY_STORE_SERIALIZED_FLAG)
fResult = CommitAllToSerializedRegistry(pRegStore, dwFlags);
else
fResult = TRUE;
break;
case CERT_STORE_CTRL_CANCEL_NOTIFY:
{
HANDLE *phEvent = (HANDLE *) pvCtrlPara;
HANDLE hEvent = phEvent ? *phEvent : NULL;
if (hEvent)
fResult = RegistryNotifyChange(pRegStore, hEvent,
REG_STORE_CTRL_CANCEL_NOTIFY_FLAG);
else
fResult = TRUE;
}
break;
default:
goto NotSupported;
}
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(NotSupported, ERROR_CALL_NOT_IMPLEMENTED)
}
//+=========================================================================
// System and physical store support functions
//==========================================================================
STATIC BOOL HasBackslash(
IN LPCWSTR pwsz
)
{
WCHAR wch;
if (NULL == pwsz)
return FALSE;
while (L'\0' != (wch = *pwsz++)) {
if (L'\\' == wch)
return TRUE;
}
return FALSE;
}
static inline LPCSTR GetSystemStoreLocationOID(
IN DWORD dwFlags
)
{
return (LPCSTR)(DWORD_PTR) ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) >>
CERT_SYSTEM_STORE_LOCATION_SHIFT);
}
static inline DWORD GetSystemStoreLocationID(
IN DWORD dwFlags
)
{
return ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) >>
CERT_SYSTEM_STORE_LOCATION_SHIFT);
}
static inline BOOL IsSystemStoreLocationInRegistry(
IN DWORD dwFlags
)
{
DWORD dwID = GetSystemStoreLocationID(dwFlags);
return (dwID < NUM_SYSTEM_STORE_LOCATION &&
0 == (rgSystemStoreLocationInfo[dwID].dwFlags &
NOT_IN_REGISTRY_SYSTEM_STORE_LOCATION_FLAG));
}
static inline BOOL IsRemotableSystemStoreLocationInRegistry(
IN DWORD dwFlags
)
{
DWORD dwID = GetSystemStoreLocationID(dwFlags);
return (dwID < NUM_SYSTEM_STORE_LOCATION &&
0 != (rgSystemStoreLocationInfo[dwID].dwFlags &
REMOTABLE_SYSTEM_STORE_LOCATION_FLAG));
}
static inline BOOL IsLMSystemStoreLocationInRegistry(
IN DWORD dwFlags
)
{
DWORD dwID = GetSystemStoreLocationID(dwFlags);
return (dwID < NUM_SYSTEM_STORE_LOCATION &&
0 != (rgSystemStoreLocationInfo[dwID].dwFlags &
LM_SYSTEM_STORE_LOCATION_FLAG));
}
static inline BOOL IsSerializedSystemStoreLocationInRegistry(
IN DWORD dwFlags
)
{
DWORD dwID = GetSystemStoreLocationID(dwFlags);
return (dwID < NUM_SYSTEM_STORE_LOCATION &&
0 != (rgSystemStoreLocationInfo[dwID].dwFlags &
SERIALIZED_SYSTEM_STORE_LOCATION_FLAG));
}
STATIC BOOL IsPredefinedSystemStore(
IN LPCWSTR pwszSystemName,
IN DWORD dwFlags
)
{
DWORD i;
DWORD dwCheckFlag;
DWORD dwLocID;
DWORD dwPredefinedSystemFlags;
dwLocID = GetSystemStoreLocationID(dwFlags);
assert(NUM_SYSTEM_STORE_LOCATION > dwLocID);
dwPredefinedSystemFlags =
rgSystemStoreLocationInfo[dwLocID].dwPredefinedSystemFlags;
for (i = 0, dwCheckFlag = 1; i < NUM_PREDEFINED_SYSTEM_STORE;
i++, dwCheckFlag = dwCheckFlag << 1) {
if ((dwCheckFlag & dwPredefinedSystemFlags) &&
0 == _wcsicmp(rgpwszPredefinedSystemStore[i], pwszSystemName))
return TRUE;
}
return FALSE;
}
#define UNICODE_SYSTEM_PROVIDER_FLAG 0x1
#define ASCII_SYSTEM_PROVIDER_FLAG 0x2
#define PHYSICAL_PROVIDER_FLAG 0x4
STATIC DWORD GetSystemProviderFlags(
IN LPCSTR pszStoreProvider
)
{
DWORD dwFlags;
if (0xFFFF < (DWORD_PTR) pszStoreProvider &&
CONST_OID_STR_PREFIX_CHAR == pszStoreProvider[0])
// Convert "#<number>" string to its corresponding constant OID value
pszStoreProvider = (LPCSTR)(DWORD_PTR) atol(pszStoreProvider + 1);
dwFlags = 0;
if (CERT_STORE_PROV_SYSTEM_A == pszStoreProvider)
dwFlags = ASCII_SYSTEM_PROVIDER_FLAG;
else if (CERT_STORE_PROV_SYSTEM_W == pszStoreProvider)
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG;
else if (CERT_STORE_PROV_SYSTEM_REGISTRY_A == pszStoreProvider)
dwFlags = ASCII_SYSTEM_PROVIDER_FLAG;
else if (CERT_STORE_PROV_SYSTEM_REGISTRY_W == pszStoreProvider)
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG;
else if (CERT_STORE_PROV_PHYSICAL_W == pszStoreProvider)
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG | PHYSICAL_PROVIDER_FLAG;
else if (0xFFFF < (DWORD_PTR) pszStoreProvider) {
if (0 == _stricmp(sz_CERT_STORE_PROV_SYSTEM_W, pszStoreProvider))
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG;
else if (0 == _stricmp(sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W,
pszStoreProvider))
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG;
else if (0 == _stricmp(sz_CERT_STORE_PROV_PHYSICAL_W,
pszStoreProvider))
dwFlags = UNICODE_SYSTEM_PROVIDER_FLAG | PHYSICAL_PROVIDER_FLAG;
}
return dwFlags;
}
STATIC LPCSTR ChangeAsciiToUnicodeProvider(
IN LPCSTR pszStoreProvider
)
{
LPCSTR pszUnicodeProvider = NULL;
if (0xFFFF < (DWORD_PTR) pszStoreProvider &&
CONST_OID_STR_PREFIX_CHAR == pszStoreProvider[0])
// Convert "#<number>" string to its corresponding constant OID value
pszStoreProvider = (LPCSTR)(DWORD_PTR) atol(pszStoreProvider + 1);
if (CERT_STORE_PROV_SYSTEM_A == pszStoreProvider)
pszUnicodeProvider = CERT_STORE_PROV_SYSTEM_W;
else if (CERT_STORE_PROV_SYSTEM_REGISTRY_A == pszStoreProvider)
pszUnicodeProvider = CERT_STORE_PROV_SYSTEM_REGISTRY_W;
assert(pszUnicodeProvider);
return pszUnicodeProvider;
}
STATIC void FreeSystemNameInfo(
IN PSYSTEM_NAME_INFO pInfo
)
{
DWORD i;
for (i = 0; i < SYSTEM_NAME_PATH_COUNT; i++) {
if (pInfo->rgpwszName[i]) {
PkiFree(pInfo->rgpwszName[i]);
pInfo->rgpwszName[i] = NULL;
}
}
}
//+-------------------------------------------------------------------------
// If CERT_SYSTEM_STORE_RELOCATE_FLAG is set in dwFlags, then, treat the
// parameter as a pointer to a relocate data structure consisting of
// the relocate HKEY base and the pointer to the system name path.
// Otherwise, treat the parameter as a pointer to the system name path.
//
// Parses and validates the system name path according to the system store
// location and the number of required System and Physical name components.
// All name components are separated by the backslash, "\", character.
//
// Depending on the system store location and the number of required System
// and Physical name components, the system name path can have the following
// name components:
//
// CERT_SYSTEM_STORE_CURRENT_USER or
// CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
// []
// SystemName
// SystemName\PhysicalName
// CERT_SYSTEM_STORE_LOCAL_MACHINE or
// CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY or
// CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
// []
// [[\\]ComputerName]
// [[\\]ComputerName\]SystemName
// [[\\]ComputerName\]SystemName\PhysicalName
// CERT_SYSTEM_STORE_CURRENT_SERVICE
// []
// SystemName
// SystemName\PhysicalName
// CERT_SYSTEM_STORE_SERVICES
// []
// [\\ComputerName]
// [[\\]ComputerName\]
// [ServiceName]
// [[\\]ComputerName\ServiceName]
// [[\\]ComputerName\]ServiceName\SystemName
// [[\\]ComputerName\]ServiceName\SystemName\PhysicalName
// CERT_SYSTEM_STORE_USERS
// []
// [\\ComputerName]
// [[\\]ComputerName\]
// [UserName]
// [[\\]ComputerName\UserName]
// [[\\]ComputerName\]UserName\SystemName
// [[\\]ComputerName\]UserName\SystemName\PhysicalName
//
// For enumeration, where cReqName = 0, all store locations allow the no name
// components option. CERT_SYSTEM_STORE_CURRENT_USER,
// CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY,
// CERT_SYSTEM_CURRENT_SERVICE only allow the no name component option.
//
// The leading \\ before the ComputerName is optional.
//
// A PhysicalName always requires a preceding SystemName.
//
// For CERT_SYSTEM_STORE_SERVICES or CERT_SYSTEM_STORE_USERS,
// for enumeration, if only a single
// name component, then, interpretted as a ServiceName or UserName unless it
// contains a leading \\ or a trailing \, in which case its interpretted as a
// ComputerName. Otherwise, when not enumeration, the ServiceName or UserName
// is required.
//--------------------------------------------------------------------------
STATIC BOOL ParseSystemStorePara(
IN const void *pvPara,
IN DWORD dwFlags,
IN DWORD cReqName, // 0 for enum, 1 for OpenSystem, 2 for OpenPhysical
OUT PSYSTEM_NAME_INFO pInfo
)
{
LPCWSTR pwszPath; // not allocated
BOOL fResult;
DWORD cMaxOptName;
DWORD cMaxTotalName;
DWORD cOptName;
DWORD cTotalName;
BOOL fHasComputerNameBackslashes;
DWORD i;
LPCWSTR pwszEnd;
LPCWSTR pwsz;
LPCWSTR rgpwszStart[SYSTEM_NAME_PATH_COUNT];
DWORD cchName[SYSTEM_NAME_PATH_COUNT];
memset(pInfo, 0, sizeof(*pInfo));
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pRelocatePara =
(PCERT_SYSTEM_STORE_RELOCATE_PARA) pvPara;
if (NULL == pRelocatePara)
goto NullRelocateParaError;
if (NULL == pRelocatePara->hKeyBase)
goto NullRelocateHKEYError;
pInfo->hKeyBase = pRelocatePara->hKeyBase;
pwszPath = pRelocatePara->pwszSystemStore;
} else
pwszPath = (LPCWSTR) pvPara;
if (NULL == pwszPath || L'\0' == *pwszPath) {
if (0 == cReqName)
goto SuccessReturn;
else
goto MissingSystemName;
}
dwFlags &= CERT_SYSTEM_STORE_LOCATION_MASK;
switch (dwFlags) {
case CERT_SYSTEM_STORE_CURRENT_USER:
case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
case CERT_SYSTEM_STORE_CURRENT_SERVICE:
cMaxOptName = 0;
break;
case CERT_SYSTEM_STORE_LOCAL_MACHINE:
case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
cMaxOptName = 1; // Allow ComputerName
break;
case CERT_SYSTEM_STORE_SERVICES:
case CERT_SYSTEM_STORE_USERS:
// Allow ComputerName and/or ServiceOrUserName
cMaxOptName = 2;
break;
default:
goto InvalidStoreLocation;
}
cMaxTotalName = cReqName + cMaxOptName;
assert(cReqName <= SERVICE_NAME_INDEX);
assert(cMaxTotalName <= SYSTEM_NAME_PATH_COUNT);
if (0 == cMaxTotalName)
goto MachineOrServiceNameNotAllowed;
if (L'\\' == pwszPath[0] && L'\\' == pwszPath[1]) {
pwszPath += 2;
fHasComputerNameBackslashes = TRUE;
} else
fHasComputerNameBackslashes = FALSE;
// Starting at the end, get up through cMaxTotalName strings separated
// by backslashes. Note, don't parse the left-most name component. This
// allows a ComputerName to contain embedded backslashes.
pwszEnd = pwszPath + wcslen(pwszPath);
pwsz = pwszEnd;
cTotalName = 0;
while (cTotalName < cMaxTotalName - 1) {
while (pwsz > pwszPath && L'\\' != *pwsz)
pwsz--;
if (L'\\' != *pwsz) {
// Left-most name component.
assert(pwsz == pwszPath);
break;
}
assert(L'\\' == *pwsz);
cchName[cTotalName] = (DWORD)(pwszEnd - pwsz) - 1; // exclude "\"
rgpwszStart[cTotalName] = pwsz + 1; // exclude "\"
cTotalName++;
pwszEnd = pwsz; // remember pointer to "\"
if (pwsz == pwszPath)
// Left-most name component is empty
break;
pwsz--; // skip before the "\"
}
// Left-most name component. Note, it may have embedded backslashes
cchName[cTotalName] = (DWORD)(pwszEnd - pwszPath);
rgpwszStart[cTotalName] = pwszPath;
cTotalName++;
if (cTotalName < cReqName)
goto MissingSystemOrPhysicalName;
// Allocate and copy the required name components
for (i = 0; i < cReqName; i++) {
if (0 == cchName[i])
goto EmptySystemOrPhysicalName;
if (NULL == (pInfo->rgpwszName[SERVICE_NAME_INDEX - cReqName + i] =
ILS_AllocAndCopyString(rgpwszStart[i], cchName[i])))
goto OutOfMemory;
}
cOptName = cTotalName - cReqName;
assert(cOptName || cReqName);
if (0 == cOptName) {
assert(cReqName);
// No ComputerName and/or ServiceName prefix
// Check if left-most name component (SystemName) has any backslashes
assert(pInfo->rgpwszName[SYSTEM_NAME_INDEX]);
if (fHasComputerNameBackslashes || HasBackslash(
pInfo->rgpwszName[SYSTEM_NAME_INDEX]))
goto InvalidBackslashInSystemName;
if (CERT_SYSTEM_STORE_SERVICES == dwFlags ||
CERT_SYSTEM_STORE_USERS == dwFlags)
// For non-enumeration, require the ServiceName
goto MissingServiceOrUserName;
} else {
if (CERT_SYSTEM_STORE_SERVICES == dwFlags ||
CERT_SYSTEM_STORE_USERS == dwFlags) {
// ServiceName or UserName prefix
if (0 == cchName[cReqName] ||
(1 == cOptName && fHasComputerNameBackslashes)) {
if (0 != cReqName)
goto MissingServiceOrUserName;
// else
// ComputerName only Enumeration with either:
// ComputerName\ <- trailing backslash
// \\ComputerName <- leading backslashes
// \\ComputerName\ <- both
} else {
if (NULL == (pInfo->rgpwszName[SERVICE_NAME_INDEX] =
ILS_AllocAndCopyString(rgpwszStart[cReqName],
cchName[cReqName])))
goto OutOfMemory;
}
}
if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwFlags ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY == dwFlags ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE == dwFlags ||
2 == cOptName || fHasComputerNameBackslashes) {
// ComputerName prefix
DWORD cchComputer = cchName[cTotalName - 1];
if (0 == cchComputer)
goto EmptyComputerName;
if (pInfo->hKeyBase)
goto BothRemoteAndRelocateNotAllowed;
if (NULL == (pInfo->rgpwszName[COMPUTER_NAME_INDEX] =
(LPWSTR) PkiNonzeroAlloc(
(2 + cchComputer + 1) * sizeof(WCHAR))))
goto OutOfMemory;
wcscpy(pInfo->rgpwszName[COMPUTER_NAME_INDEX], L"\\\\");
memcpy((BYTE *) (pInfo->rgpwszName[COMPUTER_NAME_INDEX] + 2),
(BYTE *) rgpwszStart[cTotalName -1],
cchComputer * sizeof(WCHAR));
*(pInfo->rgpwszName[COMPUTER_NAME_INDEX] + 2 + cchComputer) = L'\0';
}
}
SuccessReturn:
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
FreeSystemNameInfo(pInfo);
fResult = FALSE;
goto CommonReturn;
SET_ERROR(MissingSystemName, E_INVALIDARG)
SET_ERROR(NullRelocateParaError, E_INVALIDARG)
SET_ERROR(NullRelocateHKEYError, E_INVALIDARG)
SET_ERROR(MissingSystemOrPhysicalName, E_INVALIDARG)
SET_ERROR(InvalidStoreLocation, E_INVALIDARG)
SET_ERROR(MachineOrServiceNameNotAllowed, E_INVALIDARG)
SET_ERROR(EmptySystemOrPhysicalName, E_INVALIDARG)
SET_ERROR(InvalidBackslashInSystemName, E_INVALIDARG)
SET_ERROR(MissingServiceOrUserName, E_INVALIDARG)
SET_ERROR(EmptyComputerName, E_INVALIDARG)
SET_ERROR(BothRemoteAndRelocateNotAllowed, E_INVALIDARG)
TRACE_ERROR(OutOfMemory)
}
typedef struct _SYSTEM_NAME_GROUP {
DWORD cName;
LPCWSTR *rgpwszName;
} SYSTEM_NAME_GROUP, *PSYSTEM_NAME_GROUP;
//+-------------------------------------------------------------------------
// Formats a System Name Path by concatenating together the name components
// with an intervening "\" separator.
//--------------------------------------------------------------------------
STATIC LPWSTR FormatSystemNamePath(
IN DWORD cNameGroup,
IN SYSTEM_NAME_GROUP rgNameGroup[]
)
{
DWORD cchPath;
LPWSTR pwszPath;
BOOL fFirst;
DWORD iGroup;
// First, get total length of formatted path
cchPath = 0;
fFirst = TRUE;
for (iGroup = 0; iGroup < cNameGroup; iGroup++) {
DWORD iName;
for (iName = 0; iName < rgNameGroup[iGroup].cName; iName++) {
LPCWSTR pwszName = rgNameGroup[iGroup].rgpwszName[iName];
if (pwszName && *pwszName) {
if (fFirst)
fFirst = FALSE;
else
cchPath++; // "\" separator
cchPath += wcslen(pwszName);
}
}
}
cchPath++; // "\0" terminator
if (NULL == (pwszPath = (LPWSTR) PkiNonzeroAlloc(cchPath * sizeof(WCHAR))))
return NULL;
// Now do concatenated copies with intervening '\'
fFirst = TRUE;
for (iGroup = 0; iGroup < cNameGroup; iGroup++) {
DWORD iName;
for (iName = 0; iName < rgNameGroup[iGroup].cName; iName++) {
LPCWSTR pwszName = rgNameGroup[iGroup].rgpwszName[iName];
if (pwszName && *pwszName) {
if (fFirst) {
wcscpy(pwszPath, pwszName);
fFirst = FALSE;
} else {
wcscat(pwszPath, L"\\");
wcscat(pwszPath, pwszName);
}
}
}
}
if (fFirst)
// Empty string
*pwszPath = L'\0';
return pwszPath;
}
//+-------------------------------------------------------------------------
// If the SystemNameInfo has a non-NULL hKeyBase, then, the returned
// pvPara is a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA containing both
// the hKeyBase and the formatted system name path. Otherwise, returns
// pointer to only the formatted system name path.
//
// Calls the above FormatSystemNamePath() to do the actual formatting.
//--------------------------------------------------------------------------
STATIC void * FormatSystemNamePara(
IN DWORD cNameGroup,
IN SYSTEM_NAME_GROUP rgNameGroup[],
IN PSYSTEM_NAME_INFO pSystemNameInfo
)
{
if (NULL == pSystemNameInfo->hKeyBase)
return FormatSystemNamePath(cNameGroup, rgNameGroup);
else {
PCERT_SYSTEM_STORE_RELOCATE_PARA pRelocatePara;
if (NULL == (pRelocatePara =
(PCERT_SYSTEM_STORE_RELOCATE_PARA) PkiNonzeroAlloc(
sizeof(CERT_SYSTEM_STORE_RELOCATE_PARA))))
return NULL;
pRelocatePara->hKeyBase = pSystemNameInfo->hKeyBase;
if (NULL == (pRelocatePara->pwszSystemStore = FormatSystemNamePath(
cNameGroup, rgNameGroup))) {
PkiFree(pRelocatePara);
return NULL;
} else
return pRelocatePara;
}
}
STATIC void FreeSystemNamePara(
IN void *pvSystemNamePara,
IN PSYSTEM_NAME_INFO pSystemNameInfo
)
{
if (pvSystemNamePara) {
if (pSystemNameInfo->hKeyBase) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pRelocatePara =
(PCERT_SYSTEM_STORE_RELOCATE_PARA) pvSystemNamePara;
PkiFree((LPWSTR) pRelocatePara->pwszSystemStore);
}
PkiFree(pvSystemNamePara);
}
}
//+-------------------------------------------------------------------------
// Localizes the physical, system and service name components. If unable
// to find a localized name string, uses the unlocalized name component.
//
// Re-formats the system name path with intervening backslashes and
// sets the store's CERT_STORE_LOCALIZED_NAME_PROP_ID property.
//--------------------------------------------------------------------------
STATIC void SetLocalizedNameStoreProperty(
IN HCERTSTORE hCertStore,
IN PSYSTEM_NAME_INFO pSystemNameInfo
)
{
LPWSTR pwszLocalizedPath = NULL;
LPCWSTR rgpwszLocalizedName[SYSTEM_NAME_PATH_COUNT];
SYSTEM_NAME_GROUP NameGroup;
CRYPT_DATA_BLOB Property;
DWORD i;
// Except for the computer name, try to get localized name components.
// If unable to find a localized name, use the original name component.
for (i = 0; i < SYSTEM_NAME_PATH_COUNT; i++) {
LPCWSTR pwszName;
LPCWSTR pwszLocalizedName;
pwszName = pSystemNameInfo->rgpwszName[i];
if (NULL == pwszName || COMPUTER_NAME_INDEX == i)
pwszLocalizedName = pwszName;
else {
// Returned pwszLocalizedName isn't allocated
if (NULL == (pwszLocalizedName = CryptFindLocalizedName(
pwszName)) || L'\0' == *pwszLocalizedName)
pwszLocalizedName = pwszName;
}
// Before formatting, need to reverse.
rgpwszLocalizedName[SYSTEM_NAME_PATH_COUNT - 1 - i] =
pwszLocalizedName;
}
NameGroup.cName = SYSTEM_NAME_PATH_COUNT;
NameGroup.rgpwszName = rgpwszLocalizedName;
if (NULL == (pwszLocalizedPath = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
Property.pbData = (BYTE *) pwszLocalizedPath;
Property.cbData = (wcslen(pwszLocalizedPath) + 1) * sizeof(WCHAR);
if (!CertSetStoreProperty(
hCertStore,
CERT_STORE_LOCALIZED_NAME_PROP_ID,
0, // dwFlags
(const void *) &Property
))
goto SetStorePropertyError;
CommonReturn:
PkiFree(pwszLocalizedPath);
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(FormatSystemNamePathError)
TRACE_ERROR(SetStorePropertyError)
}
//+-------------------------------------------------------------------------
// For NT, get the formatted SID. For Win95, get the current user name.
//--------------------------------------------------------------------------
STATIC LPWSTR GetCurrentServiceOrUserName()
{
LPWSTR pwszCurrentService = NULL;
if (!FIsWinNT()) {
DWORD cch = _MAX_PATH;
if (NULL == (pwszCurrentService = (LPWSTR) PkiNonzeroAlloc(
(cch + 1) * sizeof(WCHAR))))
goto OutOfMemory;
if (!GetUserNameU(pwszCurrentService, &cch))
goto GetUserNameError;
} else {
DWORD cch = 256;
if (NULL == (pwszCurrentService = (LPWSTR) PkiNonzeroAlloc(
(cch + 1) * sizeof(WCHAR))))
goto OutOfMemory;
if (!GetUserTextualSidHKCU(pwszCurrentService, &cch)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto GetUserTextualSidHKUCError;
PkiFree(pwszCurrentService);
if (NULL == (pwszCurrentService = (LPWSTR) PkiNonzeroAlloc(
(cch + 1) * sizeof(WCHAR))))
goto OutOfMemory;
if (!GetUserTextualSidHKCU(pwszCurrentService, &cch))
goto GetUserTextualSidHKUCError;
}
}
CommonReturn:
return pwszCurrentService;
ErrorReturn:
if (pwszCurrentService)
wcscpy(pwszCurrentService, DEFAULT_USER_NAME);
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(GetUserNameError)
TRACE_ERROR(GetUserTextualSidHKUCError)
}
//+-------------------------------------------------------------------------
// For NT and Win95, get the computer name
//--------------------------------------------------------------------------
STATIC LPWSTR GetCurrentComputerName()
{
LPWSTR pwszCurrentComputer = NULL;
DWORD cch = _MAX_PATH;
if (NULL == (pwszCurrentComputer = (LPWSTR) PkiNonzeroAlloc(
(cch + 1) * sizeof(WCHAR))))
goto OutOfMemory;
if (!GetComputerNameU(pwszCurrentComputer, &cch))
goto GetComputerNameError;
CommonReturn:
return pwszCurrentComputer;
ErrorReturn:
PkiFree(pwszCurrentComputer);
pwszCurrentComputer = NULL;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(GetComputerNameError)
}
//+-------------------------------------------------------------------------
// Uses the store location in the upper word of dwFlags, the parsed
// System Name components consisting of: computer, service/user, system and
// physical names, and the optional SubKey name to open the appropriate
// registry key. If the Computer name is non-NULL, does a RegConnectRegistry
// to connect a registry key on a remote computer. If the hKeyBase is
// non-NULL, does a relocated open instead of using HKCU or HKLM.
//--------------------------------------------------------------------------
STATIC LPWSTR FormatSystemRegPath(
IN PSYSTEM_NAME_INFO pInfo,
IN OPTIONAL LPCWSTR pwszSubKeyName,
IN DWORD dwFlags,
OUT HKEY *phKey
)
{
LONG err;
HKEY hKey = NULL;
LPWSTR pwszRegPath = NULL;
LPWSTR pwszCurrentService = NULL;
DWORD dwStoreLocation;
SYSTEM_NAME_GROUP rgNameGroup[3];
DWORD cNameGroup;
LPCWSTR rgpwszService[3];
LPCWSTR rgpwszUser[2];
LPCWSTR rgpwszStore[3];
if (pwszSubKeyName) {
cNameGroup = 3;
rgNameGroup[2].cName = 1;
rgNameGroup[2].rgpwszName = &pwszSubKeyName;
} else
cNameGroup = 2;
dwStoreLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
switch (dwStoreLocation) {
case CERT_SYSTEM_STORE_CURRENT_SERVICE:
case CERT_SYSTEM_STORE_SERVICES:
rgNameGroup[0].cName = 3;
rgNameGroup[0].rgpwszName = rgpwszService;
rgpwszService[0] = SERVICES_REGPATH;
rgpwszService[2] = SYSTEM_CERTIFICATES_SUBKEY_NAME;
if (CERT_SYSTEM_STORE_CURRENT_SERVICE == dwStoreLocation) {
assert(NULL == pInfo->rgpwszName[COMPUTER_NAME_INDEX]);
assert(NULL == pInfo->rgpwszName[SERVICE_NAME_INDEX]);
if (NULL == (pwszCurrentService =
GetCurrentServiceOrUserName()))
goto GetCurrentServiceNameError;
rgpwszService[1] = pwszCurrentService;
} else {
if (NULL == pInfo->rgpwszName[SERVICE_NAME_INDEX]) {
// May be NULL for CertEnumSystemStore
assert(NULL == pInfo->rgpwszName[SYSTEM_NAME_INDEX]);
assert(NULL == pInfo->rgpwszName[PHYSICAL_NAME_INDEX]);
rgNameGroup[0].cName = 1;
} else
rgpwszService[1] = pInfo->rgpwszName[SERVICE_NAME_INDEX];
}
break;
case CERT_SYSTEM_STORE_CURRENT_USER:
case CERT_SYSTEM_STORE_LOCAL_MACHINE:
rgpwszUser[0] = SYSTEM_STORE_REGPATH;
rgNameGroup[0].cName = 1;
rgNameGroup[0].rgpwszName = rgpwszUser;
break;
case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
rgpwszUser[0] = GROUP_POLICY_STORE_REGPATH;
rgNameGroup[0].cName = 1;
rgNameGroup[0].rgpwszName = rgpwszUser;
break;
case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
rgpwszUser[0] = ENTERPRISE_STORE_REGPATH;
rgNameGroup[0].cName = 1;
rgNameGroup[0].rgpwszName = rgpwszUser;
break;
case CERT_SYSTEM_STORE_USERS:
if (NULL == pInfo->rgpwszName[USER_NAME_INDEX]) {
// May be NULL for CertEnumSystemStore
assert(NULL == pInfo->rgpwszName[SYSTEM_NAME_INDEX]);
assert(NULL == pInfo->rgpwszName[PHYSICAL_NAME_INDEX]);
rgNameGroup[0].cName = 0;
} else {
rgpwszUser[0] = pInfo->rgpwszName[USER_NAME_INDEX];
rgpwszUser[1] = SYSTEM_STORE_REGPATH;
rgNameGroup[0].cName = 2;
rgNameGroup[0].rgpwszName = rgpwszUser;
}
break;
default:
goto InvalidArg;
}
rgNameGroup[1].rgpwszName = rgpwszStore;
rgpwszStore[0] = pInfo->rgpwszName[SYSTEM_NAME_INDEX];
if (pInfo->rgpwszName[PHYSICAL_NAME_INDEX]) {
assert(pInfo->rgpwszName[SYSTEM_NAME_INDEX]);
rgNameGroup[1].cName = 3;
rgpwszStore[1] = PHYSICAL_STORES_SUBKEY_NAME;
rgpwszStore[2] = pInfo->rgpwszName[PHYSICAL_NAME_INDEX];
} else
rgNameGroup[1].cName = 1;
if (pInfo->rgpwszName[COMPUTER_NAME_INDEX]) {
assert(IsRemotableSystemStoreLocationInRegistry(dwFlags));
assert(NULL == pInfo->hKeyBase);
if (ERROR_SUCCESS != (err = RegConnectRegistryU(
pInfo->rgpwszName[COMPUTER_NAME_INDEX],
(CERT_SYSTEM_STORE_USERS == dwStoreLocation) ?
HKEY_USERS : HKEY_LOCAL_MACHINE,
&hKey)))
goto RegConnectRegistryError;
} else if (pInfo->hKeyBase) {
assert(dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG);
hKey = pInfo->hKeyBase;
} else {
switch (dwStoreLocation) {
case CERT_SYSTEM_STORE_CURRENT_USER:
case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
hKey = HKEY_CURRENT_USER;
break;
case CERT_SYSTEM_STORE_LOCAL_MACHINE:
case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
case CERT_SYSTEM_STORE_CURRENT_SERVICE:
case CERT_SYSTEM_STORE_SERVICES:
hKey = HKEY_LOCAL_MACHINE;
break;
case CERT_SYSTEM_STORE_USERS:
hKey = HKEY_USERS;
break;
default:
goto InvalidArg;
}
}
if (NULL == (pwszRegPath = FormatSystemNamePath(
cNameGroup,
rgNameGroup
)))
goto FormatSystemNamePathError;
CommonReturn:
PkiFree(pwszCurrentService);
*phKey = hKey;
return pwszRegPath;
ErrorReturn:
pwszRegPath = NULL;
goto CommonReturn;
TRACE_ERROR(GetCurrentServiceNameError)
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR_VAR(RegConnectRegistryError, err)
TRACE_ERROR(FormatSystemNamePathError)
}
STATIC HKEY OpenSystemRegPathKey(
IN PSYSTEM_NAME_INFO pInfo,
IN OPTIONAL LPCWSTR pwszSubKeyName,
IN DWORD dwFlags
)
{
LPWSTR pwszRegPath;
HKEY hKey = NULL;
HKEY hKeyRegPath;
if (NULL == (pwszRegPath = FormatSystemRegPath(
pInfo,
pwszSubKeyName,
dwFlags,
&hKey
)))
goto FormatSystemRegPathError;
hKeyRegPath = OpenSubKey(
hKey,
pwszRegPath,
dwFlags
);
CommonReturn:
PkiFree(pwszRegPath);
if (pInfo->rgpwszName[COMPUTER_NAME_INDEX] && hKey)
ILS_CloseRegistryKey(hKey);
return hKeyRegPath;
ErrorReturn:
hKeyRegPath = NULL;
goto CommonReturn;
TRACE_ERROR(FormatSystemRegPathError)
}
STATIC HKEY OpenSystemStore(
IN const void *pvPara,
IN DWORD dwFlags
)
{
HKEY hKey;
SYSTEM_NAME_INFO SystemNameInfo;
if (!ParseSystemStorePara(
pvPara,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags
);
CommonReturn:
FreeSystemNameInfo(&SystemNameInfo);
return hKey;
ErrorReturn:
hKey = NULL;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
}
STATIC HKEY OpenPhysicalStores(
IN const void *pvPara,
IN DWORD dwFlags
)
{
HKEY hKey;
SYSTEM_NAME_INFO SystemNameInfo;
if (!ParseSystemStorePara(
pvPara,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
hKey = OpenSystemRegPathKey(
&SystemNameInfo,
PHYSICAL_STORES_SUBKEY_NAME,
dwFlags
);
CommonReturn:
FreeSystemNameInfo(&SystemNameInfo);
return hKey;
ErrorReturn:
hKey = NULL;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
}
//+-------------------------------------------------------------------------
// Register a system store.
//
// The upper word of the dwFlags parameter is used to specify the location of
// the system store.
//
// Set CERT_STORE_CREATE_NEW_FLAG to cause a failure if the system store
// already exists in the store location.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertRegisterSystemStore(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN PCERT_SYSTEM_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved
)
{
BOOL fResult;
HKEY hKey;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[REGISTER_SYSTEM_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_REGISTER_SYSTEM_STORE) pvFuncAddr)(
pvSystemStore,
dwFlags,
pStoreInfo,
pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (dwFlags & ~REGISTER_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (NULL == (hKey = OpenSystemStore(pvSystemStore, dwFlags)))
goto OpenSystemStoreError;
RegCloseKey(hKey);
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(OpenSystemStoreError)
}
//+-------------------------------------------------------------------------
// Register a physical store for the specified system store.
//
// The upper word of the dwFlags parameter is used to specify the location of
// the system store.
//
// Set CERT_STORE_CREATE_NEW_FLAG to cause a failure if the physical store
// already exists in the system store.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertRegisterPhysicalStore(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN LPCWSTR pwszStoreName,
IN PCERT_PHYSICAL_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved
)
{
BOOL fResult;
LONG err;
HKEY hKey = NULL;
SYSTEM_NAME_INFO SystemNameInfo;
char szOID[34];
LPCSTR pszOID;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[REGISTER_PHYSICAL_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_REGISTER_PHYSICAL_STORE) pvFuncAddr)(
pvSystemStore,
dwFlags,
pwszStoreName,
pStoreInfo,
pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (!ParseSystemStorePara(
pvSystemStore,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
if (NULL == pwszStoreName || L'\0' == *pwszStoreName ||
HasBackslash(pwszStoreName))
goto InvalidArg;
assert(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX]);
assert(NULL == SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX]);
SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX] = (LPWSTR) pwszStoreName;
if (dwFlags & ~REGISTER_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (NULL == pStoreInfo ||
sizeof(CERT_PHYSICAL_STORE_INFO) > pStoreInfo->cbSize)
goto InvalidArg;
if (NULL == (hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags
)))
goto OpenSystemRegPathKeyError;
pszOID = pStoreInfo->pszOpenStoreProvider;
if (0xFFFF >= (DWORD_PTR) pszOID) {
// Convert to "#<number>" string
szOID[0] = CONST_OID_STR_PREFIX_CHAR;
_ltoa((long) ((DWORD_PTR) pszOID), szOID + 1, 10);
pszOID = szOID;
}
if (ERROR_SUCCESS != (err = RegSetValueExA(
hKey,
"OpenStoreProvider",
0, // dwReserved
REG_SZ,
(BYTE *) pszOID,
strlen(pszOID) + 1)))
goto RegSetOpenStoreProviderError;
if (!WriteDWORDValueToRegistry(
hKey,
L"OpenEncodingType",
pStoreInfo->dwOpenEncodingType))
goto WriteDWORDError;
if (!WriteDWORDValueToRegistry(
hKey,
L"OpenFlags",
pStoreInfo->dwOpenFlags))
goto WriteDWORDError;
if (ERROR_SUCCESS != (err = RegSetValueExU(
hKey,
L"OpenParameters",
0, // dwReserved
REG_BINARY,
pStoreInfo->OpenParameters.pbData,
pStoreInfo->OpenParameters.cbData)))
goto RegSetOpenParametersError;
if (!WriteDWORDValueToRegistry(
hKey,
L"Flags",
pStoreInfo->dwFlags))
goto WriteDWORDError;
if (!WriteDWORDValueToRegistry(
hKey,
L"Priority",
pStoreInfo->dwPriority))
goto WriteDWORDError;
fResult = TRUE;
CommonReturn:
SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX] = NULL; // not allocated
FreeSystemNameInfo(&SystemNameInfo);
ILS_CloseRegistryKey(hKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(ParseSystemStoreParaError)
TRACE_ERROR(OpenSystemRegPathKeyError)
SET_ERROR_VAR(RegSetOpenStoreProviderError, err)
SET_ERROR_VAR(RegSetOpenParametersError, err)
TRACE_ERROR(WriteDWORDError)
}
//+-------------------------------------------------------------------------
// Unregister the specified system store.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertUnregisterSystemStore(
IN const void *pvSystemStore,
IN DWORD dwFlags
)
{
BOOL fResult;
HKEY hKey = NULL;
SYSTEM_NAME_INFO SystemNameInfo;
LPWSTR pwszStore; // not allocated
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[UNREGISTER_SYSTEM_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_UNREGISTER_SYSTEM_STORE) pvFuncAddr)(
pvSystemStore,
dwFlags
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (!ParseSystemStorePara(
pvSystemStore,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
if (dwFlags & ~UNREGISTER_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
// Delete the SystemRegistry components
if (NULL == (hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG
)))
goto OpenSystemRegPathKeyError;
if (!DeleteAllFromRegistry(
hKey,
(dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) |
(SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX] ?
CERT_REGISTRY_STORE_REMOTE_FLAG : 0)
))
goto DeleteAllError;
RegCloseKey(hKey);
hKey = NULL;
// Open SystemCertificates SubKey preceding the store. In order to do this
// the SYSTEM_NAME component must be NULL.
assert(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX]);
pwszStore = SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX];
SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX] = NULL;
hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG
);
SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX] = pwszStore;
if (NULL == hKey)
goto OpenSystemRegPathKeyError;
// Delete the remaining System components (such as PhysicalStores) and
// the System store itself
if (!RecursiveDeleteSubKey(hKey, pwszStore, dwFlags))
goto DeleteSubKeyError;
fResult = TRUE;
CommonReturn:
FreeSystemNameInfo(&SystemNameInfo);
ILS_CloseRegistryKey(hKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(DeleteAllError)
TRACE_ERROR(OpenSystemRegPathKeyError)
TRACE_ERROR(DeleteSubKeyError)
}
//+-------------------------------------------------------------------------
// Unregister the physical store from the specified system store.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertUnregisterPhysicalStore(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN LPCWSTR pwszStoreName
)
{
BOOL fResult;
HKEY hKey = NULL;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[UNREGISTER_PHYSICAL_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_UNREGISTER_PHYSICAL_STORE) pvFuncAddr)(
pvSystemStore,
dwFlags,
pwszStoreName
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (dwFlags & ~UNREGISTER_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (NULL == (hKey = OpenPhysicalStores(
pvSystemStore,
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG
)))
goto OpenPhysicalStoresError;
if (!RecursiveDeleteSubKey(hKey, pwszStoreName, dwFlags))
goto DeleteSubKeyError;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hKey);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(OpenPhysicalStoresError)
TRACE_ERROR(DeleteSubKeyError)
}
typedef struct _ENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO {
DWORD dwLastError;
void *pvArg;
PFN_CERT_ENUM_SYSTEM_STORE_LOCATION pfnEnum;
} ENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO,
*PENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO;
STATIC BOOL WINAPI EnumRegisteredSystemStoreLocationCallback(
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
)
{
PENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO pEnumRegisteredInfo =
(PENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO) pvArg;
LPCWSTR pwszLocation = L"";
DWORD dwFlags;
if (0 != pEnumRegisteredInfo->dwLastError)
return FALSE;
if (CONST_OID_STR_PREFIX_CHAR != *pszOID)
return TRUE;
dwFlags =
(((DWORD) atol(pszOID + 1)) << CERT_SYSTEM_STORE_LOCATION_SHIFT) &
CERT_SYSTEM_STORE_LOCATION_MASK;
if (0 == dwFlags)
return TRUE;
// Try to find the SystemStoreLocation value
while (cValue--) {
if (0 == _wcsicmp(rgpwszValueName[cValue],
CRYPT_OID_SYSTEM_STORE_LOCATION_VALUE_NAME) &&
REG_SZ == rgdwValueType[cValue]) {
pwszLocation = (LPCWSTR) rgpbValueData[cValue];
break;
}
}
if (!pEnumRegisteredInfo->pfnEnum(
pwszLocation,
dwFlags,
NULL, // pvReserved
pEnumRegisteredInfo->pvArg
)) {
if (0 == (pEnumRegisteredInfo->dwLastError = GetLastError()))
pEnumRegisteredInfo->dwLastError = (DWORD) E_UNEXPECTED;
return FALSE;
} else
return TRUE;
}
//+-------------------------------------------------------------------------
// Enumerate the system store locations.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertEnumSystemStoreLocation(
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CERT_ENUM_SYSTEM_STORE_LOCATION pfnEnum
)
{
DWORD i;
ENUM_REGISTERED_SYSTEM_STORE_LOCATION_INFO EnumRegisteredInfo;
if (dwFlags & ~ENUM_FLAGS_MASK) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
// Enumerate through the predefined, crypt32.dll system store locations
for (i = 0; i < ENUM_SYSTEM_STORE_LOCATION_CNT; i++) {
if (!pfnEnum(
rgEnumSystemStoreLocationInfo[i].pwszLocation,
rgEnumSystemStoreLocationInfo[i].dwFlags,
NULL, // pvReserved
pvArg
))
return FALSE;
}
// Enumerate through the registered system store locations
EnumRegisteredInfo.dwLastError = 0;
EnumRegisteredInfo.pvArg = pvArg;
EnumRegisteredInfo.pfnEnum = pfnEnum;
CryptEnumOIDFunction(
0, // dwEncodingType
CRYPT_OID_ENUM_SYSTEM_STORE_FUNC,
NULL, // pszOID
0, // dwFlags
(void *) &EnumRegisteredInfo, // pvArg
EnumRegisteredSystemStoreLocationCallback
);
if (0 != EnumRegisteredInfo.dwLastError) {
SetLastError(EnumRegisteredInfo.dwLastError);
return FALSE;
} else
return TRUE;
}
STATIC BOOL EnumServicesOrUsersSystemStore(
IN OUT PSYSTEM_NAME_INFO pLocationNameInfo,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CERT_ENUM_SYSTEM_STORE pfnEnum
)
{
BOOL fResult;
HKEY hKey = NULL;
DWORD cSubKeys;
DWORD cchMaxSubKey;
LPWSTR pwszEnumServiceName = NULL;
void *pvEnumServicePara = NULL;
BOOL fDidEnum;
assert(NULL == pLocationNameInfo->rgpwszName[SERVICE_NAME_INDEX]);
// Opens ..\Cryptography\Services SubKey or HKEY_USERS SubKey
if (NULL == (hKey = OpenSystemRegPathKey(
pLocationNameInfo,
NULL, // pwszSubKeyName
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG
)))
goto OpenSystemRegPathKeyError;
if (!GetSubKeyInfo(
hKey,
&cSubKeys,
&cchMaxSubKey
))
goto GetSubKeyInfoError;
// Enumerates the ServiceOrUserNames
fDidEnum = FALSE;
if (cSubKeys && cchMaxSubKey) {
DWORD i;
LPCWSTR rgpwszEnumName[2];
SYSTEM_NAME_GROUP EnumNameGroup;
EnumNameGroup.cName = 2;
EnumNameGroup.rgpwszName = rgpwszEnumName;
cchMaxSubKey++;
if (NULL == (pwszEnumServiceName = (LPWSTR) PkiNonzeroAlloc(
cchMaxSubKey * sizeof(WCHAR))))
goto OutOfMemory;
rgpwszEnumName[0] = pLocationNameInfo->rgpwszName[COMPUTER_NAME_INDEX];
rgpwszEnumName[1] = pwszEnumServiceName;
for (i = 0; i < cSubKeys; i++) {
DWORD cchEnumServiceName = cchMaxSubKey;
LONG err;
if (ERROR_SUCCESS != (err = RegEnumKeyExU(
hKey,
i,
pwszEnumServiceName,
&cchEnumServiceName,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
)) || 0 == cchEnumServiceName ||
L'\0' == *pwszEnumServiceName) {
if (ERROR_NO_MORE_ITEMS == err)
break;
else
continue;
}
if (NULL == (pvEnumServicePara = FormatSystemNamePara(
1, &EnumNameGroup, pLocationNameInfo)))
goto FormatSystemNameParaError;
if (!CertEnumSystemStore(
dwFlags,
pvEnumServicePara,
pvArg,
pfnEnum
)) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto EnumSystemStoreError;
} else
fDidEnum = TRUE;
FreeSystemNamePara(pvEnumServicePara, pLocationNameInfo);
pvEnumServicePara = NULL;
}
}
if (!fDidEnum)
goto NoSystemStores;
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hKey);
PkiFree(pwszEnumServiceName);
FreeSystemNamePara(pvEnumServicePara, pLocationNameInfo);
FreeSystemNameInfo(pLocationNameInfo);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSystemRegPathKeyError)
TRACE_ERROR(GetSubKeyInfoError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(FormatSystemNameParaError)
TRACE_ERROR(EnumSystemStoreError)
SET_ERROR(NoSystemStores, ERROR_FILE_NOT_FOUND)
}
//+-------------------------------------------------------------------------
// Enumerate the system stores.
//
// The upper word of the dwFlags parameter is used to specify the location of
// the system store.
//
// All registry based system store locations have the predefined stores
// of: My, Root, Trust and CA.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertEnumSystemStore(
IN DWORD dwFlags,
IN OPTIONAL void *pvSystemStoreLocationPara,
IN void *pvArg,
IN PFN_CERT_ENUM_SYSTEM_STORE pfnEnum
)
{
BOOL fResult;
HKEY hKey = NULL;
DWORD cSubKeys;
DWORD cchMaxSubKey = 0;
SYSTEM_NAME_INFO LocationNameInfo;
LPWSTR pwszEnumSystemStore = NULL;
void *pvEnumSystemPara = NULL;
DWORD i;
DWORD dwCheckFlag;
DWORD dwLocID;
DWORD dwPredefinedSystemFlags;
CERT_SYSTEM_STORE_INFO NullSystemStoreInfo;
LPCWSTR rgpwszEnumName[3];
SYSTEM_NAME_GROUP EnumNameGroup;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[ENUM_SYSTEM_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_ENUM_SYSTEM_STORE) pvFuncAddr)(
dwFlags,
pvSystemStoreLocationPara,
pvArg,
pfnEnum
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (!ParseSystemStorePara(
pvSystemStoreLocationPara,
dwFlags,
0, // cReqName, none for enumeration
&LocationNameInfo // zero'ed for error
))
goto ParseSystemStoreParaError;
if (dwFlags & ~ENUM_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
dwLocID = GetSystemStoreLocationID(dwFlags);
if ((CERT_SYSTEM_STORE_SERVICES_ID == dwLocID ||
CERT_SYSTEM_STORE_USERS_ID == dwLocID)
&&
NULL == LocationNameInfo.rgpwszName[SERVICE_NAME_INDEX])
// Following frees rgpwszLocationName entries
return EnumServicesOrUsersSystemStore(
&LocationNameInfo,
dwFlags,
pvArg,
pfnEnum
);
// Opens SystemCertificates subkey
if (NULL == (hKey = OpenSystemRegPathKey(
&LocationNameInfo,
NULL, // pwszSubKeyName
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG
))) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenSystemRegPathKeyError;
// Note, a registry entry isn't needed for the predefined stores
cSubKeys = 0;
} else if (!GetSubKeyInfo(
hKey,
&cSubKeys,
&cchMaxSubKey
))
goto GetSubKeyInfoError;
memset(&NullSystemStoreInfo, 0, sizeof(NullSystemStoreInfo));
NullSystemStoreInfo.cbSize = sizeof(NullSystemStoreInfo);
EnumNameGroup.cName = 3;
EnumNameGroup.rgpwszName = rgpwszEnumName;
rgpwszEnumName[0] = LocationNameInfo.rgpwszName[COMPUTER_NAME_INDEX];
rgpwszEnumName[1] = LocationNameInfo.rgpwszName[SERVICE_NAME_INDEX];
// Enumerate the predefined system stores.
assert(NUM_SYSTEM_STORE_LOCATION > dwLocID);
dwPredefinedSystemFlags =
rgSystemStoreLocationInfo[dwLocID].dwPredefinedSystemFlags;
for (i = 0, dwCheckFlag = 1; i < NUM_PREDEFINED_SYSTEM_STORE;
i++, dwCheckFlag = dwCheckFlag << 1) {
if (0 == (dwCheckFlag & dwPredefinedSystemFlags))
continue;
rgpwszEnumName[2] = rgpwszPredefinedSystemStore[i];
if (NULL == (pvEnumSystemPara = FormatSystemNamePara(
1, &EnumNameGroup, &LocationNameInfo)))
goto FormatSystemNameParaError;
if (!pfnEnum(
pvEnumSystemPara,
dwFlags & CERT_SYSTEM_STORE_MASK,
&NullSystemStoreInfo,
NULL, // pvReserved
pvArg
))
goto EnumCallbackError;
FreeSystemNamePara(pvEnumSystemPara, &LocationNameInfo);
pvEnumSystemPara = NULL;
}
// Enumerate the registered systems stores. Skip past any of the above
// predefined stores
if (cSubKeys && cchMaxSubKey) {
cchMaxSubKey++;
if (NULL == (pwszEnumSystemStore = (LPWSTR) PkiNonzeroAlloc(
cchMaxSubKey * sizeof(WCHAR))))
goto OutOfMemory;
rgpwszEnumName[2] = pwszEnumSystemStore;
for (i = 0; i < cSubKeys; i++) {
DWORD cchEnumSystemStore = cchMaxSubKey;
LONG err;
if (ERROR_SUCCESS != (err = RegEnumKeyExU(
hKey,
i,
pwszEnumSystemStore,
&cchEnumSystemStore,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
)) || 0 == cchEnumSystemStore) {
if (ERROR_NO_MORE_ITEMS == err)
break;
else
continue;
}
if (IsPredefinedSystemStore(pwszEnumSystemStore, dwFlags))
// Already enumerated above
continue;
if (NULL == (pvEnumSystemPara = FormatSystemNamePara(
1, &EnumNameGroup, &LocationNameInfo)))
goto FormatSystemNameParaError;
if (!pfnEnum(
pvEnumSystemPara,
dwFlags & CERT_SYSTEM_STORE_MASK,
&NullSystemStoreInfo,
NULL, // pvReserved
pvArg
))
goto EnumCallbackError;
FreeSystemNamePara(pvEnumSystemPara, &LocationNameInfo);
pvEnumSystemPara = NULL;
}
}
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(hKey);
PkiFree(pwszEnumSystemStore);
FreeSystemNamePara(pvEnumSystemPara, &LocationNameInfo);
FreeSystemNameInfo(&LocationNameInfo);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(OpenSystemRegPathKeyError)
TRACE_ERROR(GetSubKeyInfoError)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(FormatSystemNameParaError)
TRACE_ERROR(EnumCallbackError)
}
typedef struct _ENUM_PHYSICAL_STORE_INFO ENUM_PHYSICAL_STORE_INFO,
*PENUM_PHYSICAL_STORE_INFO;
struct _ENUM_PHYSICAL_STORE_INFO {
CERT_PHYSICAL_STORE_INFO RegistryInfo;
LPWSTR pwszStoreName;
PENUM_PHYSICAL_STORE_INFO pNext;
};
STATIC void FreeEnumPhysicalStoreInfo(
IN PENUM_PHYSICAL_STORE_INFO pStoreInfo
)
{
PCERT_PHYSICAL_STORE_INFO pRegistryInfo = &pStoreInfo->RegistryInfo;
PkiFree(pRegistryInfo->OpenParameters.pbData);
PkiFree(pRegistryInfo->pszOpenStoreProvider);
PkiFree(pStoreInfo->pwszStoreName);
PkiFree(pStoreInfo);
}
STATIC PENUM_PHYSICAL_STORE_INFO GetEnumPhysicalStoreInfo(
IN HKEY hKey,
IN LPCWSTR pwszStoreName,
IN DWORD dwFlags // CERT_STORE_BACKUP_RESTORE_FLAG may be set
)
{
LONG err;
HKEY hSubKey = NULL;
PENUM_PHYSICAL_STORE_INFO pStoreInfo;
PCERT_PHYSICAL_STORE_INFO pRegistryInfo; // not allocated
if (NULL == (pStoreInfo = (PENUM_PHYSICAL_STORE_INFO) PkiZeroAlloc(
sizeof(ENUM_PHYSICAL_STORE_INFO))))
return NULL;
pRegistryInfo = &pStoreInfo->RegistryInfo;
pRegistryInfo->cbSize = sizeof(*pRegistryInfo);
if (NULL == (pStoreInfo->pwszStoreName =
ILS_AllocAndCopyString(pwszStoreName)))
goto OutOfMemory;
if (ERROR_SUCCESS != (err = OpenHKCUKeyExU(
hKey,
pwszStoreName,
dwFlags,
KEY_READ,
&hSubKey)))
goto OpenHKCUKeyError;
if (!ILS_ReadBINARYValueFromRegistry(
hSubKey,
L"OpenParameters",
&pRegistryInfo->OpenParameters.pbData,
&pRegistryInfo->OpenParameters.cbData
)) {
LPWSTR pwszParameters;
if (pwszParameters = ILS_ReadSZValueFromRegistry(
hSubKey,
L"OpenParameters"
)) {
pRegistryInfo->OpenParameters.pbData = (BYTE *) pwszParameters;
pRegistryInfo->OpenParameters.cbData =
(wcslen(pwszParameters) + 1) * sizeof(WCHAR);
} else {
// Default to empty string
if (NULL == (pRegistryInfo->OpenParameters.pbData =
(BYTE *) ILS_AllocAndCopyString(L"")))
goto OutOfMemory;
pRegistryInfo->OpenParameters.cbData = 0;
}
}
if (NULL == (pRegistryInfo->pszOpenStoreProvider = ILS_ReadSZValueFromRegistry(
hSubKey,
"OpenStoreProvider"
)))
goto NoOpenStoreProviderError;
ILS_ReadDWORDValueFromRegistry(
hSubKey,
L"OpenFlags",
&pRegistryInfo->dwOpenFlags
);
ILS_ReadDWORDValueFromRegistry(
hSubKey,
L"OpenEncodingType",
&pRegistryInfo->dwOpenEncodingType
);
ILS_ReadDWORDValueFromRegistry(
hSubKey,
L"Flags",
&pRegistryInfo->dwFlags
);
ILS_ReadDWORDValueFromRegistry(
hSubKey,
L"Priority",
&pRegistryInfo->dwPriority
);
CommonReturn:
ILS_CloseRegistryKey(hSubKey);
return pStoreInfo;
ErrorReturn:
FreeEnumPhysicalStoreInfo(pStoreInfo);
pStoreInfo = NULL;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR_VAR(OpenHKCUKeyError, err)
TRACE_ERROR(NoOpenStoreProviderError)
}
STATIC BOOL IsSelfPhysicalStoreInfo(
IN PSYSTEM_NAME_INFO pSystemNameInfo,
IN DWORD dwFlags,
IN PCERT_PHYSICAL_STORE_INFO pStoreInfo,
OUT DWORD *pdwSystemProviderFlags
)
{
BOOL fResult;
DWORD dwSystemProviderFlags;
LPWSTR pwszStoreName = (LPWSTR) pStoreInfo->OpenParameters.pbData;
SYSTEM_NAME_INFO StoreNameInfo;
LPWSTR pwszCurrentServiceName = NULL;
LPWSTR pwszCurrentComputerName = NULL;
DWORD dwSystemLocation;
DWORD dwInfoLocation;
BOOL fSameLocation;
*pdwSystemProviderFlags = 0;
dwSystemLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
// Note, if the RELOCATE_FLAG is incorrectly set in the dwOpenFlags
// then, never match
dwInfoLocation = pStoreInfo->dwOpenFlags &
(CERT_SYSTEM_STORE_LOCATION_MASK | CERT_SYSTEM_STORE_RELOCATE_FLAG);
// Check if in same system store location
fSameLocation = (dwSystemLocation == dwInfoLocation);
if (!fSameLocation) {
if (CERT_SYSTEM_STORE_CURRENT_SERVICE == dwInfoLocation)
dwInfoLocation = CERT_SYSTEM_STORE_SERVICES;
if (CERT_SYSTEM_STORE_CURRENT_SERVICE == dwSystemLocation)
dwSystemLocation = CERT_SYSTEM_STORE_SERVICES;
if (CERT_SYSTEM_STORE_CURRENT_USER == dwInfoLocation)
dwInfoLocation = CERT_SYSTEM_STORE_USERS;
if (CERT_SYSTEM_STORE_CURRENT_USER == dwSystemLocation)
dwSystemLocation = CERT_SYSTEM_STORE_USERS;
if (dwSystemLocation != dwInfoLocation)
return FALSE;
}
// Check if SYSTEM or SYSTEM_REGISTRY store.
dwSystemProviderFlags = GetSystemProviderFlags(
pStoreInfo->pszOpenStoreProvider);
if (0 == dwSystemProviderFlags ||
(dwSystemProviderFlags & PHYSICAL_PROVIDER_FLAG))
return FALSE;
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG) {
if (NULL == (pwszStoreName = MkWStr((LPSTR) pwszStoreName)))
return FALSE;
}
if (!ParseSystemStorePara(
pwszStoreName,
pStoreInfo->dwOpenFlags,
1, // cReq, 1 for OpenSystemStore
&StoreNameInfo // zero'ed for error
))
goto ParseSystemStoreParaError;
// Default to not self
fResult = FALSE;
if (StoreNameInfo.rgpwszName[COMPUTER_NAME_INDEX]) {
if (NULL == pSystemNameInfo->rgpwszName[COMPUTER_NAME_INDEX]) {
LPCWSTR pwszStoreComputerName;
if (NULL == (pwszCurrentComputerName = GetCurrentComputerName()))
goto GetCurrentComputerNameError;
pwszStoreComputerName =
StoreNameInfo.rgpwszName[COMPUTER_NAME_INDEX];
assert(L'\\' == pwszStoreComputerName[0] &&
L'\\' == pwszStoreComputerName[1]);
if (!('\\' == pwszCurrentComputerName[0] &&
L'\\' == pwszCurrentComputerName[1]))
pwszStoreComputerName += 2;
if (0 != _wcsicmp(pwszStoreComputerName, pwszCurrentComputerName))
goto CommonReturn;
} else if (0 != _wcsicmp(StoreNameInfo.rgpwszName[COMPUTER_NAME_INDEX],
pSystemNameInfo->rgpwszName[COMPUTER_NAME_INDEX]))
goto CommonReturn;
}
// else
// Opening using none or the same computer name
if (StoreNameInfo.rgpwszName[SERVICE_NAME_INDEX]) {
if (NULL == pSystemNameInfo->rgpwszName[SERVICE_NAME_INDEX]) {
if (NULL == (pwszCurrentServiceName =
GetCurrentServiceOrUserName()))
goto GetCurrentServiceOrUserNameError;
if (0 != _wcsicmp(StoreNameInfo.rgpwszName[SERVICE_NAME_INDEX],
pwszCurrentServiceName))
goto CommonReturn;
} else if (0 != _wcsicmp(StoreNameInfo.rgpwszName[SERVICE_NAME_INDEX],
pSystemNameInfo->rgpwszName[SERVICE_NAME_INDEX]))
goto CommonReturn;
}
// else
// Opening using none or the same service/user name
assert(StoreNameInfo.rgpwszName[SYSTEM_NAME_INDEX] &&
pSystemNameInfo->rgpwszName[SYSTEM_NAME_INDEX]);
if (0 != _wcsicmp(StoreNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
pSystemNameInfo->rgpwszName[SYSTEM_NAME_INDEX]))
goto CommonReturn;
// We have a match !!!
fResult = TRUE;
*pdwSystemProviderFlags = dwSystemProviderFlags;
CommonReturn:
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG)
FreeWStr(pwszStoreName);
FreeSystemNameInfo(&StoreNameInfo);
PkiFree(pwszCurrentServiceName);
PkiFree(pwszCurrentComputerName);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetCurrentComputerNameError)
TRACE_ERROR(GetCurrentServiceOrUserNameError)
TRACE_ERROR(ParseSystemStoreParaError)
}
// List is sorted according to physical store priority
STATIC void AddToEnumPhysicalStoreList(
IN PENUM_PHYSICAL_STORE_INFO *ppStoreInfoHead,
IN PENUM_PHYSICAL_STORE_INFO pAddInfo
)
{
if (NULL == *ppStoreInfoHead)
*ppStoreInfoHead = pAddInfo;
else {
PENUM_PHYSICAL_STORE_INFO pListInfo;
DWORD dwPriority = pAddInfo->RegistryInfo.dwPriority;
pListInfo = *ppStoreInfoHead;
if (dwPriority > pListInfo->RegistryInfo.dwPriority) {
// Insert at beginning before first entry
pAddInfo->pNext = pListInfo;
*ppStoreInfoHead = pAddInfo;
} else {
// Insert after the entry whose next entry has
// lower priority or insert after the last entry
while (pListInfo->pNext &&
dwPriority <= pListInfo->pNext->RegistryInfo.dwPriority)
pListInfo = pListInfo->pNext;
pAddInfo->pNext = pListInfo->pNext;
pListInfo->pNext = pAddInfo;
}
}
}
STATIC void FreeEnumPhysicalStoreList(
IN PENUM_PHYSICAL_STORE_INFO pStoreInfoHead
)
{
while (pStoreInfoHead) {
PENUM_PHYSICAL_STORE_INFO pStoreInfo = pStoreInfoHead;
pStoreInfoHead = pStoreInfo->pNext;
FreeEnumPhysicalStoreInfo(pStoreInfo);
}
}
// Returns NULL if unable to successfully get the Url. Returned string
// must be freed by calling CryptMemFree
STATIC LPWSTR GetUserDsUserCertificateUrl()
{
DWORD dwErr;
LPWSTR pwszUrl = NULL;
HMODULE hDll = NULL;
PFN_GET_USER_DS_STORE_URL pfnGetUserDsStoreUrl;
if (NULL == (hDll = LoadLibraryA(sz_CRYPTNET_DLL)))
goto LoadCryptNetDllError;
if (NULL == (pfnGetUserDsStoreUrl =
(PFN_GET_USER_DS_STORE_URL) GetProcAddress(hDll,
sz_GetUserDsStoreUrl)))
goto GetUserDsStoreUrlProcAddressError;
if (!pfnGetUserDsStoreUrl(wsz_USER_CERTIFICATE_ATTR, &pwszUrl)) {
dwErr = GetLastError();
goto GetUserDsStoreUrlError;
}
CommonReturn:
if (hDll) {
dwErr = GetLastError();
FreeLibrary(hDll);
SetLastError(dwErr);
}
return pwszUrl;
ErrorReturn:
pwszUrl = NULL;
goto CommonReturn;
TRACE_ERROR(LoadCryptNetDllError)
TRACE_ERROR(GetUserDsStoreUrlProcAddressError)
SET_ERROR_VAR(GetUserDsStoreUrlError, dwErr)
}
STATIC BOOL IsCurrentUserTrustedPublishersAllowed()
{
DWORD dwFlags = 0;
I_CryptReadTrustedPublisherDWORDValueFromRegistry(
CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME,
&dwFlags
);
return 0 == (dwFlags &
(CERT_TRUST_PUB_ALLOW_MACHINE_ADMIN_TRUST |
CERT_TRUST_PUB_ALLOW_ENTERPRISE_ADMIN_TRUST));
}
STATIC BOOL IsLocalMachineTrustedPublishersAllowed()
{
DWORD dwFlags = 0;
I_CryptReadTrustedPublisherDWORDValueFromRegistry(
CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME,
&dwFlags
);
return 0 == (dwFlags & CERT_TRUST_PUB_ALLOW_ENTERPRISE_ADMIN_TRUST);
}
//+-------------------------------------------------------------------------
// Unless, CERT_STORE_OPEN_EXISTING_FLAG or CERT_STORE_READONLY_FLAG is
// set, the pvSystemStore will be created if it doesn't already exist.
//
// Note, depending on the store location and possibly the store name, there
// are predefined physical stores of .Default, .LocalMachine, .GroupPolicy,
// .Enterprise
//--------------------------------------------------------------------------
STATIC BOOL EnumPhysicalStore(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum
)
{
BOOL fResult;
LONG *plDepth = NULL; // allocated per thread, don't free here
HKEY hKey = NULL;
DWORD cSubKeys;
DWORD cchMaxSubKey = 0;
LPWSTR pwszStoreName = NULL;
PENUM_PHYSICAL_STORE_INFO pStoreInfoHead = NULL;
PENUM_PHYSICAL_STORE_INFO pStoreInfo; // not allocated
SYSTEM_NAME_INFO SystemNameInfo;
DWORD dwStoreLocationID;
DWORD dwPredefinedPhysicalFlags;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (!CryptGetOIDFunctionAddress(
rghFuncSet[ENUM_PHYSICAL_STORE_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&hFuncAddr))
return FALSE;
fResult = ((PFN_ENUM_PHYSICAL_STORE) pvFuncAddr)(
pvSystemStore,
dwFlags,
pvArg,
pfnEnum
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fResult;
}
if (!ParseSystemStorePara(
pvSystemStore,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
if (dwFlags & ~ENUM_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
// Check for cross store recursion by checking the thread's enum
// depth
if (NULL == (plDepth = (LONG *) I_CryptGetTls(
hTlsEnumPhysicalStoreDepth))) {
if (NULL == (plDepth = (LONG *) PkiNonzeroAlloc(sizeof(*plDepth))))
goto OutOfMemory;
*plDepth = 1;
I_CryptSetTls(hTlsEnumPhysicalStoreDepth, plDepth);
} else {
*plDepth += 1;
if (MAX_ENUM_PHYSICAL_STORE_DEPTH < *plDepth)
goto ExceededEnumPhysicalStoreDepth_PossibleCrossStoreRecursion;
}
if (IsClientGptStore(&SystemNameInfo, dwFlags)) {
cSubKeys = 0;
} else if (NULL == (hKey = OpenSystemRegPathKey(
&SystemNameInfo,
PHYSICAL_STORES_SUBKEY_NAME,
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG
))) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenPhysicalStoresError;
// Check if we have a system store without the "PhysicalStores" subkey
if (NULL == (hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags
))) {
if (dwFlags & CERT_STORE_MAXIMUM_ALLOWED_FLAG)
hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_READONLY_FLAG
);
}
if (NULL == hKey) {
// Note, the predefined stores don't need to exist in the
// registry
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto OpenSystemStoreError;
} else {
RegCloseKey(hKey);
hKey = NULL;
}
cSubKeys = 0;
} else if (!GetSubKeyInfo(
hKey,
&cSubKeys,
&cchMaxSubKey
))
goto GetSubKeyInfoError;
// Get flags containing list of predefined physical stores according to
// store name and/or store location
dwStoreLocationID = GetSystemStoreLocationID(dwFlags);
if (0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_MY_STORE) ||
0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_REQUEST_STORE))
// Only .Default is predefined for "My" or "Request" store
dwPredefinedPhysicalFlags = MY_PHYSICAL_FLAGS;
else if (0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_ROOT_STORE)) {
if (CERT_SYSTEM_STORE_CURRENT_USER_ID == dwStoreLocationID) {
if (IPR_IsCurrentUserRootsAllowed()) {
// .Default and .LocalMachine physical stores are predefined
dwPredefinedPhysicalFlags = CURRENT_USER_ROOT_PHYSICAL_FLAGS;
} else {
// Don't read the CurrentUser's SystemRegistry
dwPredefinedPhysicalFlags = CURRENT_USER_ROOT_PHYSICAL_FLAGS &
~DEFAULT_PHYSICAL_FLAG;
// Since we won't be reading the SystemRegistry, ensure
// the protected list of roots is initialized.
IPR_InitProtectedRootInfo();
}
// Only the predefined physical stores are allowed for Root
cSubKeys = 0;
} else if (CERT_SYSTEM_STORE_LOCAL_MACHINE_ID == dwStoreLocationID) {
if (IPR_IsAuthRootsAllowed()) {
// .Default, .AuthRoot, .GroupPolicy and .Enterprise
// physical stores are predefined
dwPredefinedPhysicalFlags = LOCAL_MACHINE_ROOT_PHYSICAL_FLAGS;
} else {
// Don't read the AuthRoot's SystemRegistry
dwPredefinedPhysicalFlags = LOCAL_MACHINE_ROOT_PHYSICAL_FLAGS &
~AUTH_ROOT_PHYSICAL_FLAG;
}
// Only the predefined physical stores are allowed for Root
cSubKeys = 0;
} else if (CERT_SYSTEM_STORE_USERS_ID == dwStoreLocationID) {
// Only .LocalMachine physical stores is predefined
dwPredefinedPhysicalFlags = USERS_ROOT_PHYSICAL_FLAGS;
// Only the predefined physical stores are allowed for Root
cSubKeys = 0;
} else {
// According to store location.
dwPredefinedPhysicalFlags =
rgSystemStoreLocationInfo[
dwStoreLocationID].dwPredefinedPhysicalFlags;
}
} else if (0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_TRUST_PUB_STORE) ||
0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_DISALLOWED_STORE)) {
if (CERT_SYSTEM_STORE_CURRENT_USER_ID == dwStoreLocationID) {
if (IsCurrentUserTrustedPublishersAllowed()) {
// .Default, .GroupPolicy and .LocalMachine physical stores
// are predefined
dwPredefinedPhysicalFlags =
CURRENT_USER_TRUST_PUB_PHYSICAL_FLAGS;
} else {
// Don't read the CurrentUser's SystemRegistry
dwPredefinedPhysicalFlags =
CURRENT_USER_TRUST_PUB_PHYSICAL_FLAGS &
~DEFAULT_PHYSICAL_FLAG;
}
// Only the predefined physical stores are allowed for
// HKCU TrustedPublisher
cSubKeys = 0;
} else if (CERT_SYSTEM_STORE_LOCAL_MACHINE_ID == dwStoreLocationID) {
if (IsLocalMachineTrustedPublishersAllowed()) {
// .Default, .GroupPolicy and .Enterprise
// physical stores are predefined
dwPredefinedPhysicalFlags =
LOCAL_MACHINE_TRUST_PUB_PHYSICAL_FLAGS;
} else {
// Don't read the LocalMachine's SystemRegistry
dwPredefinedPhysicalFlags =
LOCAL_MACHINE_TRUST_PUB_PHYSICAL_FLAGS &
~DEFAULT_PHYSICAL_FLAG;
}
// Only the predefined physical stores are allowed for
// HKLM TrustedPublisher
cSubKeys = 0;
} else {
// According to store location.
dwPredefinedPhysicalFlags =
rgSystemStoreLocationInfo[
dwStoreLocationID].dwPredefinedPhysicalFlags;
}
} else if (0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_USER_DS_STORE)) {
// Only .UserCertificate is predefined for "UserDS"
dwPredefinedPhysicalFlags = USER_DS_PHYSICAL_FLAGS;
} else
// According to store location
dwPredefinedPhysicalFlags =
rgSystemStoreLocationInfo[
dwStoreLocationID].dwPredefinedPhysicalFlags;
if (cSubKeys && cchMaxSubKey) {
DWORD i;
cchMaxSubKey++;
if (NULL == (pwszStoreName = (LPWSTR) PkiNonzeroAlloc(
cchMaxSubKey * sizeof(WCHAR))))
goto OutOfMemory;
for (i = 0; i < cSubKeys; i++) {
DWORD cchStoreName = cchMaxSubKey;
LONG err;
if (ERROR_SUCCESS != (err = RegEnumKeyExU(
hKey,
i,
pwszStoreName,
&cchStoreName,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
)) || 0 == cchStoreName) {
if (ERROR_NO_MORE_ITEMS == err)
break;
else
continue;
}
if (NULL == (pStoreInfo = GetEnumPhysicalStoreInfo(
hKey,
pwszStoreName,
dwFlags
)))
continue;
AddToEnumPhysicalStoreList(&pStoreInfoHead, pStoreInfo);
}
}
for (pStoreInfo = pStoreInfoHead; pStoreInfo;
pStoreInfo = pStoreInfo->pNext) {
PCERT_PHYSICAL_STORE_INFO pRegistryInfo = &pStoreInfo->RegistryInfo;
BOOL fSelfPhysicalStoreInfo;
DWORD dwSystemProviderFlags;
char szOID[34];
if (IsSelfPhysicalStoreInfo(
&SystemNameInfo,
dwFlags,
pRegistryInfo,
&dwSystemProviderFlags)) {
assert((dwSystemProviderFlags & UNICODE_SYSTEM_PROVIDER_FLAG) ||
(dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG));
// Force to use SYSTEM_REGISTRY provider to inhibit recursion.
PkiFree(pRegistryInfo->pszOpenStoreProvider);
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG) {
// Convert to "#<number>" string
szOID[0] = CONST_OID_STR_PREFIX_CHAR;
_ltoa((long) ((DWORD_PTR)CERT_STORE_PROV_SYSTEM_REGISTRY_A), szOID + 1, 10);
pRegistryInfo->pszOpenStoreProvider = szOID;
} else
pRegistryInfo->pszOpenStoreProvider =
sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W;
dwPredefinedPhysicalFlags &= ~DEFAULT_PHYSICAL_FLAG;
fSelfPhysicalStoreInfo = TRUE;
} else {
if (0 != dwPredefinedPhysicalFlags) {
// Check if matches one of the predefined physical stores
DWORD i;
DWORD dwCheckFlag;
for (i = 0, dwCheckFlag = 1; i < NUM_PREDEFINED_PHYSICAL;
i++, dwCheckFlag = dwCheckFlag << 1) {
if ((dwCheckFlag & dwPredefinedPhysicalFlags) &&
0 == _wcsicmp(pStoreInfo->pwszStoreName,
rgpwszPredefinedPhysical[i])) {
dwPredefinedPhysicalFlags &= ~dwCheckFlag;
break;
}
}
}
fSelfPhysicalStoreInfo = FALSE;
}
if (dwFlags & CERT_STORE_MAXIMUM_ALLOWED_FLAG) {
pRegistryInfo->dwOpenFlags |= CERT_STORE_MAXIMUM_ALLOWED_FLAG;
pRegistryInfo->dwOpenFlags &= ~CERT_STORE_READONLY_FLAG;
}
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) {
pRegistryInfo->dwOpenFlags |= CERT_STORE_BACKUP_RESTORE_FLAG;
}
fResult = pfnEnum(
pvSystemStore,
dwFlags & CERT_SYSTEM_STORE_MASK,
pStoreInfo->pwszStoreName,
&pStoreInfo->RegistryInfo,
NULL, // pvReserved
pvArg
);
if (fSelfPhysicalStoreInfo) {
// Not allocated. Set to NULL to inhibit subsequent free.
pRegistryInfo->pszOpenStoreProvider = NULL;
}
if (!fResult)
goto EnumCallbackError;
}
if (0 != dwPredefinedPhysicalFlags) {
CERT_PHYSICAL_STORE_INFO SelfInfo;
LPWSTR pwszLocalStore;
DWORD cbLocalStore;
DWORD i;
DWORD dwCheckFlag;
if (SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX]) {
// Format local store name without the ComputerName
LPCWSTR rgpwszGroupName[2];
SYSTEM_NAME_GROUP NameGroup;
NameGroup.cName = 2;
NameGroup.rgpwszName = rgpwszGroupName;
assert(IsRemotableSystemStoreLocationInRegistry(dwFlags));
rgpwszGroupName[0] = SystemNameInfo.rgpwszName[SERVICE_NAME_INDEX];
rgpwszGroupName[1] = SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX];
if (NULL == (pwszLocalStore = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
} else {
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pRelocatePara =
(PCERT_SYSTEM_STORE_RELOCATE_PARA) pvSystemStore;
pwszLocalStore = (LPWSTR) pRelocatePara->pwszSystemStore;
} else
pwszLocalStore = (LPWSTR) pvSystemStore;
}
cbLocalStore = (wcslen(pwszLocalStore) + 1) * sizeof(WCHAR);
memset(&SelfInfo, 0, sizeof(SelfInfo));
SelfInfo.cbSize = sizeof(SelfInfo);
fResult = TRUE;
for (i = 0, dwCheckFlag = 1; i < NUM_PREDEFINED_PHYSICAL;
i++, dwCheckFlag = dwCheckFlag << 1) {
LPWSTR pwszUserDsUserCertificateUrl;
if (0 == (dwCheckFlag & dwPredefinedPhysicalFlags))
continue;
SelfInfo.pszOpenStoreProvider = sz_CERT_STORE_PROV_SYSTEM_W;
SelfInfo.OpenParameters.pbData =
(BYTE *) SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX];
SelfInfo.OpenParameters.cbData =
(wcslen(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX]) + 1) *
sizeof(WCHAR);
SelfInfo.dwFlags = 0;
pwszUserDsUserCertificateUrl = NULL;
switch (i) {
case DEFAULT_PHYSICAL_INDEX:
SelfInfo.pszOpenStoreProvider =
sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W;
SelfInfo.dwOpenFlags = dwFlags &
CERT_SYSTEM_STORE_LOCATION_MASK;
if (0 == _wcsicmp(
SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_MY_STORE))
SelfInfo.dwOpenFlags |= CERT_STORE_UPDATE_KEYID_FLAG;
SelfInfo.OpenParameters.pbData = (BYTE *) pwszLocalStore;
SelfInfo.OpenParameters.cbData = cbLocalStore;
SelfInfo.dwFlags = CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
break;
case AUTH_ROOT_PHYSICAL_INDEX:
SelfInfo.pszOpenStoreProvider =
sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W;
SelfInfo.dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
SelfInfo.OpenParameters.pbData =
(BYTE *) wsz_AUTH_ROOT_STORE;
SelfInfo.OpenParameters.cbData =
(wcslen(wsz_AUTH_ROOT_STORE) + 1) * sizeof(WCHAR);
SelfInfo.dwFlags = CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
break;
case GROUP_POLICY_PHYSICAL_INDEX:
if (CERT_SYSTEM_STORE_LOCAL_MACHINE_ID ==
dwStoreLocationID)
SelfInfo.dwOpenFlags =
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY |
CERT_STORE_READONLY_FLAG;
else
SelfInfo.dwOpenFlags =
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY |
CERT_STORE_READONLY_FLAG;
break;
case LOCAL_MACHINE_PHYSICAL_INDEX:
SelfInfo.dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE |
CERT_STORE_READONLY_FLAG;
break;
case DS_USER_CERT_PHYSICAL_INDEX:
if (NULL == (pwszUserDsUserCertificateUrl =
GetUserDsUserCertificateUrl()))
continue;
SelfInfo.pszOpenStoreProvider = sz_CERT_STORE_PROV_LDAP_W;
SelfInfo.dwOpenFlags = 0;
SelfInfo.OpenParameters.pbData =
(BYTE *) pwszUserDsUserCertificateUrl;
SelfInfo.OpenParameters.cbData = (wcslen(
pwszUserDsUserCertificateUrl) + 1) * sizeof(WCHAR);
SelfInfo.dwFlags = CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
break;
case LMGP_PHYSICAL_INDEX:
SelfInfo.dwOpenFlags =
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY |
CERT_STORE_READONLY_FLAG;
break;
case ENTERPRISE_PHYSICAL_INDEX:
SelfInfo.dwOpenFlags =
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE |
CERT_STORE_READONLY_FLAG;
break;
default:
assert(i < NUM_PREDEFINED_PHYSICAL);
continue;
}
if (dwFlags & CERT_STORE_MAXIMUM_ALLOWED_FLAG) {
SelfInfo.dwOpenFlags |= CERT_STORE_MAXIMUM_ALLOWED_FLAG;
SelfInfo.dwOpenFlags &= ~CERT_STORE_READONLY_FLAG;
}
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) {
SelfInfo.dwOpenFlags |= CERT_STORE_BACKUP_RESTORE_FLAG;
}
fResult = pfnEnum(
pvSystemStore,
(dwFlags & CERT_SYSTEM_STORE_MASK) |
CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG,
rgpwszPredefinedPhysical[i], // pwszStoreName
&SelfInfo,
NULL, // pvReserved
pvArg
);
if (pwszUserDsUserCertificateUrl)
CryptMemFree(pwszUserDsUserCertificateUrl);
if (!fResult)
break;
}
if (SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX])
PkiFree(pwszLocalStore);
if (!fResult)
goto EnumCallbackError;
}
fResult = TRUE;
CommonReturn:
if (plDepth)
*plDepth -= 1;
ILS_CloseRegistryKey(hKey);
FreeSystemNameInfo(&SystemNameInfo);
PkiFree(pwszStoreName);
FreeEnumPhysicalStoreList(pStoreInfoHead);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(OutOfMemory)
SET_ERROR(ExceededEnumPhysicalStoreDepth_PossibleCrossStoreRecursion, E_UNEXPECTED)
TRACE_ERROR(OpenPhysicalStoresError)
TRACE_ERROR(OpenSystemStoreError)
TRACE_ERROR(GetSubKeyInfoError)
TRACE_ERROR(FormatSystemNamePathError)
TRACE_ERROR(EnumCallbackError)
}
//+-------------------------------------------------------------------------
// Enumerate the physical stores for the specified system store.
//
// The upper word of the dwFlags parameter is used to specify the location of
// the system store.
//
// If the system store location only supports system stores and doesn't
// support physical stores, LastError is set to ERROR_CALL_NOT_IMPLEMENTED.
//--------------------------------------------------------------------------
BOOL
WINAPI
CertEnumPhysicalStore(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum
)
{
return EnumPhysicalStore(
pvSystemStore,
dwFlags | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
pvArg,
pfnEnum
);
}
STATIC BOOL IsHKCUStore(
IN LPCWSTR pwszStoreName,
IN PSYSTEM_NAME_INFO pInfo,
IN DWORD dwFlags
)
{
DWORD dwStoreLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
if (CERT_SYSTEM_STORE_CURRENT_USER != dwStoreLocation ||
0 != _wcsicmp(pInfo->rgpwszName[SYSTEM_NAME_INDEX], pwszStoreName))
return FALSE;
if (dwFlags & (CERT_SYSTEM_STORE_RELOCATE_FLAG | CERT_STORE_DELETE_FLAG))
return FALSE;
return TRUE;
}
//+-------------------------------------------------------------------------
// Open the system registry store provider (unicode version)
//
// Open the system registry store specified by its name. For example,
// L"My".
//
// pvPara contains the LPCWSTR system registry store name.
//
// Note for an error return, the caller will free any certs, CRLs or CTLs
// successfully added to the store.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenSystemRegistryStoreProvW(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
LONG err;
HKEY hKey = NULL;
SYSTEM_NAME_INFO SystemNameInfo;
BOOL fUserRoot;
HKEY hHKCURoot = NULL;
DWORD dwOpenRegFlags;
const void *pvOpenRegPara;
LPWSTR pwszRoamingDirectory = NULL;
CERT_REGISTRY_STORE_ROAMING_PARA RoamingStorePara;
CERT_REGISTRY_STORE_CLIENT_GPT_PARA ClientGptStorePara;
memset(&ClientGptStorePara, 0, sizeof(ClientGptStorePara));
if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
dwFlags &= ~CERT_STORE_UNSAFE_PHYSICAL_FLAG;
}
if (!ParseSystemStorePara(
pvPara,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
if (dwFlags & ~OPEN_SYS_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
// Check for the CurrentUser "Root" store.
fUserRoot = FALSE;
if (0 == _wcsicmp(SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX],
wsz_ROOT_STORE) &&
0 == (dwFlags & CERT_SYSTEM_STORE_UNPROTECTED_FLAG)) {
DWORD dwStoreLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
// Note, LOCAL_MACHINE check is needed to prevent use of relocation
// to access the current user's root store
if (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation) {
fUserRoot = TRUE;
if (NULL == SystemNameInfo.hKeyBase) {
if (ERROR_SUCCESS != (err = RegOpenHKCUEx(
&hHKCURoot,
REG_HKCU_DISABLE_DEFAULT_FLAG
)))
goto RegOpenHKCUExRootError;
SystemNameInfo.hKeyBase = hHKCURoot;
dwFlags |= CERT_SYSTEM_STORE_RELOCATE_FLAG;
}
} else if (CERT_SYSTEM_STORE_USERS == dwStoreLocation ||
((dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) &&
CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation))
goto RootAccessDenied;
}
if (IsClientGptStore(&SystemNameInfo, dwFlags)) {
DWORD dwStoreLocation;
assert(!fUserRoot);
if (NULL == (ClientGptStorePara.pwszRegPath = FormatSystemRegPath(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags,
&ClientGptStorePara.hKeyBase)))
goto FormatSystemRegPathError;
pvOpenRegPara = (const void *) &ClientGptStorePara;
dwOpenRegFlags =
dwFlags & ~(CERT_SYSTEM_STORE_MASK |
CERT_STORE_SET_LOCALIZED_NAME_FLAG);
dwOpenRegFlags |= CERT_REGISTRY_STORE_CLIENT_GPT_FLAG;
// | CERT_REGISTRY_STORE_SERIALIZED_FLAG;
dwStoreLocation = dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
if (CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY == dwStoreLocation)
dwOpenRegFlags |= CERT_REGISTRY_STORE_LM_GPT_FLAG;
if (SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX])
dwOpenRegFlags |= CERT_REGISTRY_STORE_REMOTE_FLAG;
} else {
BOOL fIsHKCUMyStore;
fIsHKCUMyStore = IsHKCUStore(wsz_MY_STORE, &SystemNameInfo, dwFlags);
if (fIsHKCUMyStore) {
pwszRoamingDirectory =
ILS_GetRoamingStoreDirectory(ROAMING_MY_STORE_SUBDIR);
} else if (IsHKCUStore(wsz_REQUEST_STORE, &SystemNameInfo, dwFlags)) {
pwszRoamingDirectory =
ILS_GetRoamingStoreDirectory(ROAMING_REQUEST_STORE_SUBDIR);
}
if (NULL != pwszRoamingDirectory) {
// OK for this to fail. After the first open, all contexts should
// be persisted in files and not the registry.
hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
(dwFlags & ~CERT_STORE_CREATE_NEW_FLAG) |
CERT_STORE_OPEN_EXISTING_FLAG
);
RoamingStorePara.hKey = hKey;
RoamingStorePara.pwszStoreDirectory = pwszRoamingDirectory;
pvOpenRegPara = (const void *) &RoamingStorePara;
dwOpenRegFlags =
dwFlags & ~(CERT_SYSTEM_STORE_MASK |
CERT_STORE_CREATE_NEW_FLAG |
CERT_STORE_SET_LOCALIZED_NAME_FLAG);
dwOpenRegFlags |= CERT_REGISTRY_STORE_ROAMING_FLAG;
} else {
if (NULL == (hKey = OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags)))
goto OpenSystemStoreError;
pvOpenRegPara = (const void *) hKey;
dwOpenRegFlags =
dwFlags & ~(CERT_SYSTEM_STORE_MASK |
CERT_STORE_CREATE_NEW_FLAG |
CERT_STORE_SET_LOCALIZED_NAME_FLAG);
if (SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX])
dwOpenRegFlags |= CERT_REGISTRY_STORE_REMOTE_FLAG;
if (IsSerializedSystemStoreLocationInRegistry(dwFlags)) {
assert(!fUserRoot);
dwOpenRegFlags |= CERT_REGISTRY_STORE_SERIALIZED_FLAG;
}
}
}
if (fUserRoot)
IPR_InitProtectedRootInfo();
if (!I_CertDllOpenRegStoreProv(
NULL, // lpszStoreProvider
dwEncodingType,
hCryptProv,
dwOpenRegFlags,
pvOpenRegPara,
hCertStore,
pStoreProvInfo))
goto OpenRegStoreProvError;
if (fUserRoot) {
PREG_STORE pRegStore = (PREG_STORE) pStoreProvInfo->hStoreProv;
// Set count to 0 to inhibit any callbacks from being called.
pStoreProvInfo->cStoreProvFunc = 0;
// For the "Root" delete any roots that aren't in the protected root
// list.
if (!IPR_DeleteUnprotectedRootsFromStore(
hCertStore,
&pRegStore->fProtected
)) goto DeleteUnprotectedRootsError;
// For the "Root" replace some of the provider callback functions
// that first prompt the user directly (if not protected) or
// prompt the user via the system service (if protected).
pStoreProvInfo->cStoreProvFunc = ROOT_STORE_PROV_FUNC_COUNT;
pStoreProvInfo->rgpvStoreProvFunc = (void **) rgpvRootStoreProvFunc;
}
if (dwFlags & CERT_STORE_SET_LOCALIZED_NAME_FLAG)
SetLocalizedNameStoreProperty(hCertStore, &SystemNameInfo);
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_SYSTEM_STORE_FLAG;
if (IsLMSystemStoreLocationInRegistry(dwFlags))
pStoreProvInfo->dwStoreProvFlags |=
CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG;
fResult = TRUE;
CommonReturn:
if (SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX] &&
ClientGptStorePara.hKeyBase)
ILS_CloseRegistryKey(ClientGptStorePara.hKeyBase);
PkiFree(ClientGptStorePara.pwszRegPath);
FreeSystemNameInfo(&SystemNameInfo);
PkiFree(pwszRoamingDirectory);
ILS_CloseRegistryKey(hKey);
if (hHKCURoot) {
DWORD dwErr = GetLastError();
RegCloseHKCU(hHKCURoot);
SetLastError(dwErr);
}
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(RootAccessDenied, E_ACCESSDENIED)
SET_ERROR_VAR(RegOpenHKCUExRootError, err)
TRACE_ERROR(FormatSystemRegPathError)
TRACE_ERROR(OpenSystemStoreError)
TRACE_ERROR(OpenRegStoreProvError)
TRACE_ERROR(DeleteUnprotectedRootsError)
}
//+-------------------------------------------------------------------------
// Open the system registry store provider (ascii version)
//
// Open the system registry store specified by its name. For example,
// "My".
//
// pvPara contains the LPCSTR system store name.
//
// Note for an error return, the caller will free any certs or CRLs
// successfully added to the store.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenSystemRegistryStoreProvA(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
LPCSTR pszStoreName; // not allocated
LPWSTR pwszStoreName;
CERT_SYSTEM_STORE_RELOCATE_PARA RelocatePara;
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pInPara;
if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
assert(pvPara);
pInPara = (PCERT_SYSTEM_STORE_RELOCATE_PARA) pvPara;
RelocatePara.hKeyBase = pInPara->hKeyBase;
pszStoreName = pInPara->pszSystemStore;
} else
pszStoreName = (LPCSTR) pvPara;
assert(pszStoreName);
if (NULL == (pwszStoreName = MkWStr((LPSTR) pszStoreName)))
fResult = FALSE;
else {
const void *pvParaW;
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
RelocatePara.pwszSystemStore = pwszStoreName;
pvParaW = (const void *) &RelocatePara;
} else
pvParaW = (const void *) pwszStoreName;
fResult = I_CertDllOpenSystemRegistryStoreProvW(
NULL, // lpszStoreProvider
dwEncodingType,
hCryptProv,
dwFlags,
pvParaW,
hCertStore,
pStoreProvInfo
);
FreeWStr(pwszStoreName);
}
return fResult;
}
typedef struct _OPEN_PHYSICAL_STORE_INFO {
HCERTSTORE hCollectionStore;
LPCWSTR pwszComputerName; // NULL implies local
LPCWSTR pwszServiceName; // NULL implies current
LPCWSTR pwszPhysicalName; // NULL implies any
HKEY hKeyBase; // non-NULL, relocatable
DWORD dwFlags;
BOOL fDidOpen;
} OPEN_PHYSICAL_STORE_INFO, *POPEN_PHYSICAL_STORE_INFO;
STATIC BOOL WINAPI OpenPhysicalStoreCallback(
IN const void *pvSystemStore,
IN DWORD dwFlags,
IN LPCWSTR pwszStoreName,
IN PCERT_PHYSICAL_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved,
IN OPTIONAL void *pvArg
)
{
BOOL fResult;
HCERTSTORE hPhysicalStore = NULL;
POPEN_PHYSICAL_STORE_INFO pOpenInfo =
(POPEN_PHYSICAL_STORE_INFO) pvArg;
void *pvOpenParameters;
LPWSTR pwszRemoteOpenParameters = NULL;
LPCSTR pszOpenStoreProvider;
DWORD dwOpenFlags;
DWORD dwAddFlags;
CERT_SYSTEM_STORE_RELOCATE_PARA RelocateOpenParameters;
if ((pStoreInfo->dwFlags & CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG)
||
(pOpenInfo->pwszPhysicalName &&
0 != _wcsicmp(pOpenInfo->pwszPhysicalName, pwszStoreName))
||
(pOpenInfo->pwszComputerName &&
(pStoreInfo->dwFlags &
CERT_PHYSICAL_STORE_REMOTE_OPEN_DISABLE_FLAG)))
return TRUE;
pvOpenParameters = pStoreInfo->OpenParameters.pbData;
assert(pvOpenParameters);
dwOpenFlags = pStoreInfo->dwOpenFlags;
pszOpenStoreProvider = pStoreInfo->pszOpenStoreProvider;
if (!(dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG)) {
// The parameters for the physical were read from the registry.
// Set the unsafe flag to alert the physical store provider to be
// called.
dwOpenFlags |= CERT_STORE_UNSAFE_PHYSICAL_FLAG;
// Check for potentially unsafe open flags
if (dwOpenFlags & (
CERT_STORE_NO_CRYPT_RELEASE_FLAG |
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG |
CERT_STORE_DELETE_FLAG |
CERT_STORE_SHARE_STORE_FLAG |
CERT_STORE_SHARE_CONTEXT_FLAG |
CERT_STORE_MANIFOLD_FLAG |
CERT_STORE_BACKUP_RESTORE_FLAG
))
goto UnsafeOpenPhysicalFlagsError;
// Following flags can be set
// CERT_STORE_SET_LOCALIZED_NAME_FLAG
// CERT_STORE_UNSAFE_PHYSICAL_FLAG
// CERT_STORE_ENUM_ARCHIVED_FLAG
// CERT_STORE_UPDATE_KEYID_FLAG
// CERT_STORE_READONLY_FLAG
// CERT_STORE_OPEN_EXISTING_FLAG
// CERT_STORE_CREATE_NEW_FLAG
// CERT_STORE_MAXIMUM_ALLOWED_FLAG
}
if (pOpenInfo->pwszComputerName || pOpenInfo->pwszServiceName) {
// Possibly insert the \\ComputerName\ServiceName before the
// OpenParameters
LPCWSTR pwszComputerName = NULL;
LPCWSTR pwszServiceName = NULL;
LPWSTR pwszSystemStore = (LPWSTR) pvOpenParameters;
DWORD dwSystemProviderFlags =
GetSystemProviderFlags(pszOpenStoreProvider);
if (0 != dwSystemProviderFlags) {
SYSTEM_NAME_INFO ProviderNameInfo;
DWORD cReqName;
if (dwOpenFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
goto RelocateFlagSetInPhysicalStoreInfoError;
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG) {
if (NULL == (pwszSystemStore =
MkWStr((LPSTR) pvOpenParameters)))
goto OutOfMemory;
}
if (dwSystemProviderFlags & PHYSICAL_PROVIDER_FLAG)
cReqName = 2;
else
cReqName = 1;
ParseSystemStorePara(
pwszSystemStore,
dwOpenFlags,
cReqName,
&ProviderNameInfo // zero'ed on error
);
if (ProviderNameInfo.rgpwszName[COMPUTER_NAME_INDEX]) {
// Already has \\ComputerName\ prefix. For Services or
// Users, already has ServiceName\ prefix.
;
} else if (ProviderNameInfo.rgpwszName[SYSTEM_NAME_INDEX]) {
// Needed above check if ParseSystemStorePara failed.
pwszComputerName = pOpenInfo->pwszComputerName;
if (pOpenInfo->pwszServiceName) {
// If the provider store is located in CURRENT_SERVICE or
// CURRENT_USER use outer store's SERVICE_NAME and change
// store location accordingly
DWORD dwOpenLocation =
dwOpenFlags & CERT_SYSTEM_STORE_LOCATION_MASK;
if (CERT_SYSTEM_STORE_CURRENT_SERVICE == dwOpenLocation) {
pwszServiceName = pOpenInfo->pwszServiceName;
dwOpenFlags =
(dwOpenFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) |
CERT_SYSTEM_STORE_SERVICES;
} else if (CERT_SYSTEM_STORE_CURRENT_USER ==
dwOpenLocation) {
pwszServiceName = pOpenInfo->pwszServiceName;
dwOpenFlags =
(dwOpenFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) |
CERT_SYSTEM_STORE_USERS;
}
}
}
FreeSystemNameInfo(&ProviderNameInfo);
} else if (pStoreInfo->dwFlags &
CERT_PHYSICAL_STORE_INSERT_COMPUTER_NAME_ENABLE_FLAG)
pwszComputerName = pOpenInfo->pwszComputerName;
if (pwszComputerName || pwszServiceName) {
// Insert \\ComputerName\ServiceName before and re-format
// open parameters
LPCWSTR rgpwszName[3];
SYSTEM_NAME_GROUP NameGroup;
assert(pwszSystemStore);
NameGroup.cName = 3;
NameGroup.rgpwszName = rgpwszName;
rgpwszName[0] = pwszComputerName;
rgpwszName[1] = pwszServiceName;
rgpwszName[2] = pwszSystemStore;
pwszRemoteOpenParameters = FormatSystemNamePath(1, &NameGroup);
pvOpenParameters = pwszRemoteOpenParameters;
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG)
pszOpenStoreProvider = ChangeAsciiToUnicodeProvider(
pszOpenStoreProvider);
}
if (dwSystemProviderFlags & ASCII_SYSTEM_PROVIDER_FLAG) {
FreeWStr(pwszSystemStore);
if (NULL == pszOpenStoreProvider)
goto UnableToChangeToUnicodeProvider;
}
if (NULL == pvOpenParameters)
goto FormatSystemNamePathError;
}
if (NULL != pOpenInfo->hKeyBase &&
0 != GetSystemProviderFlags(pszOpenStoreProvider)) {
if (dwOpenFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
goto RelocateFlagSetInPhysicalStoreInfoError;
// Inherit outer store's hKeyBase and convert to a relocated
// physical store
RelocateOpenParameters.hKeyBase = pOpenInfo->hKeyBase;
RelocateOpenParameters.pvSystemStore = pvOpenParameters;
pvOpenParameters = &RelocateOpenParameters;
dwOpenFlags |= CERT_SYSTEM_STORE_RELOCATE_FLAG;
}
if (NULL == (hPhysicalStore = CertOpenStore(
pszOpenStoreProvider,
pStoreInfo->dwOpenEncodingType,
0, // hCryptProv
dwOpenFlags | (pOpenInfo->dwFlags &
(CERT_STORE_READONLY_FLAG |
CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_MANIFOLD_FLAG |
CERT_STORE_SHARE_CONTEXT_FLAG |
CERT_STORE_SHARE_STORE_FLAG |
CERT_STORE_BACKUP_RESTORE_FLAG |
CERT_STORE_UPDATE_KEYID_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG)),
pvOpenParameters))) {
DWORD dwErr = GetLastError();
if (ERROR_FILE_NOT_FOUND == dwErr || ERROR_PROC_NOT_FOUND == dwErr ||
ERROR_GEN_FAILURE == dwErr) {
if (pOpenInfo->pwszPhysicalName &&
(dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG)) {
// For a predefined physical convert to an empty collection
CertAddStoreToCollection(
pOpenInfo->hCollectionStore,
NULL, // hSiblingStore, NULL implies convert only
0, // dwFlags
0 // dwPriority
);
goto OpenReturn;
} else
goto SuccessReturn;
} else
goto OpenPhysicalStoreError;
}
dwAddFlags = pStoreInfo->dwFlags;
if ((dwOpenFlags & CERT_STORE_MAXIMUM_ALLOWED_FLAG) &&
0 == (dwAddFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG) &&
pOpenInfo->pwszPhysicalName) {
DWORD dwAccessStateFlags;
DWORD cbData = sizeof(dwAccessStateFlags);
if (CertGetStoreProperty(
hPhysicalStore,
CERT_ACCESS_STATE_PROP_ID,
&dwAccessStateFlags,
&cbData
)) {
if (dwAccessStateFlags & CERT_ACCESS_STATE_WRITE_PERSIST_FLAG)
dwAddFlags |= CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
}
}
if (!CertAddStoreToCollection(
pOpenInfo->hCollectionStore,
hPhysicalStore,
dwAddFlags,
pStoreInfo->dwPriority))
goto AddStoreToCollectionError;
OpenReturn:
pOpenInfo->fDidOpen = TRUE;
SuccessReturn:
fResult = TRUE;
CommonReturn:
PkiFree(pwszRemoteOpenParameters);
if (hPhysicalStore)
CertCloseStore(hPhysicalStore, 0);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR(UnableToChangeToUnicodeProvider, E_UNEXPECTED)
TRACE_ERROR(OpenPhysicalStoreError)
TRACE_ERROR(AddStoreToCollectionError)
TRACE_ERROR(FormatSystemNamePathError)
SET_ERROR(UnsafeOpenPhysicalFlagsError, E_INVALIDARG)
SET_ERROR(RelocateFlagSetInPhysicalStoreInfoError, E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Open the system store provider (unicode version)
//
// Open the system store specified by its name. For example,
// L"My".
//
// pvPara contains the LPCWSTR system store name.
//
// Note for an error return, the caller will free any certs, CRLs or CTLs
// successfully added to the store.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenSystemStoreProvW(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
SYSTEM_NAME_INFO SystemNameInfo;
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_SYSTEM_STORE_FLAG;
if (IsLMSystemStoreLocationInRegistry(dwFlags))
pStoreProvInfo->dwStoreProvFlags |=
CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG;
if (!IsSystemStoreLocationInRegistry(dwFlags)) {
void *pvFuncAddr;
assert(NULL == pStoreProvInfo->hStoreProvFuncAddr2);
if (!CryptGetOIDFunctionAddress(
rghFuncSet[OPEN_SYSTEM_STORE_PROV_FUNC_SET],
0, // dwEncodingType,
GetSystemStoreLocationOID(dwFlags),
0, // dwFlags
&pvFuncAddr,
&pStoreProvInfo->hStoreProvFuncAddr2))
return FALSE;
fResult = ((PFN_CERT_DLL_OPEN_STORE_PROV_FUNC) pvFuncAddr)(
lpszStoreProvider,
dwEncodingType,
hCryptProv,
dwFlags,
pvPara,
hCertStore,
pStoreProvInfo
);
// Note, hStoreProvFuncAddr2 is CryptFreeOIDFunctionAddress'ed by
// CertCloseStore()
return fResult;
}
if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
dwFlags &= ~CERT_STORE_UNSAFE_PHYSICAL_FLAG;
}
if (!ParseSystemStorePara(
pvPara,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
if (dwFlags & ~OPEN_SYS_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (dwFlags & CERT_STORE_DELETE_FLAG) {
// Need to clear out CERT_STORE_NO_CRYPT_RELEASE_FLAG
if (!CertUnregisterSystemStore(
pvPara,
dwFlags & UNREGISTER_FLAGS_MASK
))
goto UnregisterSystemStoreError;
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_DELETED_FLAG;
} else {
OPEN_PHYSICAL_STORE_INFO OpenInfo;
if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) {
HKEY hKey;
if (NULL == (hKey = OpenSystemStore(pvPara, dwFlags)))
goto OpenSystemStoreError;
RegCloseKey(hKey);
dwFlags &= ~CERT_STORE_CREATE_NEW_FLAG;
}
OpenInfo.hCollectionStore = hCertStore;
OpenInfo.pwszComputerName =
SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX];
OpenInfo.pwszServiceName =
SystemNameInfo.rgpwszName[SERVICE_NAME_INDEX];
OpenInfo.pwszPhysicalName = NULL; // NULL implies any
OpenInfo.hKeyBase = SystemNameInfo.hKeyBase;
OpenInfo.dwFlags = dwFlags & ~CERT_STORE_SET_LOCALIZED_NAME_FLAG;
OpenInfo.fDidOpen = FALSE;
// Need to clear out CERT_STORE_NO_CRYPT_RELEASE_FLAG
if (!EnumPhysicalStore(
pvPara,
dwFlags & ENUM_FLAGS_MASK,
&OpenInfo,
OpenPhysicalStoreCallback
))
goto EnumPhysicalStoreError;
if (!OpenInfo.fDidOpen) {
if (IsPredefinedSystemStore(
SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX], dwFlags))
// Convert to a collection store
CertAddStoreToCollection(
hCertStore,
NULL, // hSiblingStore, NULL implies convert only
0, // dwFlags
0 // dwPriority
);
else
goto PhysicalStoreNotFound;
}
if (dwFlags & CERT_STORE_SET_LOCALIZED_NAME_FLAG)
SetLocalizedNameStoreProperty(hCertStore, &SystemNameInfo);
}
fResult = TRUE;
CommonReturn:
FreeSystemNameInfo(&SystemNameInfo);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ParseSystemStoreParaError)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(UnregisterSystemStoreError)
TRACE_ERROR(OpenSystemStoreError)
TRACE_ERROR(EnumPhysicalStoreError)
SET_ERROR(PhysicalStoreNotFound, ERROR_FILE_NOT_FOUND)
}
//+-------------------------------------------------------------------------
// Open the system store provider (ascii version)
//
// Open the system store specified by its name. For example,
// "My".
//
// pvPara contains the LPCSTR system store name.
//
// Note for an error return, the caller will free any certs or CRLs
// successfully added to the store.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenSystemStoreProvA(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
LPCSTR pszStoreName; // not allocated
LPWSTR pwszStoreName;
CERT_SYSTEM_STORE_RELOCATE_PARA RelocatePara;
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pInPara;
if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
assert(pvPara);
pInPara = (PCERT_SYSTEM_STORE_RELOCATE_PARA) pvPara;
RelocatePara.hKeyBase = pInPara->hKeyBase;
pszStoreName = pInPara->pszSystemStore;
} else
pszStoreName = (LPCSTR) pvPara;
assert(pszStoreName);
if (NULL == (pwszStoreName = MkWStr((LPSTR) pszStoreName)))
fResult = FALSE;
else {
const void *pvParaW;
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
RelocatePara.pwszSystemStore = pwszStoreName;
pvParaW = (const void *) &RelocatePara;
} else
pvParaW = (const void *) pwszStoreName;
fResult = I_CertDllOpenSystemStoreProvW(
NULL, // lpszStoreProvider
dwEncodingType,
hCryptProv,
dwFlags,
pvParaW,
hCertStore,
pStoreProvInfo
);
FreeWStr(pwszStoreName);
}
return fResult;
}
//+-------------------------------------------------------------------------
// Open the physical store provider (unicode version)
//
// Open the physical store in the specified system store. For example,
// L"My\.Default".
//
// pvPara contains the LPCWSTR pwszSystemAndPhysicalName which is the
// concatenation of the system and physical store names with an
// intervening "\".
//
// Note for an error return, the caller will free any certs, CRLs or CTLs
// successfully added to the store.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CertDllOpenPhysicalStoreProvW(
IN LPCSTR lpszStoreProvider,
IN DWORD dwEncodingType,
IN HCRYPTPROV hCryptProv,
IN DWORD dwFlags,
IN const void *pvPara,
IN HCERTSTORE hCertStore,
IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
)
{
BOOL fResult;
LPCWSTR pwszBoth; // not allocated
LPWSTR pwszSystem = NULL; // allocated
DWORD cchSystem;
LPCWSTR pwszPhysical; // not allocated
void *pvSystemPara; // not allocated
CERT_SYSTEM_STORE_RELOCATE_PARA RelocatePara;
if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
goto InvalidArg;
dwFlags &= ~CERT_STORE_UNSAFE_PHYSICAL_FLAG;
}
if (dwFlags & ~OPEN_PHY_FLAGS_MASK)
goto InvalidArg;
if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
ILS_EnableBackupRestorePrivileges();
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pInPara;
if (NULL == pvPara)
goto InvalidArg;
pInPara = (PCERT_SYSTEM_STORE_RELOCATE_PARA) pvPara;
pwszBoth = pInPara->pwszSystemStore;
} else
pwszBoth = (LPCWSTR) pvPara;
// Extract the system and physical name components by starting at
// the end and searching backwards for the first "\"
if (NULL == pwszBoth)
goto InvalidArg;
pwszPhysical = pwszBoth + wcslen(pwszBoth);
while (pwszPhysical > pwszBoth && L'\\' != *pwszPhysical)
pwszPhysical--;
cchSystem = (DWORD)(pwszPhysical - pwszBoth);
pwszPhysical++; // advance past "\"
if (0 < cchSystem && L'\0' != *pwszPhysical) {
if (NULL == (pwszSystem = ILS_AllocAndCopyString(pwszBoth, cchSystem)))
goto OutOfMemory;
} else
// Missing "\" or empty System or Physical Name.
goto InvalidArg;
if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
PCERT_SYSTEM_STORE_RELOCATE_PARA pInPara =
(PCERT_SYSTEM_STORE_RELOCATE_PARA) pvPara;
RelocatePara.hKeyBase = pInPara->hKeyBase;
RelocatePara.pwszSystemStore = pwszSystem;
pvSystemPara = &RelocatePara;
} else
pvSystemPara = pwszSystem;
if (dwFlags & CERT_STORE_DELETE_FLAG) {
// Need to clear out CERT_STORE_NO_CRYPT_RELEASE_FLAG
if (!CertUnregisterPhysicalStore(
pvSystemPara,
dwFlags & UNREGISTER_FLAGS_MASK,
pwszPhysical
))
goto UnregisterPhysicalStoreError;
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_DELETED_FLAG;
} else {
SYSTEM_NAME_INFO SystemNameInfo;
OPEN_PHYSICAL_STORE_INFO OpenInfo;
// Note, already removed PhysicalName above. That's why
// cReqName is 1 and not 2.
if (!ParseSystemStorePara(
pvSystemPara,
dwFlags,
1, // cReqName
&SystemNameInfo)) // zero'ed on error
goto ParseSystemStoreParaError;
OpenInfo.hCollectionStore = hCertStore;
OpenInfo.pwszComputerName =
SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX];
OpenInfo.pwszServiceName =
SystemNameInfo.rgpwszName[SERVICE_NAME_INDEX];
OpenInfo.pwszPhysicalName = pwszPhysical;
OpenInfo.hKeyBase = SystemNameInfo.hKeyBase;
OpenInfo.dwFlags = dwFlags & ~CERT_STORE_SET_LOCALIZED_NAME_FLAG;
OpenInfo.fDidOpen = FALSE;
// For .Default physical store, allow the store to be created.
// Otherwise, the store must already exist.
if (0 != _wcsicmp(CERT_PHYSICAL_STORE_DEFAULT_NAME, pwszPhysical))
dwFlags |= CERT_STORE_OPEN_EXISTING_FLAG |
CERT_STORE_READONLY_FLAG;
// Need to clear out CERT_STORE_NO_CRYPT_RELEASE_FLAG
fResult = EnumPhysicalStore(
pvSystemPara,
dwFlags & ENUM_FLAGS_MASK,
&OpenInfo,
OpenPhysicalStoreCallback
);
if (dwFlags & CERT_STORE_SET_LOCALIZED_NAME_FLAG) {
assert(NULL == SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX]);
SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX] =
(LPWSTR) pwszPhysical;
SetLocalizedNameStoreProperty(hCertStore, &SystemNameInfo);
SystemNameInfo.rgpwszName[PHYSICAL_NAME_INDEX] = NULL;
}
FreeSystemNameInfo(&SystemNameInfo);
if (!fResult)
goto EnumPhysicalStoreError;
if (!OpenInfo.fDidOpen)
goto PhysicalStoreNotFound;
}
pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_SYSTEM_STORE_FLAG;
if (IsLMSystemStoreLocationInRegistry(dwFlags))
pStoreProvInfo->dwStoreProvFlags |=
CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG;
fResult = TRUE;
CommonReturn:
PkiFree(pwszSystem);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(UnregisterPhysicalStoreError)
TRACE_ERROR(ParseSystemStoreParaError)
TRACE_ERROR(EnumPhysicalStoreError)
SET_ERROR(PhysicalStoreNotFound, ERROR_FILE_NOT_FOUND)
}
//+=========================================================================
// "ROOT" STORE
//==========================================================================
//+-------------------------------------------------------------------------
// For "Root": prompt before adding a cert.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RootStoreProvWriteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
PCCERT_CONTEXT pProvCertContext = NULL;
BYTE *pbSerializedElement = NULL;
DWORD cbSerializedElement;
assert(pRegStore);
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (pRegStore->fProtected) {
if (!CertSerializeCertificateStoreElement(
pCertContext,
0, // dwFlags
NULL, // pbElement
&cbSerializedElement
)) goto SerializeCertError;
if (NULL == (pbSerializedElement = (BYTE *) PkiNonzeroAlloc(
cbSerializedElement)))
goto OutOfMemory;
if (!CertSerializeCertificateStoreElement(
pCertContext,
0, // dwFlags
pbSerializedElement,
&cbSerializedElement
)) goto SerializeCertError;
fResult = I_CertProtectFunction(
CERT_PROT_ADD_ROOT_FUNC_ID,
0, // dwFlags
NULL, // pwszIn
pbSerializedElement,
cbSerializedElement,
NULL, // ppbOut
NULL // pcbOut
);
} else {
// If the certificate doesn't already exist, then, prompt the user
if (!RegStoreProvReadCert(
hStoreProv,
pCertContext,
0, // dwFlags
&pProvCertContext)) {
if (IDYES != IPR_ProtectedRootMessageBox(
NULL, // hRpc
pCertContext,
IDS_ROOT_MSG_BOX_ADD_ACTION,
0))
goto Cancelled;
}
fResult = RegStoreProvWriteCert(
hStoreProv,
pCertContext,
dwFlags
);
}
CommonReturn:
CertFreeCertificateContext(pProvCertContext);
PkiFree(pbSerializedElement);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
SET_ERROR(Cancelled, ERROR_CANCELLED)
TRACE_ERROR(SerializeCertError)
TRACE_ERROR(OutOfMemory)
}
//+-------------------------------------------------------------------------
// For "Root": prompt before deleting a cert.
//--------------------------------------------------------------------------
STATIC BOOL WINAPI RootStoreProvDeleteCert(
IN HCERTSTOREPROV hStoreProv,
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwFlags
)
{
BOOL fResult;
PREG_STORE pRegStore = (PREG_STORE) hStoreProv;
PCCERT_CONTEXT pProvCertContext = NULL;
assert(pRegStore);
if (IsInResync(pRegStore))
// Only delete from store cache, not from registry
return TRUE;
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
if (pRegStore->fProtected) {
BYTE rgbHash[MAX_HASH_LEN];
DWORD cbHash = MAX_HASH_LEN;
// get the thumbprint
if(!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbHash
)) goto GetCertHashPropError;
fResult = I_CertProtectFunction(
CERT_PROT_DELETE_ROOT_FUNC_ID,
0, // dwFlags
NULL, // pwszIn
rgbHash,
cbHash,
NULL, // ppbOut
NULL // pcbOut
);
} else {
// Prompt the user before deleting
if (RegStoreProvReadCert(
hStoreProv,
pCertContext,
0, // dwFlags
&pProvCertContext)) {
if (IDYES != IPR_ProtectedRootMessageBox(
NULL, // hRpc
pCertContext,
IDS_ROOT_MSG_BOX_DELETE_ACTION,
0))
goto Cancelled;
fResult = RegStoreProvDeleteCert(
hStoreProv,
pCertContext,
dwFlags
);
} else
fResult = TRUE;
}
CommonReturn:
CertFreeCertificateContext(pProvCertContext);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
SET_ERROR(Cancelled, ERROR_CANCELLED)
TRACE_ERROR(GetCertHashPropError)
}
//+=========================================================================
// Change Notify Support Functions
//==========================================================================
#if 0
typedef VOID (NTAPI * WAITORTIMERCALLBACKFUNC) (PVOID, BOOLEAN );
typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK ;
WINBASEAPI
BOOL
WINAPI
RegisterWaitForSingleObject(
PHANDLE hNewWaitObject,
HANDLE hObject,
WAITORTIMERCALLBACK Callback,
PVOID Context,
ULONG dwMilliseconds,
ULONG dwFlags
);
WINBASEAPI
BOOL
WINAPI
UnregisterWait(
HANDLE WaitHandle
);
WINBASEAPI
BOOL
WINAPI
UnregisterWaitEx(
HANDLE WaitHandle,
HANDLE CompletionEvent // INVALID_HANDLE_VALUE => create event
// to wait for
);
#endif
typedef BOOL (WINAPI *PFN_ILS_REGISTER_WAIT_FOR_SINGLE_OBJECT)(
PHANDLE hNewWaitObject,
HANDLE hObject,
ILS_WAITORTIMERCALLBACK Callback,
PVOID Context,
ULONG dwMilliseconds,
ULONG dwFlags
);
typedef BOOL (WINAPI *PFN_ILS_UNREGISTER_WAIT_EX)(
HANDLE WaitHandle,
HANDLE CompletionEvent // INVALID_HANDLE_VALUE => create event
// to wait for
);
#define sz_KERNEL32_DLL "kernel32.dll"
#define sz_RegisterWaitForSingleObject "RegisterWaitForSingleObject"
#define sz_UnregisterWaitEx "UnregisterWaitEx"
static HMODULE hKernel32Dll = NULL;
PFN_ILS_REGISTER_WAIT_FOR_SINGLE_OBJECT pfnILS_RegisterWaitForSingleObject;
PFN_ILS_UNREGISTER_WAIT_EX pfnILS_UnregisterWaitEx;
#define ILS_REG_WAIT_EXIT_HANDLE_INDEX 0
#define ILS_REG_WAIT_OBJECT_HANDLE_INDEX 1
#define ILS_REG_WAIT_HANDLE_COUNT 2
typedef struct _ILS_REG_WAIT_INFO {
HANDLE hThread;
DWORD dwThreadId;
HANDLE rghWait[ILS_REG_WAIT_HANDLE_COUNT];
ILS_WAITORTIMERCALLBACK Callback;
PVOID Context;
ULONG dwMilliseconds;
HANDLE hDoneEvent;
} ILS_REG_WAIT_INFO, *PILS_REG_WAIT_INFO;
DWORD WINAPI ILS_WaitForThreadProc(
LPVOID lpThreadParameter
)
{
PILS_REG_WAIT_INFO pWaitInfo = (PILS_REG_WAIT_INFO) lpThreadParameter;
DWORD cWait;
if (pWaitInfo->rghWait[ILS_REG_WAIT_OBJECT_HANDLE_INDEX])
cWait = ILS_REG_WAIT_HANDLE_COUNT;
else
cWait = ILS_REG_WAIT_HANDLE_COUNT - 1;
while (TRUE) {
DWORD dwWaitObject;
dwWaitObject = WaitForMultipleObjectsEx(
cWait,
pWaitInfo->rghWait,
FALSE, // bWaitAll
pWaitInfo->dwMilliseconds,
FALSE // bAlertable
);
switch (dwWaitObject) {
case WAIT_OBJECT_0 + ILS_REG_WAIT_OBJECT_HANDLE_INDEX:
pWaitInfo->Callback(pWaitInfo->Context, TRUE);
break;
case WAIT_TIMEOUT:
pWaitInfo->Callback(pWaitInfo->Context, FALSE);
break;
case WAIT_OBJECT_0 + ILS_REG_WAIT_EXIT_HANDLE_INDEX:
if (pWaitInfo->hDoneEvent) {
SetEvent(pWaitInfo->hDoneEvent);
}
goto CommonReturn;
break;
default:
goto InvalidWaitForObject;
}
}
CommonReturn:
return 0;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(InvalidWaitForObject)
}
BOOL
WINAPI
ILS_RegisterWaitForSingleObject(
PHANDLE hNewWaitObject,
HANDLE hObject,
ILS_WAITORTIMERCALLBACK Callback,
PVOID Context,
ULONG dwMilliseconds,
ULONG dwFlags
)
{
BOOL fResult;
PILS_REG_WAIT_INFO pWaitInfo = NULL;
HANDLE hDupObject = NULL;
if ( dwMilliseconds == 0 )
{
dwMilliseconds = INFINITE ;
}
if (NULL == (pWaitInfo = (PILS_REG_WAIT_INFO) PkiZeroAlloc(
sizeof(ILS_REG_WAIT_INFO))))
goto OutOfMemory;
if (hObject) {
if (!DuplicateHandle(
GetCurrentProcess(),
hObject,
GetCurrentProcess(),
&hDupObject,
0, // dwDesiredAccess
FALSE, // bInheritHandle
DUPLICATE_SAME_ACCESS
) || NULL == hDupObject)
goto DuplicateEventError;
pWaitInfo->rghWait[ILS_REG_WAIT_OBJECT_HANDLE_INDEX] = hDupObject;
}
pWaitInfo->Callback = Callback;
pWaitInfo->Context = Context;
pWaitInfo->dwMilliseconds = dwMilliseconds;
// Create event to be signaled to terminate the thread
if (NULL == (pWaitInfo->rghWait[ILS_REG_WAIT_EXIT_HANDLE_INDEX] =
CreateEvent(
NULL, // lpsa
FALSE, // fManualReset
FALSE, // fInitialState
NULL))) // lpszEventName
goto CreateThreadExitEventError;
// Create the thread to do the wait for
if (NULL == (pWaitInfo->hThread = CreateThread(
NULL, // lpThreadAttributes
0, // dwStackSize
ILS_WaitForThreadProc,
pWaitInfo,
0, // dwCreationFlags
&pWaitInfo->dwThreadId
)))
goto CreateThreadError;
fResult = TRUE;
CommonReturn:
*hNewWaitObject = (HANDLE) pWaitInfo;
return fResult;
ErrorReturn:
if (pWaitInfo) {
DWORD dwErr = GetLastError();
for (DWORD i = 0; i < ILS_REG_WAIT_HANDLE_COUNT; i++) {
if (pWaitInfo->rghWait[i])
CloseHandle(pWaitInfo->rghWait[i]);
}
PkiFree(pWaitInfo);
pWaitInfo = NULL;
SetLastError(dwErr);
}
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(DuplicateEventError)
TRACE_ERROR(CreateThreadExitEventError)
TRACE_ERROR(CreateThreadError)
}
BOOL
WINAPI
ILS_UnregisterWait(
HANDLE WaitHandle
)
{
PILS_REG_WAIT_INFO pWaitInfo = (PILS_REG_WAIT_INFO) WaitHandle;
if (pWaitInfo->dwThreadId != GetCurrentThreadId()) {
DWORD cWait;
HANDLE rghWait[2];
// On Win98 at ProcessDetach it might switch to one of the
// threads we created.
//
// Alternatively, we may be called from the callback itself via
// ILS_ExitWait()
// Create event to be signaled by thread when its done executing
pWaitInfo->hDoneEvent = CreateEvent(
NULL,
FALSE,
FALSE,
NULL
);
// Wake up the wait for thread.
SetEvent(pWaitInfo->rghWait[ILS_REG_WAIT_EXIT_HANDLE_INDEX]);
// Wait for either the thread to exit or the thread to signal us.
// We can't just wait on the thread handle because the
// loader lock might already be held if we are being called
// from a PROCESS_DETACH (in WinINet's DllMain for example).
rghWait[0] = pWaitInfo->hThread;
if (pWaitInfo->hDoneEvent) {
rghWait[1] = pWaitInfo->hDoneEvent;
cWait = 2;
} else {
cWait = 1;
}
WaitForMultipleObjectsEx(
cWait,
rghWait,
FALSE, // bWaitAll
INFINITE,
FALSE // bAlertable
);
if (pWaitInfo->hDoneEvent)
CloseHandle(pWaitInfo->hDoneEvent);
}
CloseHandle(pWaitInfo->hThread);
for (DWORD i = 0; i < ILS_REG_WAIT_HANDLE_COUNT; i++) {
if (pWaitInfo->rghWait[i])
CloseHandle(pWaitInfo->rghWait[i]);
}
PkiFree(pWaitInfo);
return TRUE;
}
BOOL
WINAPI
ILS_UnregisterWaitEx(
HANDLE WaitHandle,
HANDLE CompletionEvent // INVALID_HANDLE_VALUE => create event
// to wait for
)
{
assert(CompletionEvent == INVALID_HANDLE_VALUE);
return ILS_UnregisterWait(WaitHandle);
}
// Called from the callback function
BOOL
WINAPI
ILS_ExitWait(
HANDLE WaitHandle,
HMODULE hLibModule
)
{
ILS_UnregisterWait(WaitHandle);
if (hLibModule)
FreeLibraryAndExitThread(hLibModule, 0);
else
ExitThread(0);
}
STATIC void RegWaitForProcessAttach()
{
if (NULL == (hKernel32Dll = LoadLibraryA(sz_KERNEL32_DLL)))
goto LoadKernel32DllError;
if (NULL == (pfnILS_RegisterWaitForSingleObject =
(PFN_ILS_REGISTER_WAIT_FOR_SINGLE_OBJECT) GetProcAddress(
hKernel32Dll, sz_RegisterWaitForSingleObject)))
goto GetRegisterWaitForSingleObjectProcAddressError;
if (NULL == (pfnILS_UnregisterWaitEx =
(PFN_ILS_UNREGISTER_WAIT_EX) GetProcAddress(
hKernel32Dll, sz_UnregisterWaitEx)))
goto GetUnregisterWaitExProcAddressError;
CommonReturn:
return;
ErrorReturn:
pfnILS_RegisterWaitForSingleObject = ILS_RegisterWaitForSingleObject;
pfnILS_UnregisterWaitEx = ILS_UnregisterWaitEx;
goto CommonReturn;
TRACE_ERROR(LoadKernel32DllError)
TRACE_ERROR(GetRegisterWaitForSingleObjectProcAddressError)
TRACE_ERROR(GetUnregisterWaitExProcAddressError)
}
STATIC void RegWaitForProcessDetach()
{
if (hKernel32Dll) {
FreeLibrary(hKernel32Dll);
hKernel32Dll = NULL;
}
}
// Upon entry/exit, the resync list is locked by the caller
void ILS_RemoveEventFromResyncList(
IN HANDLE hEvent,
IN OUT DWORD *pcEntry,
IN OUT PILS_RESYNC_ENTRY *ppEntry
)
{
DWORD cOrigEntry = *pcEntry;
DWORD cNewEntry = 0;
PILS_RESYNC_ENTRY pEntry = *ppEntry;
DWORD i;
for (i = 0; i < cOrigEntry; i++) {
if (pEntry[i].hOrigEvent == hEvent) {
HANDLE hDupEvent;
hDupEvent = pEntry[i].hDupEvent;
if (hDupEvent)
CloseHandle(hDupEvent);
} else {
if (i != cNewEntry)
pEntry[cNewEntry] = pEntry[i];
cNewEntry++;
}
}
*pcEntry = cNewEntry;
}
// Upon entry/exit, the resync list is locked by the caller
BOOL ILS_AddRemoveEventToFromResyncList(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags,
IN OUT DWORD *pcEntry,
IN OUT PILS_RESYNC_ENTRY *ppEntry
)
{
BOOL fResult;
HANDLE hDupEvent = NULL;
DWORD cEntry;
PILS_RESYNC_ENTRY pEntry;
DWORD i;
assert(hEvent);
if (dwFlags & REG_STORE_CTRL_CANCEL_NOTIFY_FLAG) {
ILS_RemoveEventFromResyncList(
hEvent,
pcEntry,
ppEntry
);
return TRUE;
}
cEntry = *pcEntry;
pEntry = *ppEntry;
// First check if the hEvent is already in the list
for (i = 0; i < cEntry; i++) {
if (hEvent == pEntry[i].hOrigEvent)
return TRUE;
}
if (0 == (dwFlags & CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG)) {
if (!DuplicateHandle(
GetCurrentProcess(),
hEvent,
GetCurrentProcess(),
&hDupEvent,
0, // dwDesiredAccess
FALSE, // bInheritHandle
DUPLICATE_SAME_ACCESS
) || NULL == hDupEvent)
goto DuplicateEventError;
}
if (NULL == (pEntry = (PILS_RESYNC_ENTRY) PkiRealloc(pEntry,
(cEntry + 1) * sizeof(ILS_RESYNC_ENTRY))))
goto OutOfMemory;
pEntry[cEntry].hOrigEvent = hEvent;
pEntry[cEntry].pRegStore = pRegStore;
pEntry[cEntry].hDupEvent = hDupEvent;
*pcEntry = cEntry + 1;
*ppEntry = pEntry;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if (hDupEvent)
ILS_CloseHandle(hDupEvent);
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(DuplicateEventError)
TRACE_ERROR(OutOfMemory)
}
// Upon entry/exit, the resync list is locked by the caller
void ILS_SignalEventsOnResyncList(
IN OUT DWORD *pcEntry,
IN OUT PILS_RESYNC_ENTRY *ppEntry
)
{
DWORD cEntry = *pcEntry;
PILS_RESYNC_ENTRY pEntry = *ppEntry;
while (cEntry--) {
HANDLE hDupEvent;
hDupEvent = pEntry[cEntry].hDupEvent;
if (hDupEvent) {
SetEvent(hDupEvent);
CloseHandle(hDupEvent);
} else
SetEvent(pEntry[cEntry].hOrigEvent);
}
PkiFree(pEntry);
*pcEntry = 0;
*ppEntry = NULL;
}
// Upon entry/exit, the resync list is locked by the caller
void ILS_SignalAndFreeRegStoreResyncEntries(
IN PREG_STORE pRegStore,
IN OUT DWORD *pcEntry,
IN OUT PILS_RESYNC_ENTRY *ppEntry
)
{
DWORD cOrigEntry = *pcEntry;
DWORD cNewEntry = 0;
PILS_RESYNC_ENTRY pEntry = *ppEntry;
DWORD i;
for (i = 0; i < cOrigEntry; i++) {
if (pEntry[i].pRegStore == pRegStore) {
HANDLE hDupEvent;
hDupEvent = pEntry[i].hDupEvent;
if (hDupEvent) {
SetEvent(hDupEvent);
CloseHandle(hDupEvent);
} else
SetEvent(pEntry[i].hOrigEvent);
} else {
if (i != cNewEntry)
pEntry[cNewEntry] = pEntry[i];
cNewEntry++;
}
}
*pcEntry = cNewEntry;
}
STATIC BOOL ILS_RegNotifyChangeKeyValue(
IN HKEY hKey,
IN HANDLE hEvent
)
{
BOOL fResult;
LONG err;
err = RegNotifyChangeKeyValue(
hKey,
TRUE, // bWatchSubtree
REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_CHANGE_LAST_SET,
hEvent,
TRUE // fAsynchronus
);
if (!(ERROR_SUCCESS == err || ERROR_KEY_DELETED == err))
goto RegNotifyChangeKeyValueError;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegNotifyChangeKeyValueError, err)
}
//+=========================================================================
// Client "GPT" Store Data Structures and Functions
//==========================================================================
static PGPT_STORE_CHANGE_INFO pLMGptStoreChangeInfo;
typedef HANDLE (WINAPI *PFN_ENTER_CRITICAL_POLICY_SECTION)(
IN BOOL bMachine
);
typedef BOOL (WINAPI *PFN_LEAVE_CRITICAL_POLICY_SECTION)(
IN HANDLE hSection
);
typedef BOOL (WINAPI *PFN_REGISTER_GP_NOTIFICATION)(
IN HANDLE hEvent,
IN BOOL bMachine
);
typedef BOOL (WINAPI *PFN_UNREGISTER_GP_NOTIFICATION)(
IN HANDLE hEvent
);
#define sz_USERENV_DLL "userenv.dll"
#define sz_EnterCriticalPolicySection "EnterCriticalPolicySection"
#define sz_LeaveCriticalPolicySection "LeaveCriticalPolicySection"
#define sz_RegisterGPNotification "RegisterGPNotification"
#define sz_UnregisterGPNotification "UnregisterGPNotification"
static fLoadedUserEnvDll = FALSE;
static HMODULE hUserEnvDll = NULL;
static PFN_ENTER_CRITICAL_POLICY_SECTION pfnEnterCriticalPolicySection = NULL;
static PFN_LEAVE_CRITICAL_POLICY_SECTION pfnLeaveCriticalPolicySection = NULL;
static PFN_REGISTER_GP_NOTIFICATION pfnRegisterGPNotification = NULL;
static PFN_UNREGISTER_GP_NOTIFICATION pfnUnregisterGPNotification = NULL;
//+-------------------------------------------------------------------------
// Lock and unlock GPT_STORE functions
//--------------------------------------------------------------------------
static inline void GptStoreLock()
{
EnterCriticalSection(&ILS_CriticalSection);
}
static inline void GptStoreUnlock()
{
LeaveCriticalSection(&ILS_CriticalSection);
}
STATIC void GptLoadUserEnvDll()
{
HMODULE hDll;
if (fLoadedUserEnvDll)
return;
// Do load library without holding a lock
hDll = LoadLibraryA(sz_USERENV_DLL);
GptStoreLock();
if (fLoadedUserEnvDll) {
if (hDll)
FreeLibrary(hDll);
goto CommonReturn;
}
if (NULL == hDll)
goto LoadUserEnvDllError;
if (pfnEnterCriticalPolicySection =
(PFN_ENTER_CRITICAL_POLICY_SECTION) GetProcAddress(
hDll, sz_EnterCriticalPolicySection)) {
if (NULL == (pfnLeaveCriticalPolicySection =
(PFN_LEAVE_CRITICAL_POLICY_SECTION) GetProcAddress(
hDll, sz_LeaveCriticalPolicySection))) {
pfnEnterCriticalPolicySection = NULL;
#if DBG
DWORD dwErr = GetLastError();
DbgPrintf(DBG_SS_CRYPT32,
"userenv.dll:: GetProcAddress(%s) returned error: %d 0x%x\n",
sz_LeaveCriticalPolicySection, dwErr, dwErr);
#endif
}
} else {
#if DBG
DWORD dwErr = GetLastError();
DbgPrintf(DBG_SS_CRYPT32,
"userenv.dll:: GetProcAddress(%s) returned error: %d 0x%x\n",
sz_EnterCriticalPolicySection, dwErr, dwErr);
#endif
}
if (pfnRegisterGPNotification =
(PFN_REGISTER_GP_NOTIFICATION) GetProcAddress(
hDll, sz_RegisterGPNotification)) {
if (NULL == (pfnUnregisterGPNotification =
(PFN_UNREGISTER_GP_NOTIFICATION) GetProcAddress(
hDll, sz_UnregisterGPNotification))) {
pfnRegisterGPNotification = NULL;
#if DBG
DWORD dwErr = GetLastError();
DbgPrintf(DBG_SS_CRYPT32,
"userenv.dll:: GetProcAddress(%s) returned error: %d 0x%x\n",
sz_UnregisterGPNotification, dwErr, dwErr);
#endif
}
} else {
#if DBG
DWORD dwErr = GetLastError();
DbgPrintf(DBG_SS_CRYPT32,
"userenv.dll:: GetProcAddress(%s) returned error: %d 0x%x\n",
sz_RegisterGPNotification, dwErr, dwErr);
#endif
}
if (pfnEnterCriticalPolicySection || pfnRegisterGPNotification)
hUserEnvDll = hDll;
else
FreeLibrary(hDll);
CommonReturn:
fLoadedUserEnvDll = TRUE;
GptStoreUnlock();
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(LoadUserEnvDllError)
}
STATIC HANDLE GptStoreEnterCriticalPolicySection(
IN BOOL bMachine
)
{
#if 1
// ATTENTION:: entering this critical section is causing numerous hanging,
// deadlock problems
return NULL;
#else
HANDLE hSection;
GptLoadUserEnvDll();
if (NULL == pfnEnterCriticalPolicySection)
return NULL;
assert(hUserEnvDll);
assert(pfnLeaveCriticalPolicySection);
if (NULL == (hSection = pfnEnterCriticalPolicySection(bMachine)))
goto EnterCriticalPolicySectionError;
CommonReturn:
return hSection;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(EnterCriticalPolicySectionError)
#endif
}
STATIC void GptStoreLeaveCriticalPolicySection(
IN HANDLE hSection
)
{
if (hSection) {
assert(hUserEnvDll);
assert(pfnLeaveCriticalPolicySection);
if (!pfnLeaveCriticalPolicySection(hSection))
goto LeaveCriticalPolicySectionError;
}
CommonReturn:
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(LeaveCriticalPolicySectionError)
}
STATIC void GptStoreSignalAndFreeRegStoreResyncEntries(
IN PREG_STORE pRegStore
)
{
GptStoreLock();
if (pLMGptStoreChangeInfo)
ILS_SignalAndFreeRegStoreResyncEntries(
pRegStore,
&pLMGptStoreChangeInfo->cNotifyEntry,
&pLMGptStoreChangeInfo->rgNotifyEntry
);
GptStoreUnlock();
}
STATIC void GptStoreProcessAttach()
{
}
STATIC void GptStoreProcessDetach()
{
FreeGptStoreChangeInfo(&pLMGptStoreChangeInfo);
if (hUserEnvDll) {
FreeLibrary(hUserEnvDll);
hUserEnvDll = NULL;
}
}
STATIC VOID NTAPI GptWaitForCallback(
PVOID Context,
BOOLEAN fWaitOrTimedOut // ???
)
{
PGPT_STORE_CHANGE_INFO pInfo = (PGPT_STORE_CHANGE_INFO) Context;
DWORD cEntry;
PILS_RESYNC_ENTRY pEntry;
assert(pInfo);
assert(LM_GPT_CHANGE_INFO_TYPE == pInfo->dwType ||
CU_GPT_CHANGE_INFO_TYPE == pInfo->dwType);
if (NULL == pInfo)
return;
if (!(LM_GPT_CHANGE_INFO_TYPE == pInfo->dwType ||
CU_GPT_CHANGE_INFO_TYPE == pInfo->dwType))
return;
if (pInfo->hGPNotificationEvent) {
// We are called for all GPNotification events.
// Check that we also have a registry change notify.
if (pInfo->hPoliciesKey) {
assert(pInfo->hPoliciesEvent);
if (WAIT_OBJECT_0 != WaitForSingleObjectEx(
pInfo->hPoliciesEvent,
0, // dwMilliseconds
FALSE // bAlertable
))
return;
// When policy is applied, the registry key is deleted before
// reapplying policy.
ILS_CloseRegistryKey(pInfo->hPoliciesKey);
}
// Re-Open the Software\Policies\Microsoft\SystemCertificates registry
// key
//
// Ignore BACKUP_RESTORE case, in a different thread
pInfo->hPoliciesKey = OpenSubKey(
pInfo->hKeyBase,
GROUP_POLICY_STORE_REGPATH,
CERT_STORE_READONLY_FLAG
);
}
if (pInfo->hPoliciesKey) {
assert(pInfo->hPoliciesEvent);
// Re-arm the registry notify
ILS_RegNotifyChangeKeyValue(
pInfo->hPoliciesKey,
pInfo->hPoliciesEvent
);
}
// Minimize window of potential deadlock by only getting the values
// while holding the lock.
if (pInfo->pRegStore) {
assert(CU_GPT_CHANGE_INFO_TYPE == pInfo->dwType);
CertPerfIncrementChangeNotifyCuGpCount();
LockRegStore(pInfo->pRegStore);
} else {
assert(LM_GPT_CHANGE_INFO_TYPE == pInfo->dwType);
CertPerfIncrementChangeNotifyLmGpCount();
GptStoreLock();
}
cEntry = pInfo->cNotifyEntry;
pEntry = pInfo->rgNotifyEntry;
pInfo->cNotifyEntry = 0;
pInfo->rgNotifyEntry = NULL;
ILS_SignalEventsOnResyncList(&cEntry, &pEntry);
if (pInfo->pRegStore)
UnlockRegStore(pInfo->pRegStore);
else
GptStoreUnlock();
CertPerfIncrementChangeNotifyCount();
}
STATIC void FreeGptStoreChangeInfo(
IN OUT PGPT_STORE_CHANGE_INFO *ppInfo
)
{
PGPT_STORE_CHANGE_INFO pInfo = *ppInfo;
if (NULL == pInfo)
return;
if (!(LM_GPT_CHANGE_INFO_TYPE == pInfo->dwType ||
CU_GPT_CHANGE_INFO_TYPE == pInfo->dwType))
return;
// Unregister the wait for callback
if (pInfo->hRegWaitFor)
pfnILS_UnregisterWaitEx(pInfo->hRegWaitFor, INVALID_HANDLE_VALUE);
if (pInfo->hGPNotificationEvent) {
assert(hUserEnvDll && pfnUnregisterGPNotification);
pfnUnregisterGPNotification(
pInfo->hGPNotificationEvent);
CloseHandle(pInfo->hGPNotificationEvent);
}
ILS_CloseRegistryKey(pInfo->hPoliciesKey);
if (pInfo->hPoliciesEvent)
CloseHandle(pInfo->hPoliciesEvent);
// To inhibit any potential deadlock, do following without entering
// the critical section
ILS_SignalEventsOnResyncList(
&pInfo->cNotifyEntry,
&pInfo->rgNotifyEntry
);
PkiFree(pInfo);
*ppInfo = NULL;
}
STATIC PGPT_STORE_CHANGE_INFO CreateGptStoreChangeInfo(
IN PREG_STORE pRegStore,
IN BOOL fMachine
)
{
PGPT_STORE_CHANGE_INFO pInfo = NULL;
DWORD dwErr;
BOOL fGPNotify = FALSE;
GptLoadUserEnvDll();
if (NULL == (pInfo = (PGPT_STORE_CHANGE_INFO) PkiZeroAlloc(
sizeof(GPT_STORE_CHANGE_INFO))))
goto OutOfMemory;
if (fMachine) {
pInfo->dwType = LM_GPT_CHANGE_INFO_TYPE;
// pInfo->pRegStore = NULL;
} else {
pInfo->dwType = CU_GPT_CHANGE_INFO_TYPE;
pInfo->pRegStore = pRegStore;
}
pInfo->hKeyBase = pRegStore->GptPara.hKeyBase;
// Create our own event to be notified on a change
if (NULL == (pInfo->hPoliciesEvent = CreateEvent(
NULL, // lpsa
FALSE, // fManualReset
FALSE, // fInitialState
NULL))) // lpszEventName
goto CreateEventError;
// If the RegisterGPNotification API exists in userenv.dll, use it.
if (pfnRegisterGPNotification) {
if (NULL == (pInfo->hGPNotificationEvent = CreateEvent(
NULL, // lpsa
FALSE, // fManualReset
FALSE, // fInitialState
NULL))) // lpszEventName
goto CreateEventError;
if (pfnRegisterGPNotification(
pInfo->hGPNotificationEvent,
fMachine
))
fGPNotify = TRUE;
else {
#if DBG
dwErr = GetLastError();
DbgPrintf(DBG_SS_CRYPT32,
"RegisterGPNotification returned error: %d 0x%x\n",
dwErr, dwErr);
#endif
CloseHandle(pInfo->hGPNotificationEvent);
pInfo->hGPNotificationEvent = NULL;
}
}
// Open the Software\Policies\Microsoft\SystemCertificates registry key
//
// Ignore BACKUP_RESTORE case
if (NULL == (pInfo->hPoliciesKey = OpenSubKey(
pInfo->hKeyBase,
GROUP_POLICY_STORE_REGPATH,
CERT_STORE_READONLY_FLAG
))) {
if (!fGPNotify) {
// Ignore error if subkey doesn't exist.
if (ERROR_FILE_NOT_FOUND == GetLastError())
goto SuccessReturn;
goto OpenSubKeyError;
}
} else {
// Arm the registry notify
if (!ILS_RegNotifyChangeKeyValue(
pInfo->hPoliciesKey,
pInfo->hPoliciesEvent
))
goto RegNotifyChangeKeyValueError;
}
if (!pfnILS_RegisterWaitForSingleObject(
&pInfo->hRegWaitFor,
fGPNotify ? pInfo->hGPNotificationEvent : pInfo->hPoliciesEvent,
GptWaitForCallback,
(PVOID) pInfo,
INFINITE, // no timeout
WT_EXECUTEINWAITTHREAD
)) {
pInfo->hRegWaitFor = NULL;
dwErr = GetLastError();
goto RegisterWaitForError;
}
SuccessReturn:
CommonReturn:
return pInfo;
ErrorReturn:
dwErr = GetLastError();
FreeGptStoreChangeInfo(&pInfo);
SetLastError(dwErr);
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(CreateEventError)
TRACE_ERROR(OpenSubKeyError)
TRACE_ERROR(RegNotifyChangeKeyValueError)
SET_ERROR_VAR(RegisterWaitForError, dwErr)
}
// For LocalMachine: a single store change info data structure for all LMGP
// stores.
//
// For CurrentUser: each CUCP store has its own store change info.
STATIC BOOL RegGptStoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
)
{
BOOL fResult;
PGPT_STORE_CHANGE_INFO pInfo;
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_LM_GPT_FLAG) {
if (NULL == (pInfo = pLMGptStoreChangeInfo)) {
if (NULL == (pInfo = CreateGptStoreChangeInfo(
pRegStore,
TRUE // fMachine
)))
goto CreateChangeInfoError;
GptStoreLock();
if (pLMGptStoreChangeInfo) {
GptStoreUnlock();
FreeGptStoreChangeInfo(&pInfo);
pInfo = pLMGptStoreChangeInfo;
} else {
pLMGptStoreChangeInfo = pInfo;
GptStoreUnlock();
}
}
assert(LM_GPT_CHANGE_INFO_TYPE == pInfo->dwType);
GptStoreLock();
fResult = ILS_AddRemoveEventToFromResyncList(
pRegStore,
hEvent,
dwFlags,
&pInfo->cNotifyEntry,
&pInfo->rgNotifyEntry
);
GptStoreUnlock();
} else {
if (NULL == (pInfo = pRegStore->pGptStoreChangeInfo)) {
if (NULL == (pInfo = CreateGptStoreChangeInfo(
pRegStore,
FALSE // fMachine
)))
goto CreateChangeInfoError;
LockRegStore(pRegStore);
if (pRegStore->pGptStoreChangeInfo) {
UnlockRegStore(pRegStore);
FreeGptStoreChangeInfo(&pInfo);
pInfo = pRegStore->pGptStoreChangeInfo;
} else {
pRegStore->pGptStoreChangeInfo = pInfo;
UnlockRegStore(pRegStore);
}
}
assert(CU_GPT_CHANGE_INFO_TYPE == pInfo->dwType);
LockRegStore(pRegStore);
fResult = ILS_AddRemoveEventToFromResyncList(
pRegStore,
hEvent,
dwFlags,
&pInfo->cNotifyEntry,
&pInfo->rgNotifyEntry
);
UnlockRegStore(pRegStore);
}
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateChangeInfoError)
}
STATIC BOOL OpenAllFromGptRegistry(
IN PREG_STORE pRegStore,
IN HCERTSTORE hCertStore
)
{
BOOL fResult;
HANDLE hSection = NULL;
LockRegStore(pRegStore);
if (0 == (pRegStore->dwFlags & CERT_REGISTRY_STORE_REMOTE_FLAG))
hSection = GptStoreEnterCriticalPolicySection(
pRegStore->dwFlags & CERT_REGISTRY_STORE_LM_GPT_FLAG
);
assert(NULL == pRegStore->hKey);
if (NULL == (pRegStore->hKey = OpenSubKey(
pRegStore->GptPara.hKeyBase,
pRegStore->GptPara.pwszRegPath,
pRegStore->dwFlags
))) {
if (ERROR_FILE_NOT_FOUND != GetLastError() ||
(pRegStore->dwFlags & CERT_STORE_OPEN_EXISTING_FLAG))
goto OpenSubKeyError;
fResult = TRUE;
goto CommonReturn;
}
// fResult = OpenAllFromSerializedRegistry(pRegStore, hCertStore);
// Ignore any errors
OpenAllFromRegistry(pRegStore, hCertStore);
fResult = TRUE;
CommonReturn:
ILS_CloseRegistryKey(pRegStore->hKey);
pRegStore->hKey = NULL;
GptStoreLeaveCriticalPolicySection(hSection);
UnlockRegStore(pRegStore);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenSubKeyError)
}
STATIC BOOL CommitAllToGptRegistry(
IN PREG_STORE pRegStore,
IN DWORD dwFlags
)
{
#if 1
return TRUE;
#else
BOOL fResult;
BOOL fTouched;
DWORD dwSaveFlags;
LockRegStore(pRegStore);
if (dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG)
fTouched = TRUE;
else if (dwFlags & CERT_STORE_CTRL_COMMIT_CLEAR_FLAG)
fTouched = FALSE;
else
fTouched = pRegStore->fTouched;
if (fTouched) {
if (pRegStore->dwFlags & CERT_STORE_READONLY_FLAG)
goto AccessDenied;
} else {
pRegStore->fTouched = FALSE;
fResult = TRUE;
goto CommonReturn;
}
assert(NULL == pRegStore->hKey);
if (NULL == (pRegStore->hKey = OpenSubKey(
pRegStore->GptPara.hKeyBase,
pRegStore->GptPara.pwszRegPath,
pRegStore->dwFlags
)))
goto OpenSubKeyError;
dwSaveFlags = pRegStore->dwFlags;
pRegStore->dwFlags &= ~CERT_STORE_OPEN_EXISTING_FLAG;
fResult = CommitAllToSerializedRegistry(pRegStore, dwFlags);
pRegStore->dwFlags = dwSaveFlags;
CommonReturn:
ILS_CloseRegistryKey(pRegStore->hKey);
pRegStore->hKey = NULL;
UnlockRegStore(pRegStore);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(AccessDenied, E_ACCESSDENIED)
TRACE_ERROR(OpenSubKeyError)
#endif
}
//+=========================================================================
// Win95 Notify Store Data Structures and Functions
//
// Win95/Win98 don't support registry change notification.
//
// On Win95 we pulse an event each time a store context element is written
// or deleted.
//==========================================================================
static BOOL fWin95StoreInitialized;
static HANDLE hWin95RegWaitFor;
static DWORD cWin95StoreResyncEntry;
static ILS_RESYNC_ENTRY *pWin95StoreResyncEntry;
//+-------------------------------------------------------------------------
// Lock and unlock WIN95_STORE functions
//--------------------------------------------------------------------------
static inline void Win95StoreLock()
{
EnterCriticalSection(&ILS_CriticalSection);
}
static inline void Win95StoreUnlock()
{
LeaveCriticalSection(&ILS_CriticalSection);
}
STATIC void Win95StoreSignalAndFreeRegStoreResyncEntries(
IN PREG_STORE pRegStore
)
{
if (NULL == hWin95NotifyEvent)
return;
Win95StoreLock();
ILS_SignalAndFreeRegStoreResyncEntries(
pRegStore,
&cWin95StoreResyncEntry,
&pWin95StoreResyncEntry
);
Win95StoreUnlock();
}
STATIC void Win95StoreProcessAttach()
{
if (FIsWinNT())
return;
hWin95NotifyEvent = CreateEventA(
NULL, // lpsa
TRUE, // fManualReset
FALSE, // fInitialState
"Win95CertStoreNotifyEvent"
);
if (NULL == hWin95NotifyEvent)
goto CreateWin95NotifyEventError;
CommonReturn:
return;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(CreateWin95NotifyEventError)
}
STATIC void Win95StoreProcessDetach()
{
if (NULL == hWin95NotifyEvent)
return;
if (fWin95StoreInitialized) {
// Unregister the wait for callback
assert(hWin95RegWaitFor);
pfnILS_UnregisterWaitEx(hWin95RegWaitFor, INVALID_HANDLE_VALUE);
// To inhibit any potential deadlock, do following without entering
// the critical section
ILS_SignalEventsOnResyncList(
&cWin95StoreResyncEntry,
&pWin95StoreResyncEntry
);
fWin95StoreInitialized = FALSE;
}
CloseHandle(hWin95NotifyEvent);
}
STATIC VOID NTAPI Win95WaitForCallback(
PVOID Context,
BOOLEAN fWaitOrTimedOut // ???
)
{
DWORD cEntry;
PILS_RESYNC_ENTRY pEntry;
Win95StoreLock();
cEntry = cWin95StoreResyncEntry;
pEntry = pWin95StoreResyncEntry;
cWin95StoreResyncEntry = 0;
pWin95StoreResyncEntry = NULL;
Win95StoreUnlock();
ILS_SignalEventsOnResyncList(
&cEntry,
&pEntry
);
}
STATIC BOOL Win95StoreChangeInit()
{
BOOL fResult;
DWORD dwErr;
HANDLE hRegWaitFor;
if (fWin95StoreInitialized)
return TRUE;
Win95StoreLock();
if (fWin95StoreInitialized)
goto SuccessReturn;
assert(hWin95NotifyEvent);
if (!pfnILS_RegisterWaitForSingleObject(
&hRegWaitFor,
hWin95NotifyEvent,
Win95WaitForCallback,
NULL, // Context
INFINITE, // no timeout
0 // no flags (normal)
)) {
dwErr = GetLastError();
goto RegisterWaitForError;
}
hWin95RegWaitFor = hRegWaitFor;
SuccessReturn:
fResult = TRUE;
fWin95StoreInitialized = TRUE;
CommonReturn:
Win95StoreUnlock();
return fResult;;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR_VAR(RegisterWaitForError, dwErr)
}
STATIC BOOL RegWin95StoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
)
{
BOOL fResult;
assert(hWin95NotifyEvent);
if (!Win95StoreChangeInit())
return FALSE;
Win95StoreLock();
fResult = ILS_AddRemoveEventToFromResyncList(
pRegStore,
hEvent,
dwFlags,
&cWin95StoreResyncEntry,
&pWin95StoreResyncEntry
);
Win95StoreUnlock();
return fResult;
}
//+=========================================================================
// Roaming Store Functions
//==========================================================================
#if 0
SHSTDAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR lpszPath);
#endif
typedef HRESULT (STDAPICALLTYPE *PFN_GET_FOLDER_PATH) (
HWND hwnd,
int csidl,
HANDLE hToken,
DWORD dwFlags,
LPWSTR lpszPath
);
#define sz_SHELL32_DLL "shell32.dll"
#define sz_GetFolderPath "SHGetFolderPathW"
static fLoadedShell32Dll = FALSE;
static HMODULE hShell32Dll = NULL;
static PFN_GET_FOLDER_PATH pfnGetFolderPath = NULL;
#if 0
// from \nt\public\internal\ds\inc\userenvp.h
USERENVAPI
DWORD
WINAPI
GetUserAppDataPathW(
IN HANDLE hToken,
IN BOOL fLocalAppData,
OUT LPWSTR lpFolderPath
);
#endif
typedef DWORD (WINAPI *PFN_GET_USER_APP_DATA_PATH) (
IN HANDLE hToken,
IN BOOL fLocalAppData,
OUT LPWSTR lpFolderPath
);
#define sz_ROAMING_USERENV_DLL "userenv.dll"
#define wsz_ROAMING_USERENV_DLL L"userenv.dll"
// From \nt\ds\security\gina\userenv\main\userenv.def
// GetUserAppDataPathW @149 NONAME ;Internal
#define ORDINAL_GetUserAppDataPath 149
// First version to support GetUserAppDataPath
#define ROAMING_USERENV_DLL_VER_MS (( 5 << 16) | 1 )
#define ROAMING_USERENV_DLL_VER_LS (( 2465 << 16) | 0 )
static fLoadedRoamingUserenvDll = FALSE;
static HMODULE hRoamingUserenvDll = NULL;
static PFN_GET_USER_APP_DATA_PATH pfnGetUserAppDataPath = NULL;
static inline void RoamingStoreLock()
{
EnterCriticalSection(&ILS_CriticalSection);
}
static inline void RoamingStoreUnlock()
{
LeaveCriticalSection(&ILS_CriticalSection);
}
STATIC void RoamingStoreProcessAttach()
{
}
STATIC void RoamingStoreProcessDetach()
{
if (hShell32Dll) {
FreeLibrary(hShell32Dll);
hShell32Dll = NULL;
}
if (hRoamingUserenvDll) {
FreeLibrary(hRoamingUserenvDll);
hRoamingUserenvDll = NULL;
}
}
STATIC void RoamingStoreLoadShell32Dll()
{
if (fLoadedShell32Dll)
return;
RoamingStoreLock();
if (fLoadedShell32Dll)
goto CommonReturn;
if (NULL == (hShell32Dll = LoadLibraryA(sz_SHELL32_DLL)))
goto LoadShell32DllError;
if (NULL == (pfnGetFolderPath =
(PFN_GET_FOLDER_PATH) GetProcAddress(hShell32Dll,
sz_GetFolderPath)))
goto GetFolderPathProcAddressError;
CommonReturn:
fLoadedShell32Dll = TRUE;
RoamingStoreUnlock();
return;
ErrorReturn:
if (hShell32Dll) {
FreeLibrary(hShell32Dll);
hShell32Dll = NULL;
pfnGetFolderPath = NULL;
}
goto CommonReturn;
TRACE_ERROR(LoadShell32DllError)
TRACE_ERROR(GetFolderPathProcAddressError)
}
STATIC void RoamingStoreLoadUserenvDll()
{
DWORD dwFileVersionMS;
DWORD dwFileVersionLS;
if (fLoadedRoamingUserenvDll)
return;
RoamingStoreLock();
if (fLoadedRoamingUserenvDll)
goto CommonReturn;
// GetUserAppDataPath() not supported until later versions of userenv.dll
// in WXP
if (!I_CryptGetFileVersion(
wsz_ROAMING_USERENV_DLL,
&dwFileVersionMS,
&dwFileVersionLS
))
goto GetUserenvFileVersionError;
if (ROAMING_USERENV_DLL_VER_MS < dwFileVersionMS)
;
else if (ROAMING_USERENV_DLL_VER_MS == dwFileVersionMS &&
ROAMING_USERENV_DLL_VER_LS <= dwFileVersionLS)
;
else
goto Userenv_GetUserAppDataPathNotSupported;
if (NULL == (hRoamingUserenvDll = LoadLibraryA(sz_ROAMING_USERENV_DLL)))
goto LoadUserenvDllError;
if (NULL == (pfnGetUserAppDataPath =
(PFN_GET_USER_APP_DATA_PATH) GetProcAddress(hRoamingUserenvDll,
(LPCSTR) ORDINAL_GetUserAppDataPath)))
goto GetUserAppDataPathProcAddressError;
CommonReturn:
fLoadedRoamingUserenvDll = TRUE;
RoamingStoreUnlock();
return;
ErrorReturn:
if (hRoamingUserenvDll) {
FreeLibrary(hRoamingUserenvDll);
hRoamingUserenvDll = NULL;
pfnGetUserAppDataPath = NULL;
}
goto CommonReturn;
TRACE_ERROR(GetUserenvFileVersionError)
SET_ERROR_VAR(Userenv_GetUserAppDataPathNotSupported, ERROR_NOT_SUPPORTED)
TRACE_ERROR(LoadUserenvDllError)
TRACE_ERROR(GetUserAppDataPathProcAddressError)
}
STATIC HANDLE GetRoamingToken()
{
HANDLE hToken = NULL;
DWORD dwErr;
if (!FIsWinNT()) {
return NULL;
}
//
// first, attempt to look at the thread token. If none exists,
// which is true if the thread is not impersonating, try the
// process token.
//
if (!OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY | TOKEN_IMPERSONATE,
TRUE,
&hToken
)) {
dwErr = GetLastError();
if (ERROR_NO_TOKEN != dwErr)
goto OpenThreadTokenError;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &hToken)) {
dwErr = GetLastError();
goto OpenProcessTokenError;
}
}
CommonReturn:
return hToken;
ErrorReturn:
hToken = NULL;
goto CommonReturn;
SET_ERROR_VAR(OpenThreadTokenError, dwErr)
SET_ERROR_VAR(OpenProcessTokenError, dwErr)
}
STATIC
DWORD
FastGetUserAppDataPath(
IN HANDLE hToken,
OUT WCHAR wszFolderPath[MAX_PATH]
)
{
DWORD dwErr;
RoamingStoreLoadUserenvDll();
if (NULL == hRoamingUserenvDll)
goto ErrorReturn;
assert(pfnGetUserAppDataPath);
wszFolderPath[0] = L'\0';
__try {
dwErr = pfnGetUserAppDataPath(
hToken,
FALSE,
wszFolderPath
);
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
goto GetUserAppDataPathException;
}
if (ERROR_SUCCESS != dwErr || L'\0' == wszFolderPath[0])
goto GetUserAppDataPathError;
#if DBG
DbgPrintf(DBG_SS_CRYPT32, "userenv!GetUserAppDataPath:: %S\n",
wszFolderPath);
#endif
dwErr = ERROR_SUCCESS;
CommonReturn:
return dwErr;
ErrorReturn:
dwErr = ERROR_FILE_NOT_FOUND;
goto CommonReturn;
SET_ERROR_VAR(GetUserAppDataPathException, dwErr)
SET_ERROR_VAR(GetUserAppDataPathError, dwErr)
}
STATIC
DWORD
SlowGetUserAppDataPath(
IN HANDLE hToken,
OUT WCHAR wszFolderPath[MAX_PATH]
)
{
DWORD dwErr;
HRESULT hr;
RoamingStoreLoadShell32Dll();
if (NULL == hShell32Dll)
goto ErrorReturn;
assert(pfnGetFolderPath);
wszFolderPath[0] = L'\0';
hr = pfnGetFolderPath(
NULL, // hwndOwner
CSIDL_APPDATA | CSIDL_FLAG_CREATE,
hToken,
0, // dwFlags
wszFolderPath
);
if (S_OK != hr || L'\0' == wszFolderPath[0])
goto GetFolderPathError;
#if DBG
DbgPrintf(DBG_SS_CRYPT32, "SHFolderPath(CSIDL_APPDATA):: %S\n",
wszFolderPath);
#endif
dwErr = ERROR_SUCCESS;
CommonReturn:
return dwErr;
ErrorReturn:
dwErr = ERROR_FILE_NOT_FOUND;
goto CommonReturn;
SET_ERROR_VAR(GetFolderPathError, hr)
}
LPWSTR
ILS_GetRoamingStoreDirectory(
IN LPCWSTR pwszStoreName
)
{
DWORD dwErr;
HANDLE hToken = NULL;
LPWSTR pwszDir = NULL;
WCHAR wszFolderPath[MAX_PATH];
LPCWSTR rgpwszName[] = { wszFolderPath, pwszStoreName };
SYSTEM_NAME_GROUP NameGroup;
hToken = GetRoamingToken();
dwErr = FastGetUserAppDataPath(hToken, wszFolderPath);
if (ERROR_SUCCESS != dwErr)
dwErr = SlowGetUserAppDataPath(hToken, wszFolderPath);
if (ERROR_SUCCESS != dwErr)
goto GetUserAppDataPathError;
NameGroup.cName = sizeof(rgpwszName) / sizeof(rgpwszName[0]);
NameGroup.rgpwszName = rgpwszName;
if (NULL == (pwszDir = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
CommonReturn:
if (hToken)
ILS_CloseHandle(hToken);
return pwszDir;
ErrorReturn:
pwszDir = NULL;
goto CommonReturn;
SET_ERROR_VAR(GetUserAppDataPathError, dwErr)
TRACE_ERROR(FormatSystemNamePathError)
}
static DWORD rgdwCreateFileRetryMilliseconds[] =
{ 1, 10, 100, 500, 1000, 5000 };
#define MAX_CREATE_FILE_RETRY_COUNT \
(sizeof(rgdwCreateFileRetryMilliseconds) / \
sizeof(rgdwCreateFileRetryMilliseconds[0]))
BOOL
ILS_ReadElementFromFile(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_BACKUP_RESTORE_FLAG may be set
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
BOOL fResult;
DWORD dwErr;
LPWSTR pwszFilename = NULL;
LPCWSTR rgpwszName[] = { pwszStoreDir, pwszContextName, wszHashName };
SYSTEM_NAME_GROUP NameGroup;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cbBytesRead;
BYTE *pbElement = NULL;
DWORD cbElement;
DWORD dwRetryCount;
NameGroup.cName = sizeof(rgpwszName) / sizeof(rgpwszName[0]);
NameGroup.rgpwszName = rgpwszName;
if (NULL == (pwszFilename = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
dwRetryCount = 0;
while (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
pwszFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // lpsa
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
FILE_FLAG_BACKUP_SEMANTICS : 0),
NULL // hTemplateFile
))) {
dwErr = GetLastError();
if ((ERROR_SHARING_VIOLATION == dwErr ||
ERROR_ACCESS_DENIED == dwErr) &&
MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
dwRetryCount++;
} else {
if (ERROR_PATH_NOT_FOUND == dwErr)
dwErr = ERROR_FILE_NOT_FOUND;
goto CreateFileError;
}
}
cbElement = GetFileSize(hFile, NULL);
if (0xFFFFFFFF == cbElement) goto FileSizeError;
if (0 == cbElement) goto EmptyFile;
if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
goto OutOfMemory;
if (!ReadFile(
hFile,
pbElement,
cbElement,
&cbBytesRead,
NULL // lpOverlapped
)) {
dwErr = GetLastError();
goto FileError;
}
fResult = TRUE;
CommonReturn:
PkiFree(pwszFilename);
if (INVALID_HANDLE_VALUE != hFile)
ILS_CloseHandle(hFile);
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
fResult = FALSE;
PkiFree(pbElement);
pbElement = NULL;
cbElement = 0;
goto CommonReturn;
TRACE_ERROR(FormatSystemNamePathError)
TRACE_ERROR(OutOfMemory)
SET_ERROR_VAR(CreateFileError, dwErr)
TRACE_ERROR(FileSizeError)
SET_ERROR_VAR(FileError, dwErr)
SET_ERROR(EmptyFile, CRYPT_E_FILE_ERROR)
}
BOOL
ILS_WriteElementToFile(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags, // CERT_STORE_CREATE_NEW_FLAG or
// CERT_STORE_BACKUP_RESTORE_FLAG may be set
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
DWORD dwErr;
LPWSTR pwszDir = NULL;
LPWSTR pwszFilename = NULL;
LPCWSTR rgpwszName[] = { pwszStoreDir, pwszContextName, wszHashName };
SYSTEM_NAME_GROUP NameGroup;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cbBytesWritten;
DWORD dwRetryCount;
NameGroup.cName = sizeof(rgpwszName) / sizeof(rgpwszName[0]);
NameGroup.rgpwszName = rgpwszName;
if (NULL == (pwszFilename = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
NameGroup.cName--;
if (NULL == (pwszDir = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
if (!I_RecursiveCreateDirectory(pwszDir, NULL))
goto CreateDirError;
dwRetryCount = 0;
while (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
pwszFilename,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
(dwFlags & CERT_STORE_CREATE_NEW_FLAG) ?
CREATE_NEW : CREATE_ALWAYS,
FILE_ATTRIBUTE_SYSTEM |
((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
FILE_FLAG_BACKUP_SEMANTICS : 0),
NULL // hTemplateFile
))) {
dwErr = GetLastError();
if ((ERROR_SHARING_VIOLATION == dwErr ||
ERROR_ACCESS_DENIED == dwErr) &&
MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
dwRetryCount++;
} else
goto CreateFileError;
}
if (!WriteFile(
hFile,
pbElement,
cbElement,
&cbBytesWritten,
NULL // lpOverlapped
)) {
dwErr = GetLastError();
goto WriteFileError;
}
fResult = TRUE;
CommonReturn:
if (INVALID_HANDLE_VALUE != hFile)
ILS_CloseHandle(hFile);
PkiFree(pwszFilename);
PkiFree(pwszDir);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatSystemNamePathError)
TRACE_ERROR(CreateDirError)
SET_ERROR_VAR(CreateFileError, dwErr)
SET_ERROR_VAR(WriteFileError, dwErr)
}
BOOL
ILS_DeleteElementFromDirectory(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN DWORD dwFlags
)
{
BOOL fResult;
DWORD dwErr;
LPWSTR pwszFilename = NULL;
LPCWSTR rgpwszName[] = { pwszStoreDir, pwszContextName, wszHashName };
SYSTEM_NAME_GROUP NameGroup;
DWORD dwRetryCount;
NameGroup.cName = sizeof(rgpwszName) / sizeof(rgpwszName[0]);
NameGroup.rgpwszName = rgpwszName;
if (NULL == (pwszFilename = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
dwRetryCount = 0;
while (!DeleteFileU(pwszFilename)) {
dwErr = GetLastError();
if ((ERROR_SHARING_VIOLATION == dwErr ||
ERROR_ACCESS_DENIED == dwErr) &&
MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
dwRetryCount++;
} else
goto DeleteFileError;
}
fResult = TRUE;
CommonReturn:
PkiFree(pwszFilename);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatSystemNamePathError)
SET_ERROR_VAR(DeleteFileError, dwErr)
}
BOOL
ILS_OpenAllElementsFromDirectory(
IN LPCWSTR pwszStoreDir,
IN LPCWSTR pwszContextName,
IN DWORD dwFlags,
IN void *pvArg,
IN PFN_ILS_OPEN_ELEMENT pfnOpenElement
)
{
BOOL fResult;
DWORD dwErr;
LPWSTR pwszDir = NULL;
LPCWSTR rgpwszName[] = { pwszStoreDir, pwszContextName, L"*" };
SYSTEM_NAME_GROUP NameGroup;
HANDLE hFindFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW FindFileData;
NameGroup.cName = sizeof(rgpwszName) / sizeof(rgpwszName[0]);
NameGroup.rgpwszName = rgpwszName;
if (NULL == (pwszDir = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
if (INVALID_HANDLE_VALUE == (hFindFile = FindFirstFileU(
pwszDir,
&FindFileData
))) {
dwErr = GetLastError();
if (!(ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr))
goto FindFirstFileError;
if (dwFlags & CERT_STORE_READONLY_FLAG)
goto FindFirstFileError;
// Attempt to create the directory. Need to remove trailing L"*".
PkiFree(pwszDir);
NameGroup.cName--;
if (NULL == (pwszDir = FormatSystemNamePath(1, &NameGroup)))
goto FormatSystemNamePathError;
if (!I_RecursiveCreateDirectory(pwszDir, NULL))
goto CreateDirError;
goto SuccessReturn;
}
while (TRUE) {
if (0 == (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes) &&
0 == FindFileData.nFileSizeHigh &&
0 != FindFileData.nFileSizeLow &&
L'\0' != FindFileData.cFileName[0]) {
BYTE *pbElement;
DWORD cbElement;
if (ILS_ReadElementFromFile(
pwszStoreDir,
pwszContextName,
FindFileData.cFileName,
dwFlags,
&pbElement,
&cbElement
)) {
fResult = pfnOpenElement(
FindFileData.cFileName,
pbElement,
cbElement,
pvArg
);
PkiFree(pbElement);
if (!fResult)
goto CommonReturn;
}
}
if (!FindNextFileU(hFindFile, &FindFileData)) {
dwErr = GetLastError();
if (ERROR_NO_MORE_FILES == dwErr)
goto SuccessReturn;
else
goto FindNextFileError;
}
}
SuccessReturn:
fResult = TRUE;
CommonReturn:
PkiFree(pwszDir);
if (INVALID_HANDLE_VALUE != hFindFile) {
dwErr = GetLastError();
FindClose(hFindFile);
SetLastError(dwErr);
}
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(FormatSystemNamePathError)
SET_ERROR_VAR(FindFirstFileError, dwErr)
TRACE_ERROR(CreateDirError)
SET_ERROR_VAR(FindNextFileError, dwErr)
}
//+=========================================================================
// Registry or Roaming Store Change Notify Functions
//==========================================================================
STATIC VOID NTAPI RegistryStoreChangeCallback(
PVOID Context,
BOOLEAN fWaitOrTimedOut // ???
)
{
BOOL fRearm;
DWORD dwErr = 0;
PREG_STORE pRegStore = (PREG_STORE) Context;
PREGISTRY_STORE_CHANGE_INFO pInfo;
DWORD cEntry;
PILS_RESYNC_ENTRY pEntry;
pInfo = pRegStore->pRegistryStoreChangeInfo;
assert(pInfo);
if (NULL == pInfo)
return;
CertPerfIncrementChangeNotifyCount();
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG) {
fRearm = FindNextChangeNotification(pInfo->hChange);
CertPerfIncrementChangeNotifyCuMyCount();
} else {
fRearm = ILS_RegNotifyChangeKeyValue(pRegStore->hKey, pInfo->hChange);
CertPerfIncrementChangeNotifyRegCount();
}
if (!fRearm)
dwErr = GetLastError();
// Minimize window of potential deadlock by only getting the values
// while holding the lock.
LockRegStore(pRegStore);
cEntry = pInfo->cNotifyEntry;
pEntry = pInfo->rgNotifyEntry;
pInfo->cNotifyEntry = 0;
pInfo->rgNotifyEntry = NULL;
UnlockRegStore(pRegStore);
ILS_SignalEventsOnResyncList(&cEntry, &pEntry);
if (!fRearm)
goto RegistryStoreChangeRearmError;
CommonReturn:
return;
ErrorReturn:
goto CommonReturn;
SET_ERROR_VAR(RegistryStoreChangeRearmError, dwErr)
}
// Upon entry/exit the pRegStore is locked
STATIC BOOL InitRegistryStoreChange(
IN PREG_STORE pRegStore
)
{
BOOL fResult;
DWORD dwErr;
BOOL fRoaming;
PREGISTRY_STORE_CHANGE_INFO pInfo = NULL;
HANDLE hChange = INVALID_HANDLE_VALUE;
HANDLE hRegWaitFor;
fRoaming = (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG);
assert(NULL == pRegStore->pRegistryStoreChangeInfo);
if (NULL == (pInfo = (PREGISTRY_STORE_CHANGE_INFO) PkiZeroAlloc(
sizeof(REGISTRY_STORE_CHANGE_INFO))))
goto OutOfMemory;
pInfo->dwType = REG_CHANGE_INFO_TYPE;
if (fRoaming) {
if (INVALID_HANDLE_VALUE == (hChange = FindFirstChangeNotificationU(
pRegStore->pwszStoreDirectory,
TRUE, // bWatchSubtree
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE
))) {
dwErr = GetLastError();
goto FindFirstChangeNotificationError;
}
} else {
if (NULL == (hChange = CreateEvent(
NULL, // lpsa
FALSE, // fManualReset
FALSE, // fInitialState
NULL))) // lpszEventName
goto CreateEventError;
assert(pRegStore->hKey);
if (!ILS_RegNotifyChangeKeyValue(pRegStore->hKey, hChange))
goto RegNotifyChangeKeyValueError;
}
pInfo->hChange = hChange;
// The following must be set before the following register.
// The thread may be scheduled to run before the function returns.
pRegStore->pRegistryStoreChangeInfo = pInfo;
if (!pfnILS_RegisterWaitForSingleObject(
&hRegWaitFor,
hChange,
RegistryStoreChangeCallback,
(PVOID) pRegStore,
INFINITE, // no timeout
WT_EXECUTEINWAITTHREAD
)) {
pRegStore->pRegistryStoreChangeInfo = NULL;
dwErr = GetLastError();
goto RegisterWaitForError;
}
pInfo->hRegWaitFor = hRegWaitFor;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if (INVALID_HANDLE_VALUE != hChange && hChange) {
dwErr = GetLastError();
if (fRoaming)
FindCloseChangeNotification(hChange);
else
CloseHandle(hChange);
SetLastError(dwErr);
}
PkiFree(pInfo);
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR_VAR(FindFirstChangeNotificationError, dwErr)
TRACE_ERROR(CreateEventError)
TRACE_ERROR(RegNotifyChangeKeyValueError)
SET_ERROR_VAR(RegisterWaitForError, dwErr)
}
STATIC BOOL RegRegistryStoreChange(
IN PREG_STORE pRegStore,
IN HANDLE hEvent,
IN DWORD dwFlags
)
{
BOOL fResult;
PREGISTRY_STORE_CHANGE_INFO pInfo;
LockRegStore(pRegStore);
if (NULL == (pInfo = pRegStore->pRegistryStoreChangeInfo)) {
if (!InitRegistryStoreChange(pRegStore))
goto ChangeInitError;
pInfo = pRegStore->pRegistryStoreChangeInfo;
assert(pInfo);
assert(REG_CHANGE_INFO_TYPE == pInfo->dwType);
}
if (!ILS_AddRemoveEventToFromResyncList(
pRegStore,
hEvent,
dwFlags,
&pInfo->cNotifyEntry,
&pInfo->rgNotifyEntry
))
goto AddRemoveEventError;
fResult = TRUE;
CommonReturn:
UnlockRegStore(pRegStore);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(ChangeInitError)
TRACE_ERROR(AddRemoveEventError)
}
STATIC void FreeRegistryStoreChange(
IN PREG_STORE pRegStore
)
{
PREGISTRY_STORE_CHANGE_INFO pInfo;
if (NULL == (pInfo = pRegStore->pRegistryStoreChangeInfo))
return;
if (REG_CHANGE_INFO_TYPE != pInfo->dwType)
return;
assert(pInfo->hRegWaitFor);
pfnILS_UnregisterWaitEx(pInfo->hRegWaitFor, INVALID_HANDLE_VALUE);
assert(pInfo->hChange);
if (pRegStore->dwFlags & CERT_REGISTRY_STORE_ROAMING_FLAG)
FindCloseChangeNotification(pInfo->hChange);
else
CloseHandle(pInfo->hChange);
ILS_SignalEventsOnResyncList(
&pInfo->cNotifyEntry,
&pInfo->rgNotifyEntry
);
PkiFree(pInfo);
pRegStore->pRegistryStoreChangeInfo = NULL;
}
//+=========================================================================
// Key Identifier Functions
//==========================================================================
STATIC HKEY OpenKeyIdStoreSubKey(
IN DWORD dwFlags,
IN OPTIONAL LPCWSTR pwszComputerName
)
{
SYSTEM_NAME_INFO SystemNameInfo;
memset(&SystemNameInfo, 0, sizeof(SystemNameInfo));
SystemNameInfo.rgpwszName[SYSTEM_NAME_INDEX] = wsz_MY_STORE;
SystemNameInfo.rgpwszName[COMPUTER_NAME_INDEX] = (LPWSTR) pwszComputerName;
return OpenSystemRegPathKey(
&SystemNameInfo,
NULL, // pwszSubKeyName
dwFlags
);
}
BOOL
ILS_ReadKeyIdElement(
IN const CRYPT_HASH_BLOB *pKeyIdentifier,
IN BOOL fLocalMachine,
IN OPTIONAL LPCWSTR pwszComputerName,
OUT BYTE **ppbElement,
OUT DWORD *pcbElement
)
{
BOOL fResult;
BYTE *pbElement = NULL;
DWORD cbElement = 0;
WCHAR wszHashName[MAX_HASH_NAME_LEN];
if (0 == pKeyIdentifier->cbData || MAX_HASH_LEN < pKeyIdentifier->cbData)
goto InvalidArg;
ILS_BytesToWStr(pKeyIdentifier->cbData, pKeyIdentifier->pbData, wszHashName);
if (!fLocalMachine) {
LPWSTR pwszRoamingStoreDir;
if (pwszRoamingStoreDir = ILS_GetRoamingStoreDirectory(
ROAMING_MY_STORE_SUBDIR)) {
// Ignore BACKUP_RESTORE
fResult = ILS_ReadElementFromFile(
pwszRoamingStoreDir,
KEYID_CONTEXT_NAME,
wszHashName,
0, // dwFlags
&pbElement,
&cbElement
);
PkiFree(pwszRoamingStoreDir);
if (!fResult) {
if (ERROR_FILE_NOT_FOUND != GetLastError())
goto ReadElementFromFileError;
} else
goto CommonReturn;
}
}
{
HKEY hKey;
DWORD dwOpenFlags;
if (fLocalMachine)
dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
else
dwOpenFlags = CERT_SYSTEM_STORE_CURRENT_USER;
if (NULL == (hKey = OpenKeyIdStoreSubKey(
dwOpenFlags | CERT_STORE_READONLY_FLAG,
pwszComputerName
)))
goto OpenKeyIdStoreSubKeyError;
// Ignore BACKUP_RESTORE
fResult = ILS_ReadElementFromRegistry(
hKey,
KEYID_CONTEXT_NAME,
wszHashName,
0, // dwFlags
&pbElement,
&cbElement
);
ILS_CloseRegistryKey(hKey);
if (!fResult)
goto ReadElementFromRegistryError;
}
fResult = TRUE;
CommonReturn:
*ppbElement = pbElement;
*pcbElement = cbElement;
return fResult;
ErrorReturn:
assert(NULL == pbElement && 0 == cbElement);
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(ReadElementFromFileError)
TRACE_ERROR(OpenKeyIdStoreSubKeyError)
TRACE_ERROR(ReadElementFromRegistryError)
}
BOOL
ILS_WriteKeyIdElement(
IN const CRYPT_HASH_BLOB *pKeyIdentifier,
IN BOOL fLocalMachine,
IN OPTIONAL LPCWSTR pwszComputerName,
IN const BYTE *pbElement,
IN DWORD cbElement
)
{
BOOL fResult;
WCHAR wszHashName[MAX_HASH_NAME_LEN];
if (0 == pKeyIdentifier->cbData || MAX_HASH_LEN < pKeyIdentifier->cbData)
goto InvalidArg;
ILS_BytesToWStr(pKeyIdentifier->cbData, pKeyIdentifier->pbData, wszHashName);
if (!fLocalMachine) {
LPWSTR pwszRoamingStoreDir;
if (pwszRoamingStoreDir = ILS_GetRoamingStoreDirectory(
ROAMING_MY_STORE_SUBDIR)) {
// Ignore BACKUP_RESTORE
fResult = ILS_WriteElementToFile(
pwszRoamingStoreDir,
KEYID_CONTEXT_NAME,
wszHashName,
0, // dwFlags
pbElement,
cbElement
);
PkiFree(pwszRoamingStoreDir);
if (!fResult)
goto WriteElementToFileError;
else
goto CommonReturn;
}
}
{
HKEY hKey;
DWORD dwOpenFlags;
if (fLocalMachine)
dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
else
dwOpenFlags = CERT_SYSTEM_STORE_CURRENT_USER;
if (NULL == (hKey = OpenKeyIdStoreSubKey(
dwOpenFlags,
pwszComputerName
)))
goto OpenKeyIdStoreSubKeyError;
// Ignore BACKUP_RESTORE
fResult = ILS_WriteElementToRegistry(
hKey,
KEYID_CONTEXT_NAME,
wszHashName,
0, // dwFlags
pbElement,
cbElement
);
ILS_CloseRegistryKey(hKey);
if (!fResult)
goto WriteElementToRegistryError;
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(WriteElementToFileError)
TRACE_ERROR(OpenKeyIdStoreSubKeyError)
TRACE_ERROR(WriteElementToRegistryError)
}
BOOL
ILS_DeleteKeyIdElement(
IN const CRYPT_HASH_BLOB *pKeyIdentifier,
IN BOOL fLocalMachine,
IN OPTIONAL LPCWSTR pwszComputerName
)
{
BOOL fResult;
WCHAR wszHashName[MAX_HASH_NAME_LEN];
if (0 == pKeyIdentifier->cbData || MAX_HASH_LEN < pKeyIdentifier->cbData)
goto InvalidArg;
ILS_BytesToWStr(pKeyIdentifier->cbData, pKeyIdentifier->pbData, wszHashName);
if (!fLocalMachine) {
LPWSTR pwszRoamingStoreDir;
if (pwszRoamingStoreDir = ILS_GetRoamingStoreDirectory(
ROAMING_MY_STORE_SUBDIR)) {
// Ignore BACKUP_RESTORE
fResult = ILS_DeleteElementFromDirectory(
pwszRoamingStoreDir,
KEYID_CONTEXT_NAME,
wszHashName,
0 // dwFlags
);
PkiFree(pwszRoamingStoreDir);
if (!fResult)
goto DeleteElementFromDirectoryError;
else
goto CommonReturn;
}
}
{
HKEY hKey;
DWORD dwOpenFlags;
if (fLocalMachine)
dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
else
dwOpenFlags = CERT_SYSTEM_STORE_CURRENT_USER;
if (NULL == (hKey = OpenKeyIdStoreSubKey(
dwOpenFlags,
pwszComputerName
)))
goto OpenKeyIdStoreSubKeyError;
// Ignore BACKUP_RESTORE
fResult = ILS_DeleteElementFromRegistry(
hKey,
KEYID_CONTEXT_NAME,
wszHashName,
0 // dwFlags
);
ILS_CloseRegistryKey(hKey);
if (!fResult)
goto DeleteElementFromRegistryError;
}
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(DeleteElementFromDirectoryError)
TRACE_ERROR(OpenKeyIdStoreSubKeyError)
TRACE_ERROR(DeleteElementFromRegistryError)
}
typedef struct _OPEN_KEYID_CALLBACK_ARG {
void *pvArg;
PFN_ILS_OPEN_KEYID_ELEMENT pfnOpenKeyId;
} OPEN_KEYID_CALLBACK_ARG, *POPEN_KEYID_CALLBACK_ARG;
STATIC BOOL OpenKeyIdElementCallback(
IN const WCHAR wszHashName[MAX_HASH_NAME_LEN],
IN const BYTE *pbElement,
IN DWORD cbElement,
IN void *pvArg
)
{
POPEN_KEYID_CALLBACK_ARG pKeyIdArg = (POPEN_KEYID_CALLBACK_ARG) pvArg;
DWORD cbHash;
BYTE rgbHash[MAX_HASH_LEN];
CRYPT_HASH_BLOB KeyIdentifier;
WStrToBytes(wszHashName, rgbHash, &cbHash);
KeyIdentifier.cbData = cbHash;
KeyIdentifier.pbData = rgbHash;
return pKeyIdArg->pfnOpenKeyId(
&KeyIdentifier,
pbElement,
cbElement,
pKeyIdArg->pvArg
);
}
BOOL
ILS_OpenAllKeyIdElements(
IN BOOL fLocalMachine,
IN OPTIONAL LPCWSTR pwszComputerName,
IN void *pvArg,
IN PFN_ILS_OPEN_KEYID_ELEMENT pfnOpenKeyId
)
{
BOOL fResult;
BOOL fOpenFile = FALSE;
OPEN_KEYID_CALLBACK_ARG KeyIdArg = { pvArg, pfnOpenKeyId };
if (!fLocalMachine) {
LPWSTR pwszRoamingStoreDir;
if (pwszRoamingStoreDir = ILS_GetRoamingStoreDirectory(
ROAMING_MY_STORE_SUBDIR)) {
// Ignore BACKUP_RESTORE
fResult = ILS_OpenAllElementsFromDirectory(
pwszRoamingStoreDir,
KEYID_CONTEXT_NAME,
0, // dwFlags
(void *) &KeyIdArg,
OpenKeyIdElementCallback
);
PkiFree(pwszRoamingStoreDir);
if (!fResult)
goto ErrorReturn;
else
fOpenFile = TRUE;
}
}
{
HKEY hKey;
DWORD dwOpenFlags;
if (fLocalMachine)
dwOpenFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
else
dwOpenFlags = CERT_SYSTEM_STORE_CURRENT_USER;
if (NULL == (hKey = OpenKeyIdStoreSubKey(
dwOpenFlags | CERT_STORE_READONLY_FLAG,
pwszComputerName
)))
goto OpenKeyIdStoreSubKeyError;
// Ignore BACKUP_RESTORE
fResult = ILS_OpenAllElementsFromRegistry(
hKey,
KEYID_CONTEXT_NAME,
0, // dwFlags
(void *) &KeyIdArg,
OpenKeyIdElementCallback
);
ILS_CloseRegistryKey(hKey);
}
CommonReturn:
if (fOpenFile)
// Ignore any registry errors
return TRUE;
else
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenKeyIdStoreSubKeyError)
}