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