2731 lines
63 KiB
C++
2731 lines
63 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: config.cpp
|
|
//
|
|
// Contents: Cert Server client implementation
|
|
//
|
|
// History: 24-Aug-96 vich created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "csdisp.h"
|
|
#include "certca.h"
|
|
#include "configp.h"
|
|
#include <assert.h>
|
|
|
|
#include <lmaccess.h>
|
|
#include <lmapibuf.h>
|
|
#include <lmwksta.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#define __dwFILE__ __dwFILE_CERTCLI_CONFIGP_CPP__
|
|
|
|
|
|
WCHAR g_wszConfigFile[] = L"\\certsrv.txt";
|
|
|
|
WCHAR const g_wszRegDirectory[] = wszREGDIRECTORY;
|
|
#define cwcCONFIGLINEMAX (12 * 1024)
|
|
|
|
extern "C"
|
|
{
|
|
HWND GetDeskTopWindow(VOID);
|
|
}
|
|
|
|
HRESULT
|
|
certRequestGetConfigInfo(
|
|
IN WCHAR *pwszSharedFolder,
|
|
IN OUT LONG *pIndex,
|
|
IN OUT LONG *pCount,
|
|
OUT CERT_AUTHORITY_INFO **ppCertAuthorityInfo);
|
|
|
|
VOID
|
|
_CleanupCAInfo(
|
|
IN OUT CERT_AUTHORITY_INFO *pCA)
|
|
{
|
|
if (NULL != pCA->pwszSanitizedName)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedName);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedShortName)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedShortName);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedOrgUnit)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedOrgUnit);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedOrganization)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedOrganization);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedLocality)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedLocality);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedState)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedState);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedCountry)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedCountry);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedConfig)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedConfig);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedExchangeCertificate)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedExchangeCertificate);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedSignatureCertificate)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedSignatureCertificate);
|
|
}
|
|
if (NULL != pCA->pwszSanitizedDescription)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedDescription);
|
|
}
|
|
ZeroMemory(pCA, sizeof(*pCA));
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::~CCertConfigPrivate -- destructor
|
|
//
|
|
// free memory associated with this instance
|
|
//+--------------------------------------------------------------------------
|
|
|
|
CCertConfigPrivate::~CCertConfigPrivate()
|
|
{
|
|
LONG i;
|
|
|
|
if (NULL != m_pCertAuthorityInfo)
|
|
{
|
|
if (0 != m_Count)
|
|
{
|
|
for (i = 0; i < m_Count; ++i)
|
|
{
|
|
_CleanupCAInfo(&m_pCertAuthorityInfo[i]);
|
|
}
|
|
}
|
|
LocalFree(m_pCertAuthorityInfo);
|
|
}
|
|
if (NULL != m_pwszSharedFolder)
|
|
{
|
|
LocalFree(m_pwszSharedFolder);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
fillEmptyField(
|
|
WCHAR **ppwszField)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppwszField = (WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR));
|
|
if (NULL == *ppwszField)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
*ppwszField[0] = L'\0';
|
|
|
|
hr = S_OK;
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
dsFreeCAConfig(
|
|
LONG cCA,
|
|
CERT_AUTHORITY_INFO *pCA)
|
|
{
|
|
LONG i;
|
|
|
|
if (NULL != pCA && 0 < cCA)
|
|
{
|
|
for (i = 0; i < cCA; ++i)
|
|
{
|
|
if (NULL != pCA[i].pwszSanitizedName)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedName);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedShortName)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedShortName);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedConfig)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedConfig);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedOrganization)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedOrganization);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedOrgUnit)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedOrgUnit);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedLocality)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedLocality);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedState)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedState);
|
|
}
|
|
if (NULL != pCA[i].pwszSanitizedCountry)
|
|
{
|
|
LocalFree(pCA[i].pwszSanitizedCountry);
|
|
}
|
|
}
|
|
LocalFree(pCA);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConfigGetCertNameDNInfo(
|
|
IN CERT_NAME_INFO const *pCertNameInfo,
|
|
IN CHAR const *pszObjId,
|
|
IN OUT WCHAR **ppwszDNInfo)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszProperty = NULL;
|
|
|
|
if (NULL != *ppwszDNInfo && L'\0' != **ppwszDNInfo)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
hr = myGetCertNameProperty(pCertNameInfo, pszObjId, &pwszProperty);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
_JumpIfError(hr, error, "myGetCertNameProperty");
|
|
|
|
if (NULL != pwszProperty)
|
|
{
|
|
WCHAR *pwsz;
|
|
|
|
hr = myDupString(pwszProperty, &pwsz);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
if (NULL != *ppwszDNInfo)
|
|
{
|
|
LocalFree(*ppwszDNInfo);
|
|
}
|
|
*ppwszDNInfo = pwsz;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConfigLoadDNInfo(
|
|
IN BYTE const *pbEncoded,
|
|
IN DWORD cbEncoded,
|
|
IN OUT CERT_AUTHORITY_INFO *pCA)
|
|
{
|
|
HRESULT hr;
|
|
CERT_NAME_INFO *pCertNameInfo = NULL;
|
|
DWORD cbCertNameInfo;
|
|
|
|
// decode to name info
|
|
if (!myDecodeName(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_NAME,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pCertNameInfo,
|
|
&cbCertNameInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeName");
|
|
}
|
|
|
|
hr = ConfigGetCertNameDNInfo(
|
|
pCertNameInfo,
|
|
szOID_ORGANIZATION_NAME,
|
|
&pCA->pwszSanitizedOrganization);
|
|
_JumpIfError(hr, error, "ConfigGetCertNameDNInfo");
|
|
|
|
hr = ConfigGetCertNameDNInfo(
|
|
pCertNameInfo,
|
|
szOID_ORGANIZATIONAL_UNIT_NAME,
|
|
&pCA->pwszSanitizedOrgUnit);
|
|
_JumpIfError(hr, error, "ConfigGetCertNameDNInfo");
|
|
|
|
hr = ConfigGetCertNameDNInfo(
|
|
pCertNameInfo,
|
|
szOID_LOCALITY_NAME,
|
|
&pCA->pwszSanitizedLocality);
|
|
_JumpIfError(hr, error, "ConfigGetCertNameDNInfo");
|
|
|
|
hr = ConfigGetCertNameDNInfo(
|
|
pCertNameInfo,
|
|
szOID_STATE_OR_PROVINCE_NAME,
|
|
&pCA->pwszSanitizedState);
|
|
_JumpIfError(hr, error, "ConfigGetCertNameDNInfo");
|
|
|
|
hr = ConfigGetCertNameDNInfo(
|
|
pCertNameInfo,
|
|
szOID_COUNTRY_NAME,
|
|
&pCA->pwszSanitizedCountry);
|
|
_JumpIfError(hr, error, "ConfigGetCertNameDNInfo");
|
|
|
|
error:
|
|
if (NULL != pCertNameInfo)
|
|
{
|
|
LocalFree(pCertNameInfo);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
dsGetCAConfig(
|
|
OUT CERT_AUTHORITY_INFO **ppCAConfig,
|
|
OUT LONG *pcCAConfig)
|
|
{
|
|
HRESULT hr;
|
|
HCAINFO hCACurrent = NULL;
|
|
HCAINFO hCANext = NULL;
|
|
WCHAR **ppwszCommonName = NULL;
|
|
WCHAR **ppwszSanitizedShortName = NULL;
|
|
WCHAR **ppwszDescription = NULL;
|
|
WCHAR **ppwszMachine = NULL;
|
|
WCHAR **ppwszDN = NULL;
|
|
LONG cCA;
|
|
LONG iDst;
|
|
LONG iSrc;
|
|
CERT_AUTHORITY_INFO *pCA = NULL;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
*ppCAConfig = NULL;
|
|
*pcCAConfig = 0;
|
|
|
|
cCA = 0;
|
|
|
|
hr = CAEnumFirstCA(
|
|
NULL,
|
|
CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA,
|
|
&hCACurrent);
|
|
if (HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE) != hr)
|
|
{
|
|
_PrintIfErrorStr4(
|
|
hr,
|
|
"CAEnumFirstCA",
|
|
L"Ignored!",
|
|
HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED),
|
|
HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN),
|
|
HRESULT_FROM_WIN32(ERROR_WRONG_PASSWORD));
|
|
}
|
|
|
|
cCA = CACountCAs(hCACurrent); // 0 on error
|
|
if (0 < cCA)
|
|
{
|
|
pCA = (CERT_AUTHORITY_INFO *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cCA * sizeof(CERT_AUTHORITY_INFO));
|
|
if (NULL == pCA)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
for (iDst = 0, iSrc = 0; iSrc < cCA; iSrc++)
|
|
{
|
|
CSASSERT(NULL == ppwszCommonName);
|
|
CSASSERT(NULL == ppwszSanitizedShortName);
|
|
CSASSERT(NULL == ppwszDescription);
|
|
CSASSERT(NULL == ppwszMachine);
|
|
CSASSERT(NULL == ppwszDN);
|
|
CSASSERT(NULL == pCA[iDst].pwszSanitizedName);
|
|
CSASSERT(NULL == pCA[iDst].pwszSanitizedShortName);
|
|
CSASSERT(NULL == pCA[iDst].pwszSanitizedConfig);
|
|
|
|
hr = CAGetCAProperty(
|
|
hCACurrent,
|
|
CA_PROP_DISPLAY_NAME,
|
|
&ppwszCommonName);
|
|
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DISPLAY_NAME)");
|
|
|
|
hr = CAGetCAProperty(hCACurrent, CA_PROP_NAME, &ppwszSanitizedShortName);
|
|
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_NAME)");
|
|
|
|
hr = CAGetCAProperty(hCACurrent, CA_PROP_DESCRIPTION, &ppwszDescription);
|
|
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DESCRIPTION)");
|
|
|
|
hr = CAGetCAProperty(hCACurrent, CA_PROP_DNSNAME, &ppwszMachine);
|
|
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DNSNAME)");
|
|
|
|
hr = CAGetCAProperty(hCACurrent, CA_PROP_CERT_DN, &ppwszDN);
|
|
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_CERT_DN)");
|
|
|
|
if (NULL == ppwszCommonName ||
|
|
NULL == ppwszSanitizedShortName ||
|
|
NULL == ppwszMachine ||
|
|
NULL == ppwszDN)
|
|
{
|
|
_PrintError(E_INVALIDARG, "missing CA property");
|
|
goto skipca; // skip and don't take the CA
|
|
}
|
|
|
|
hr = mySanitizeName(*ppwszCommonName, &pCA[iDst].pwszSanitizedName);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
// already sanitized:
|
|
|
|
hr = myDupString(*ppwszSanitizedShortName, &pCA[iDst].pwszSanitizedShortName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
if (NULL != ppwszDescription)
|
|
{
|
|
hr = myDupString(*ppwszDescription, &pCA[iDst].pwszSanitizedDescription);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
|
|
pCA[iDst].pwszSanitizedConfig = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(*ppwszMachine) + wcslen(pCA[iDst].pwszSanitizedName) + 2) *
|
|
sizeof(WCHAR));
|
|
if (NULL == pCA[iDst].pwszSanitizedConfig)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc(pwszSanitizedConfig)");
|
|
}
|
|
wcscpy(pCA[iDst].pwszSanitizedConfig, *ppwszMachine);
|
|
wcscat(pCA[iDst].pwszSanitizedConfig, L"\\");
|
|
wcscat(pCA[iDst].pwszSanitizedConfig, pCA[iDst].pwszSanitizedName);
|
|
|
|
pbEncoded = NULL;
|
|
while (TRUE)
|
|
{
|
|
// convert dn string to name blob
|
|
if (!CertStrToName(
|
|
X509_ASN_ENCODING,
|
|
*ppwszDN,
|
|
CERT_X500_NAME_STR,
|
|
NULL,
|
|
pbEncoded,
|
|
&cbEncoded,
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "CertStrToName");
|
|
}
|
|
if (NULL != pbEncoded)
|
|
{
|
|
// get name
|
|
break;
|
|
}
|
|
pbEncoded = (BYTE*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
cbEncoded);
|
|
if (NULL == pbEncoded)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
}
|
|
|
|
hr = ConfigLoadDNInfo(pbEncoded, cbEncoded, &pCA[iDst]);
|
|
_JumpIfError(hr, error, "ConfigLoadDNInfo");
|
|
|
|
// fill empty for the rest
|
|
CSASSERT(NULL == pCA[iDst].pwszSanitizedExchangeCertificate);
|
|
CSASSERT(NULL == pCA[iDst].pwszSanitizedSignatureCertificate);
|
|
pCA[iDst].Flags = CAIF_DSENTRY;
|
|
++iDst;
|
|
|
|
// free dn blobs
|
|
if (NULL != pbEncoded)
|
|
{
|
|
LocalFree(pbEncoded);
|
|
pbEncoded = NULL;
|
|
}
|
|
skipca:
|
|
// free ds out properties
|
|
|
|
if (NULL != ppwszCommonName)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszCommonName);
|
|
ppwszCommonName = NULL;
|
|
}
|
|
if (NULL != ppwszSanitizedShortName)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszSanitizedShortName);
|
|
ppwszSanitizedShortName = NULL;
|
|
}
|
|
if (NULL != ppwszDescription)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszDescription);
|
|
ppwszDescription = NULL;
|
|
}
|
|
if (NULL != ppwszMachine)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszMachine);
|
|
ppwszMachine = NULL;
|
|
}
|
|
if (NULL != ppwszDN)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszDN);
|
|
ppwszDN = NULL;
|
|
}
|
|
|
|
hr = CAEnumNextCA(hCACurrent, &hCANext);
|
|
CACloseCA(hCACurrent);
|
|
hCACurrent = hCANext;
|
|
if (S_OK != hr || NULL == hCACurrent)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
*pcCAConfig = iDst;
|
|
*ppCAConfig = pCA;
|
|
pCA = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hCACurrent)
|
|
{
|
|
CACloseCA(hCACurrent);
|
|
}
|
|
if (NULL != pbEncoded)
|
|
{
|
|
LocalFree(pbEncoded);
|
|
}
|
|
if (NULL != ppwszCommonName)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszCommonName);
|
|
}
|
|
if (NULL != ppwszSanitizedShortName)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszSanitizedShortName);
|
|
}
|
|
if (NULL != ppwszMachine)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszMachine);
|
|
}
|
|
if (NULL != ppwszDN)
|
|
{
|
|
CAFreeCAProperty(hCACurrent, ppwszDN);
|
|
}
|
|
if (NULL != pCA)
|
|
{
|
|
dsFreeCAConfig(cCA, pCA);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
BOOL
|
|
FindSharedCAInDSList(
|
|
IN CERT_AUTHORITY_INFO *pDSCA,
|
|
IN LONG countDSCA,
|
|
IN CERT_AUTHORITY_INFO const *pCAFromShared,
|
|
OUT CERT_AUTHORITY_INFO **ppDSCA)
|
|
{
|
|
BOOL found = FALSE;
|
|
LONG i;
|
|
|
|
*ppDSCA = NULL;
|
|
for (i = 0; i < countDSCA; ++i)
|
|
{
|
|
if (0 == lstrcmpi(pDSCA[i].pwszSanitizedConfig, pCAFromShared->pwszSanitizedConfig) &&
|
|
0 == lstrcmpi(pDSCA[i].pwszSanitizedName, pCAFromShared->pwszSanitizedName))
|
|
{
|
|
*ppDSCA = &pDSCA[i];
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return(found);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
updateField(
|
|
IN WCHAR const *pwszSource,
|
|
OUT WCHAR **ppwszDest)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL != pwszSource &&
|
|
(NULL == *ppwszDest || L'\0' == **ppwszDest))
|
|
{
|
|
if (NULL != *ppwszDest)
|
|
{
|
|
LocalFree(*ppwszDest);
|
|
}
|
|
hr = myDupString(pwszSource, ppwszDest);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
mergeConfigFields(
|
|
IN CERT_AUTHORITY_INFO const *pCAIn,
|
|
IN OUT CERT_AUTHORITY_INFO *pCA)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == pCAIn || NULL == pCA)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "Internal Error");
|
|
}
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedName, &pCA->pwszSanitizedName);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedName)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedOrgUnit, &pCA->pwszSanitizedOrgUnit);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedOrgUnit)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedOrganization, &pCA->pwszSanitizedOrganization);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedOrganization)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedLocality, &pCA->pwszSanitizedLocality);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedLocality)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedState, &pCA->pwszSanitizedState);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedState)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedCountry, &pCA->pwszSanitizedCountry);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedCountry)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedConfig, &pCA->pwszSanitizedConfig);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedConfig)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedExchangeCertificate, &pCA->pwszSanitizedExchangeCertificate);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedExchangeCertificate)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedSignatureCertificate, &pCA->pwszSanitizedSignatureCertificate);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedSignatureCertificate)");
|
|
|
|
hr = updateField(pCAIn->pwszSanitizedDescription, &pCA->pwszSanitizedDescription);
|
|
_JumpIfError(hr, error, "updateField(pwszSanitizedDescription)");
|
|
|
|
hr = mySanitizedNameToDSName(pCAIn->pwszSanitizedName, &pCA->pwszSanitizedShortName);
|
|
_JumpIfError(hr, error, "mySanitizedNameToDSName");
|
|
|
|
pCA->Flags |= pCAIn->Flags;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::_ResizeCAInfo(
|
|
IN LONG Count)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
m_pCertAuthorityInfo = (CERT_AUTHORITY_INFO *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
Count * sizeof(CERT_AUTHORITY_INFO));
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CERT_AUTHORITY_INFO *pCAI;
|
|
|
|
pCAI = (CERT_AUTHORITY_INFO *) LocalReAlloc(
|
|
m_pCertAuthorityInfo,
|
|
Count * sizeof(CERT_AUTHORITY_INFO),
|
|
LMEM_MOVEABLE);
|
|
if (NULL == pCAI)
|
|
{
|
|
_JumpError(hr, error, "LocalReAlloc");
|
|
}
|
|
m_pCertAuthorityInfo = pCAI;
|
|
|
|
// LocalReAlloc won't zero memory when old size was already > m_Count
|
|
|
|
if (Count > m_Count)
|
|
{
|
|
ZeroMemory(
|
|
&m_pCertAuthorityInfo[m_Count],
|
|
(Count - m_Count) * sizeof(m_pCertAuthorityInfo[0]));
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::_AddRegistryConfigEntry(
|
|
IN WCHAR const *pwszDnsName,
|
|
IN WCHAR const *pwszOldName,
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN BOOL fParentCA,
|
|
OPTIONAL IN CERT_CONTEXT const *pccCAChild,
|
|
OPTIONAL OUT CERT_CONTEXT const **ppccCAOut) // non-NULL means local CA
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hMyStore = NULL;
|
|
LONG i;
|
|
BOOL fFoundCA = FALSE;
|
|
WCHAR *pwszDescription = NULL;
|
|
WCHAR *pwszSanitizedShortName = NULL;
|
|
CERT_CONTEXT const *pccCA = NULL;
|
|
CERT_AUTHORITY_INFO *pCA = NULL;
|
|
WCHAR *pwsz;
|
|
WCHAR *pwszRegPath = NULL;
|
|
HKEY hKey = NULL;
|
|
|
|
if (NULL != ppccCAOut)
|
|
{
|
|
CSASSERT(NULL == pccCAChild);
|
|
*ppccCAOut = NULL;
|
|
}
|
|
|
|
for (i = 0; i < m_Count; ++i)
|
|
{
|
|
BOOL fMachineNameMatch;
|
|
|
|
hr = myIsConfigLocal2(
|
|
m_pCertAuthorityInfo[i].pwszSanitizedConfig,
|
|
pwszDnsName,
|
|
pwszOldName,
|
|
&fMachineNameMatch);
|
|
_JumpIfError(hr, error, "myIsConfigLocal2");
|
|
|
|
if (fMachineNameMatch)
|
|
{
|
|
if (!fParentCA) // Local CA
|
|
{
|
|
m_pCertAuthorityInfo[i].Flags |= CAIF_LOCAL;
|
|
}
|
|
|
|
if (0 == lstrcmpi(
|
|
pwszSanitizedCAName,
|
|
m_pCertAuthorityInfo[i].pwszSanitizedName))
|
|
{
|
|
fFoundCA = TRUE;
|
|
|
|
pCA = &m_pCertAuthorityInfo[i];
|
|
pCA->Flags |= CAIF_REGISTRY;
|
|
if (fParentCA)
|
|
{
|
|
pCA->Flags |= CAIF_REGISTRYPARENT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!fFoundCA)
|
|
{
|
|
hr = _ResizeCAInfo(m_Count + 1);
|
|
_JumpIfError(hr, error, "_ResizeCAInfo");
|
|
|
|
pCA = &m_pCertAuthorityInfo[m_Count];
|
|
|
|
hr = myFormConfigString(
|
|
pwszDnsName,
|
|
pwszSanitizedCAName,
|
|
&pCA->pwszSanitizedConfig);
|
|
_JumpIfError(hr, error, "myFormConfigString");
|
|
|
|
hr = myDupString(pwszSanitizedCAName, &pCA->pwszSanitizedName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = mySanitizedNameToDSName(
|
|
pwszSanitizedCAName,
|
|
&pCA->pwszSanitizedShortName);
|
|
_JumpIfError(hr, error, "mySanitizedNameToDSName");
|
|
|
|
pCA->Flags = CAIF_REGISTRY;
|
|
if (fParentCA)
|
|
{
|
|
pCA->Flags |= CAIF_REGISTRYPARENT;
|
|
}
|
|
else
|
|
{
|
|
pCA->Flags |= CAIF_LOCAL;
|
|
}
|
|
|
|
}
|
|
|
|
CSASSERT(NULL != pCA); // either found or added
|
|
|
|
if (NULL == pCA->pwszSanitizedDescription ||
|
|
L'\0' == *pCA->pwszSanitizedDescription)
|
|
{
|
|
if (!fParentCA) // Local CA
|
|
{
|
|
hr = myGetCertRegStrValue(
|
|
pCA->pwszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCADESCRIPTION,
|
|
&pwszDescription);
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"myGetCertRegStrValue",
|
|
wszREGCADESCRIPTION,
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
}
|
|
else
|
|
{
|
|
hr = myRegOpenRelativeKey(
|
|
pwszDnsName,
|
|
L"ca",
|
|
0,
|
|
&pwszRegPath,
|
|
NULL,
|
|
&hKey);
|
|
_PrintIfErrorStr(hr, "myGetCertRegStrValue", wszREGCADESCRIPTION);
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD cb;
|
|
DWORD cwc;
|
|
DWORD dwType;
|
|
|
|
hr = RegQueryValueEx(
|
|
hKey,
|
|
wszREGCADESCRIPTION,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cb);
|
|
if (S_OK == hr && REG_SZ == dwType && sizeof(WCHAR) < cb)
|
|
{
|
|
cwc = cb / sizeof(WCHAR);
|
|
|
|
pwszDescription = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszDescription)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
hr = RegQueryValueEx(
|
|
hKey,
|
|
wszREGCADESCRIPTION,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pwszDescription,
|
|
&cb);
|
|
_JumpIfError(hr, error, "RegQueryValueEx");
|
|
pwszDescription[cwc] = L'\0';
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pwszDescription)
|
|
{
|
|
hr = mySanitizeName(pwszDescription, &pwsz);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
if (NULL != pCA->pwszSanitizedDescription)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedDescription);
|
|
}
|
|
pCA->pwszSanitizedDescription = pwsz;
|
|
}
|
|
}
|
|
if (fParentCA)
|
|
{
|
|
pccCA = pccCAChild;
|
|
}
|
|
else
|
|
{
|
|
DWORD ccert;
|
|
|
|
CSASSERT(NULL == pccCAChild);
|
|
|
|
hr = myGetCARegHashCount(
|
|
pCA->pwszSanitizedName,
|
|
CSRH_CASIGCERT,
|
|
&ccert);
|
|
_PrintIfError(hr, "myGetCARegHashCount");
|
|
if (S_OK == hr && 0 != ccert)
|
|
{
|
|
DWORD NameId;
|
|
|
|
// open MY store
|
|
|
|
hMyStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM_W,
|
|
X509_ASN_ENCODING,
|
|
NULL, // hProv
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE |
|
|
CERT_STORE_READONLY_FLAG,
|
|
wszMY_CERTSTORE);
|
|
if (NULL == hMyStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
|
|
hr = myFindCACertByHashIndex(
|
|
hMyStore,
|
|
pCA->pwszSanitizedName,
|
|
CSRH_CASIGCERT,
|
|
ccert - 1,
|
|
&NameId,
|
|
&pccCA);
|
|
}
|
|
}
|
|
if (NULL != pccCA)
|
|
{
|
|
CERT_NAME_BLOB *pName = !fParentCA?
|
|
&pccCA->pCertInfo->Subject :
|
|
&pccCA->pCertInfo->Issuer;
|
|
|
|
hr = ConfigLoadDNInfo(pName->pbData, pName->cbData, pCA);
|
|
_PrintIfError(hr, "ConfigLoadDNInfo");
|
|
}
|
|
if (NULL == pCA->pwszSanitizedSignatureCertificate ||
|
|
L'\0' == *pCA->pwszSanitizedSignatureCertificate)
|
|
{
|
|
DWORD cwc;
|
|
|
|
// pwszDnsName + "_" + pwszSanitizedCAName + ".crt"
|
|
|
|
cwc = wcslen(pwszDnsName) + 1 + wcslen(pwszSanitizedCAName) + 4;
|
|
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwsz, pwszDnsName);
|
|
wcscat(pwsz, L"_");
|
|
wcscat(pwsz, pwszSanitizedCAName);
|
|
wcscat(pwsz, L".crt");
|
|
CSASSERT(wcslen(pwsz) == cwc);
|
|
|
|
if (NULL != pCA->pwszSanitizedSignatureCertificate)
|
|
{
|
|
LocalFree(pCA->pwszSanitizedSignatureCertificate);
|
|
}
|
|
pCA->pwszSanitizedSignatureCertificate = pwsz;
|
|
}
|
|
if (!fFoundCA)
|
|
{
|
|
m_Count++;
|
|
}
|
|
if (NULL != pccCA && NULL != ppccCAOut)
|
|
{
|
|
*ppccCAOut = CertDuplicateCertificateContext(pccCA);
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%ws %ws CA entry: %ws\n",
|
|
fFoundCA? L"Merged" : L"Added",
|
|
fParentCA? L"Parent" : L"Local",
|
|
pCA->pwszSanitizedConfig));
|
|
pCA = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hKey)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (NULL != pwszRegPath)
|
|
{
|
|
LocalFree(pwszRegPath);
|
|
}
|
|
if (!fFoundCA && NULL != pCA)
|
|
{
|
|
_CleanupCAInfo(pCA);
|
|
}
|
|
if (NULL != pwszDescription)
|
|
{
|
|
LocalFree(pwszDescription);
|
|
}
|
|
if (NULL != pwszSanitizedShortName)
|
|
{
|
|
LocalFree(pwszSanitizedShortName);
|
|
}
|
|
if (NULL != pccCA && pccCAChild != pccCA)
|
|
{
|
|
CertFreeCertificateContext(pccCA);
|
|
}
|
|
if (NULL != hMyStore)
|
|
{
|
|
CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::_LoadTable -- load config data into class instance
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::_LoadTable(VOID)
|
|
{
|
|
HRESULT hr;
|
|
LONG Index;
|
|
LONG CountShared = 0;
|
|
LONG i;
|
|
LONG actualSharedCount;
|
|
CERT_AUTHORITY_INFO *pCAFromShared = NULL;
|
|
BOOL fDSCA = TRUE;
|
|
WCHAR *pwszSanitizedCAName = NULL;
|
|
WCHAR *pwszDnsName = NULL;
|
|
WCHAR *pwszOldName = NULL;
|
|
CERT_CONTEXT const *pccCA = NULL;
|
|
WCHAR *pwszParentMachine = NULL;
|
|
WCHAR *pwszParentMachineOld = NULL;
|
|
WCHAR *pwszParentCAName = NULL;
|
|
WCHAR *pwszParentSanitizedCAName = NULL;
|
|
|
|
m_Index = -1;
|
|
m_Count = 0;
|
|
|
|
if (m_fUseDS)
|
|
{
|
|
hr = dsGetCAConfig(&m_pCertAuthorityInfo, &m_Count);
|
|
_JumpIfError(hr, error, "dsGetCAConfig");
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%x DS entries @%x\n",
|
|
m_Count,
|
|
m_pCertAuthorityInfo));
|
|
if (NULL == m_pCertAuthorityInfo && 0 == m_Count)
|
|
{
|
|
fDSCA = FALSE;
|
|
}
|
|
|
|
Index = 0;
|
|
CountShared = INT_MAX;
|
|
hr = certRequestGetConfigInfo(
|
|
m_pwszSharedFolder,
|
|
&Index,
|
|
&CountShared,
|
|
&pCAFromShared);
|
|
// Don't fail if file not found or unc path is bad
|
|
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
_PrintIfError4(
|
|
hr,
|
|
"certRequestGetConfigInfo",
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
|
|
HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE),
|
|
HRESULT_FROM_WIN32(ERROR_INVALID_NETNAME));
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%x Shared Folder entries @%x\n",
|
|
CountShared,
|
|
pCAFromShared));
|
|
|
|
actualSharedCount = 0;
|
|
if (0 < CountShared)
|
|
{
|
|
hr = _ResizeCAInfo(m_Count + CountShared);
|
|
_JumpIfError(hr, error, "_ResizeCAInfo");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%x %ws @%x\n",
|
|
m_Count + CountShared,
|
|
fDSCA? L"Total entries" : L"new Shared Folder entries",
|
|
m_pCertAuthorityInfo));
|
|
|
|
for (i = 0; i < CountShared; ++i)
|
|
{
|
|
CERT_AUTHORITY_INFO *pCAInDS = NULL;
|
|
CERT_AUTHORITY_INFO *pCAUpdate;
|
|
|
|
if (fDSCA)
|
|
{
|
|
FindSharedCAInDSList(
|
|
m_pCertAuthorityInfo,
|
|
m_Count,
|
|
&pCAFromShared[i],
|
|
&pCAInDS);
|
|
}
|
|
|
|
if (NULL != pCAInDS)
|
|
{
|
|
pCAUpdate = pCAInDS;
|
|
}
|
|
else
|
|
{
|
|
pCAUpdate = &m_pCertAuthorityInfo[m_Count + actualSharedCount];
|
|
ZeroMemory(pCAUpdate, sizeof(*pCAUpdate));
|
|
}
|
|
|
|
hr = mergeConfigFields(&pCAFromShared[i], pCAUpdate);
|
|
_JumpIfError(hr, error, "mergeConfigFields");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"%hs CA entry: %ws\n",
|
|
NULL != pCAInDS? "Merged" : "Added",
|
|
pCAUpdate->pwszSanitizedConfig));
|
|
|
|
if (NULL == pCAInDS)
|
|
{
|
|
++actualSharedCount;
|
|
}
|
|
}
|
|
}
|
|
m_Count += actualSharedCount;
|
|
|
|
// Add local CA to the table. Merge entry if it already exists.
|
|
// Also flags all local CAs.
|
|
|
|
hr = myGetCertRegStrValue(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
wszREGACTIVE,
|
|
&pwszSanitizedCAName);
|
|
_PrintIfErrorStr(hr, "myGetCertRegStrValue", wszREGACTIVE);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = myGetComputerNames(&pwszDnsName, &pwszOldName);
|
|
_JumpIfError(hr, error, "myGetComputerNames");
|
|
|
|
hr = _AddRegistryConfigEntry(
|
|
pwszDnsName,
|
|
pwszOldName,
|
|
pwszSanitizedCAName,
|
|
FALSE, // fParentCA
|
|
NULL,
|
|
&pccCA);
|
|
_JumpIfError(hr, error, "_AddRegistryConfigEntry");
|
|
|
|
// Add parent CA to the table. Merge entry if it already exists.
|
|
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGPARENTCANAME,
|
|
&pwszParentCAName);
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"myGetCertRegStrValue",
|
|
wszREGPARENTCANAME,
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
if (S_OK == hr)
|
|
{
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGPARENTCAMACHINE,
|
|
&pwszParentMachine);
|
|
_PrintIfErrorStr(hr, "myGetCertRegStrValue", wszREGPARENTCAMACHINE);
|
|
}
|
|
|
|
if (NULL != pwszParentMachine && NULL != pwszParentCAName)
|
|
{
|
|
WCHAR *pwsz;
|
|
|
|
hr = mySanitizeName(pwszParentCAName, &pwszParentSanitizedCAName);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
hr = myDupString(pwszParentMachine, &pwszParentMachineOld);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwsz = wcschr(pwszParentMachineOld, L'.');
|
|
if (NULL != pwsz)
|
|
{
|
|
*pwsz = L'\0';
|
|
}
|
|
hr = _AddRegistryConfigEntry(
|
|
pwszParentMachine,
|
|
pwszParentMachineOld,
|
|
pwszParentSanitizedCAName,
|
|
TRUE, // fParentCA
|
|
pccCA,
|
|
NULL);
|
|
_JumpIfError(hr, error, "_AddRegistryConfigEntry");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszDnsName)
|
|
{
|
|
LocalFree(pwszDnsName);
|
|
}
|
|
if (NULL != pwszOldName)
|
|
{
|
|
LocalFree(pwszOldName);
|
|
}
|
|
if (NULL != pwszSanitizedCAName)
|
|
{
|
|
LocalFree(pwszSanitizedCAName);
|
|
}
|
|
if (NULL != pwszParentCAName)
|
|
{
|
|
LocalFree(pwszParentCAName);
|
|
}
|
|
if (NULL != pwszParentMachine)
|
|
{
|
|
LocalFree(pwszParentMachine);
|
|
}
|
|
if (NULL != pwszParentMachineOld)
|
|
{
|
|
LocalFree(pwszParentMachineOld);
|
|
}
|
|
if (NULL != pwszParentSanitizedCAName)
|
|
{
|
|
LocalFree(pwszParentSanitizedCAName);
|
|
}
|
|
if (NULL != pCAFromShared)
|
|
{
|
|
LocalFree(pCAFromShared);
|
|
}
|
|
if (NULL != pccCA)
|
|
{
|
|
CertFreeCertificateContext(pccCA);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::Reset -- load config data, reset to indexed entry,
|
|
// return count
|
|
//
|
|
// Load the configuration data if not already loaded. To reload the data after
|
|
// the data have changed, CCertConfigPrivate must be released and reloaded.
|
|
//
|
|
// Resets the current config entry to the Certification Authority configuration
|
|
// listed in the configuration file, indexed by the Index parameter. 0 indexes
|
|
// the first configuration.
|
|
//
|
|
// Upon successful completion, *pCount will be set to the number of Certificate
|
|
// Authority configurations listed in the configuration file.
|
|
//
|
|
// Returns S_FALSE if no entries are available at or after the passed Index.
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::Reset(
|
|
/* [in] */ LONG Index,
|
|
/* [retval][out] */ LONG __RPC_FAR *pCount)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pCount)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "pCount");
|
|
}
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = _LoadTable();
|
|
_JumpIfError(hr, error, "_LoadTable");
|
|
}
|
|
*pCount = m_Count;
|
|
if (0 > Index || Index > m_Count)
|
|
{
|
|
Index = m_Count + 1;
|
|
hr = S_FALSE;
|
|
}
|
|
m_Index = Index - 1;
|
|
|
|
error:
|
|
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::Next -- skip to next config entry
|
|
//
|
|
// Changes the current config entry to the next Certification Authority
|
|
// configuration listed in the configuration file.
|
|
//
|
|
// Upon successful completion, *pIndex will be set to the index of Certificate
|
|
// Authority configurations listed in the configuration file.
|
|
//
|
|
// Returns S_FALSE if no more entries are available. *pIndex is set to -1.
|
|
// Returns S_OK on success. *pIndex is set to index the current configuration.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::Next(
|
|
/* [retval][out] */ LONG __RPC_FAR *pIndex)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pIndex)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "pIndex");
|
|
}
|
|
*pIndex = -1;
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = _LoadTable();
|
|
_JumpIfError(hr, error, "_LoadTable");
|
|
}
|
|
if (m_Index < m_Count)
|
|
{
|
|
m_Index++;
|
|
}
|
|
if (m_Index < m_Count)
|
|
{
|
|
*pIndex = m_Index;
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
error:
|
|
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::GetField -- return a field from the current config entry.
|
|
//
|
|
// pstrOut points to a BSTR string filled in by this routine. If *pstrOut is
|
|
// non-NULL and this method is successful, the old string is freed. If any
|
|
// value other than S_OK is returned, the string pointer will not be modified.
|
|
//
|
|
// Upon successful completion, *pstrOut will point to a string that contains
|
|
// the requested field from the current config entry.
|
|
//
|
|
// When the caller no longer needs the string, it must be freed by calling
|
|
// SysFreeString().
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::GetField(
|
|
/* [in] */ BSTR const strFieldName,
|
|
/* [retval][out] */ BSTR __RPC_FAR *pstrOut)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CERT_AUTHORITY_INFO *pcai;
|
|
BSTR bstr;
|
|
DWORD cwc;
|
|
WCHAR *pwsz = NULL;
|
|
WCHAR *pwszRevert = NULL;
|
|
WCHAR *pwszT = NULL;
|
|
BOOL fDesanitize = TRUE;
|
|
WCHAR awc[12];
|
|
|
|
if (NULL == pstrOut || NULL == strFieldName)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "pstrOut|strFieldName");
|
|
}
|
|
if (NULL != *pstrOut)
|
|
{
|
|
SysFreeString(*pstrOut);
|
|
*pstrOut = NULL;
|
|
}
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = _LoadTable();
|
|
_JumpIfError(hr, error, "_LoadTable");
|
|
}
|
|
|
|
if (-1 == m_Index)
|
|
{
|
|
m_Index++; // implicit Next() for compatibility with Version 1
|
|
}
|
|
if (0 > m_Index || m_Index >= m_Count)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "m_Index");
|
|
}
|
|
|
|
pcai = &m_pCertAuthorityInfo[m_Index];
|
|
bstr = strFieldName;
|
|
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_COMMONNAME))
|
|
{
|
|
pwsz = pcai->pwszSanitizedName;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_SANITIZEDNAME))
|
|
{
|
|
pwsz = pcai->pwszSanitizedName;
|
|
fDesanitize = FALSE;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_SHORTNAME))
|
|
{
|
|
pwsz = pcai->pwszSanitizedShortName;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_SANITIZEDSHORTNAME))
|
|
{
|
|
pwsz = pcai->pwszSanitizedShortName;
|
|
fDesanitize = FALSE;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_ORGUNIT))
|
|
{
|
|
pwsz = pcai->pwszSanitizedOrgUnit;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_ORGANIZATION))
|
|
{
|
|
pwsz = pcai->pwszSanitizedOrganization;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_LOCALITY))
|
|
{
|
|
pwsz = pcai->pwszSanitizedLocality;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_STATE))
|
|
{
|
|
pwsz = pcai->pwszSanitizedState;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_COUNTRY))
|
|
{
|
|
pwsz = pcai->pwszSanitizedCountry;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_CONFIG))
|
|
{
|
|
pwsz = pcai->pwszSanitizedConfig;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_EXCHANGECERTIFICATE))
|
|
{
|
|
pwsz = pcai->pwszSanitizedExchangeCertificate;
|
|
fDesanitize = FALSE;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_SIGNATURECERTIFICATE))
|
|
{
|
|
pwsz = pcai->pwszSanitizedSignatureCertificate;
|
|
fDesanitize = FALSE;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_DESCRIPTION) ||
|
|
0 == lstrcmpi(bstr, wszCONFIG_COMMENT)) // obsolete
|
|
{
|
|
pwsz = pcai->pwszSanitizedDescription;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_SERVER))
|
|
{
|
|
pwsz = wcschr(pcai->pwszSanitizedConfig, L'\\');
|
|
if (NULL == pwsz)
|
|
{
|
|
cwc = wcslen(pcai->pwszSanitizedConfig);
|
|
}
|
|
else
|
|
{
|
|
cwc = SAFE_SUBTRACT_POINTERS(pwsz, pcai->pwszSanitizedConfig);
|
|
}
|
|
pwszT = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszT)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(pwszT, pcai->pwszSanitizedConfig, cwc * sizeof(WCHAR));
|
|
pwszT[cwc] = L'\0';
|
|
pwsz = pwszT;
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_AUTHORITY))
|
|
{
|
|
pwsz = wcschr(pcai->pwszSanitizedConfig, L'\\');
|
|
if (NULL == pwsz)
|
|
{
|
|
pwsz = L"";
|
|
}
|
|
else
|
|
{
|
|
pwsz++;
|
|
}
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(bstr, wszCONFIG_FLAGS))
|
|
{
|
|
wsprintf(awc, L"%u", pcai->Flags);
|
|
CSASSERT(ARRAYSIZE(awc) > wcslen(awc));
|
|
pwsz = awc;
|
|
}
|
|
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError2(hr, error, "ConvertWszToBstr", CERTSRV_E_PROPERTY_EMPTY);
|
|
}
|
|
|
|
if (fDesanitize)
|
|
{
|
|
hr = myRevertSanitizeName(pwsz, &pwszRevert);
|
|
_JumpIfError(hr, error, "myRevertSanitizeName");
|
|
|
|
pwsz = pwszRevert;
|
|
}
|
|
|
|
if (!ConvertWszToBstr(pstrOut, pwsz, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszT)
|
|
{
|
|
LocalFree(pwszT);
|
|
}
|
|
if (NULL != pwszRevert)
|
|
{
|
|
LocalFree(pwszRevert);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::GetConfigFromPicker(
|
|
OPTIONAL IN HWND hwndParent,
|
|
OPTIONAL IN WCHAR const *pwszPrompt,
|
|
OPTIONAL IN WCHAR const *pwszTitle,
|
|
OPTIONAL IN WCHAR const *pwszSharedFolder,
|
|
IN BOOL fUseDS,
|
|
IN BOOL fCountOnly,
|
|
OUT DWORD *pdwCount,
|
|
OUT CRYPTUI_CA_CONTEXT const **ppCAContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CRYPTUI_CA_CONTEXT *prgCAC = NULL;
|
|
const CRYPTUI_CA_CONTEXT **pprgCAC = NULL;
|
|
CRYPTUI_SELECT_CA_STRUCT UISelectCA;
|
|
CRYPTUI_CA_CONTEXT const *pCAContext = NULL;
|
|
|
|
LONG i;
|
|
LONG realCount = 0;
|
|
LONG cCA = 0;
|
|
BSTR bsFieldName = NULL;
|
|
BSTR bsFieldValue = NULL;
|
|
WCHAR *pwszPtr;
|
|
WCHAR **ppwszCAName = NULL;
|
|
WCHAR **ppwszCAMachineName = NULL;
|
|
|
|
if ((NULL == ppCAContext) || (NULL == pdwCount))
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError (hr, error, "NULL parm");
|
|
}
|
|
|
|
*ppCAContext = NULL;
|
|
*pdwCount = 0;
|
|
|
|
m_fUseDS = fUseDS;
|
|
if (NULL != pwszSharedFolder)
|
|
{
|
|
hr = SetSharedFolder(const_cast<WCHAR *>(pwszSharedFolder));
|
|
_JumpIfError(hr, error, "configPrivate.SetSharedFolder");
|
|
}
|
|
|
|
hr = Reset(0, &cCA);
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "configPrivate.Reset");
|
|
}
|
|
hr = S_OK; // in case of S_FALSE;
|
|
|
|
if (0 < cCA)
|
|
{
|
|
prgCAC = (CRYPTUI_CA_CONTEXT *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT,
|
|
cCA * sizeof(CRYPTUI_CA_CONTEXT));
|
|
if (NULL == prgCAC)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
pprgCAC = (const CRYPTUI_CA_CONTEXT **) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT,
|
|
cCA * sizeof(const CRYPTUI_CA_CONTEXT *));
|
|
if (NULL == pprgCAC)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
ppwszCAName = (WCHAR **) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, cCA * sizeof(WCHAR *));
|
|
if (NULL == ppwszCAName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
ppwszCAMachineName = (WCHAR **) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, cCA * sizeof(WCHAR *));
|
|
if (NULL == ppwszCAMachineName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
if (!ConvertWszToBstr(&bsFieldName, wszCONFIG_CONFIG, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
realCount = 0;
|
|
while (realCount < cCA)
|
|
{
|
|
hr = GetField(bsFieldName, &bsFieldValue);
|
|
_JumpIfError(hr, error, "configPrivate.GetField");
|
|
|
|
pwszPtr = wcsstr(bsFieldValue, L"\\");
|
|
if (NULL == pwszPtr)
|
|
{
|
|
continue;
|
|
}
|
|
// change \ to null terminator
|
|
pwszPtr[0] = L'\0';
|
|
// point to CA name
|
|
pwszPtr = &pwszPtr[1];
|
|
|
|
ppwszCAName[realCount] = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pwszPtr) + 1) * sizeof(WCHAR));
|
|
if (NULL == ppwszCAName[realCount])
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
ppwszCAMachineName[realCount] = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(bsFieldValue) + 1) * sizeof(WCHAR));
|
|
if (NULL == ppwszCAMachineName[realCount])
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
prgCAC[realCount].dwSize = sizeof(CRYPTUI_CA_CONTEXT);
|
|
wcscpy(ppwszCAName[realCount], pwszPtr);
|
|
wcscpy(ppwszCAMachineName[realCount], bsFieldValue);
|
|
prgCAC[realCount].pwszCAName = ppwszCAName[realCount];
|
|
prgCAC[realCount].pwszCAMachineName = ppwszCAMachineName[realCount];
|
|
++realCount;
|
|
|
|
hr = Next(&i);
|
|
if (S_OK != hr)
|
|
{
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = S_OK; // no more entry is not an error
|
|
}
|
|
break;
|
|
}
|
|
if (NULL != bsFieldValue)
|
|
{
|
|
SysFreeString(bsFieldValue);
|
|
bsFieldValue = NULL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < realCount; ++i)
|
|
{
|
|
pprgCAC[i] = &prgCAC[i];
|
|
}
|
|
}
|
|
|
|
*pdwCount = realCount;
|
|
if (fCountOnly || 1 > realCount)
|
|
{
|
|
// done
|
|
goto error; // normal return
|
|
}
|
|
|
|
ZeroMemory(&UISelectCA, sizeof(CRYPTUI_SELECT_CA_STRUCT));
|
|
UISelectCA.cCAContext = realCount;
|
|
UISelectCA.rgCAContext = pprgCAC;
|
|
UISelectCA.dwSize = sizeof(UISelectCA);
|
|
UISelectCA.wszDisplayString = pwszPrompt;
|
|
UISelectCA.wszTitle = pwszTitle;
|
|
UISelectCA.hwndParent = hwndParent;
|
|
|
|
// cryptui called via delay load, wrap with try/except
|
|
__try
|
|
{
|
|
// invoke dialog
|
|
pCAContext = (CRYPTUI_CA_CONTEXT const *) CryptUIDlgSelectCA(&UISelectCA); // DelayLoad Wrapped
|
|
|
|
if (NULL == pCAContext) // user cancel?
|
|
{
|
|
hr = myHLastError();
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
}
|
|
_JumpError(hr, error, "CryptUIDlgSelectCA");
|
|
}
|
|
|
|
*ppCAContext = pCAContext;
|
|
|
|
hr = S_OK;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
|
|
error:
|
|
// change to default
|
|
m_fUseDS = TRUE;
|
|
|
|
if (NULL != ppwszCAName)
|
|
{
|
|
for (i = 0; i < realCount; ++i)
|
|
{
|
|
if (NULL != ppwszCAName[i])
|
|
{
|
|
LocalFree(ppwszCAName[i]);
|
|
}
|
|
}
|
|
LocalFree(ppwszCAName);
|
|
}
|
|
if (NULL != ppwszCAMachineName)
|
|
{
|
|
for (i = 0; i < realCount; ++i)
|
|
{
|
|
if (NULL != ppwszCAMachineName[i])
|
|
{
|
|
LocalFree(ppwszCAMachineName[i]);
|
|
}
|
|
}
|
|
LocalFree(ppwszCAMachineName);
|
|
}
|
|
if (NULL != pprgCAC)
|
|
{
|
|
LocalFree(pprgCAC);
|
|
}
|
|
if (NULL != prgCAC)
|
|
{
|
|
LocalFree(prgCAC);
|
|
}
|
|
if (NULL != bsFieldName)
|
|
{
|
|
SysFreeString(bsFieldName);
|
|
}
|
|
if (NULL != bsFieldValue)
|
|
{
|
|
SysFreeString(bsFieldValue);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::GetConfig -- select a cert issuer, return config data.
|
|
//
|
|
// pstrOut points to a BSTR string filled in by this routine. If *pstrOut is
|
|
// non-NULL and this method is successful, the old string is freed. If any
|
|
// value other than S_OK is returned, the string pointer will not be modified.
|
|
//
|
|
// Flags must be set to 0.
|
|
//
|
|
// Upon successful completion, *pstrOut will point to a string that contains
|
|
// the server name and Certification Authority name.
|
|
//
|
|
// When the caller no longer needs the string, it must be freed by calling
|
|
// SysFreeString().
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::GetConfig(
|
|
/* [in] */ LONG Flags,
|
|
/* [retval][out] */ BSTR __RPC_FAR *pstrOut)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR *pwszSanitizedConfig = NULL;
|
|
WCHAR *pwszConfigRevert = NULL;
|
|
WCHAR *pwszSanitize = NULL;
|
|
HMODULE hMod = NULL;
|
|
CRYPTUI_CA_CONTEXT const *pCAContext = NULL;
|
|
DWORD dwCACount;
|
|
LONG lIndex;
|
|
LONG cCA;
|
|
LONG i;
|
|
|
|
if (NULL == pstrOut)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "pstrOut");
|
|
}
|
|
if (NULL != *pstrOut)
|
|
{
|
|
SysFreeString(*pstrOut);
|
|
*pstrOut = NULL;
|
|
}
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = _LoadTable();
|
|
_JumpIfError(hr, error, "_LoadTable");
|
|
}
|
|
if (0 > m_Count)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "m_Count");
|
|
}
|
|
|
|
switch (Flags)
|
|
{
|
|
case CC_UIPICKCONFIG:
|
|
hMod = LoadLibrary(L"cryptui.dll");
|
|
if (NULL != hMod)
|
|
{
|
|
hr = GetConfigFromPicker(
|
|
GetDesktopWindow(), // hDlg
|
|
NULL, // pwszPrompt
|
|
NULL, // pwszTitle
|
|
m_pwszSharedFolder,
|
|
TRUE, // fUseDS
|
|
FALSE, // fCountOnly
|
|
&dwCACount,
|
|
&pCAContext);
|
|
_JumpIfError(hr, error, "GetConfigFromPicker");
|
|
|
|
if (NULL == pCAContext)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
|
|
_JumpError(hr, error, "No CA Config");
|
|
}
|
|
|
|
// ca name in UI has been reverted so sanitize it
|
|
|
|
hr = mySanitizeName(pCAContext->pwszCAName, &pwszSanitize);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
pwszSanitizedConfig = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pwszSanitize) +
|
|
wcslen(pCAContext->pwszCAMachineName) + 2) *
|
|
sizeof(WCHAR));
|
|
if (NULL == pwszSanitizedConfig)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwszSanitizedConfig, pCAContext->pwszCAMachineName);
|
|
wcscat(pwszSanitizedConfig, L"\\");
|
|
wcscat(pwszSanitizedConfig, pwszSanitize);
|
|
for (lIndex = 0; lIndex < m_Count; ++lIndex)
|
|
{
|
|
if (0 == lstrcmpi(pwszSanitizedConfig, m_pCertAuthorityInfo[lIndex].pwszSanitizedConfig))
|
|
{
|
|
// update index
|
|
Reset(lIndex + 1, &cCA);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// FALLTHROUGH
|
|
|
|
case CC_LOCALCONFIG:
|
|
case CC_LOCALACTIVECONFIG:
|
|
case CC_DEFAULTCONFIG:
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "no CAs");
|
|
}
|
|
if (CC_LOCALCONFIG != Flags && CC_LOCALACTIVECONFIG != Flags)
|
|
{
|
|
// Make a recursive call to first look for a local pingable CA.
|
|
// If that fails, pick any pingable CA.
|
|
|
|
hr = GetConfig(CC_LOCALACTIVECONFIG, pstrOut);
|
|
if (S_OK == hr)
|
|
{
|
|
break;
|
|
}
|
|
_PrintError(hr, "GetConfig(CC_LOCALACTIVECONFIG)");
|
|
}
|
|
for (i = 0; i < m_Count; i++)
|
|
{
|
|
CSASSERT(NULL != m_pCertAuthorityInfo[i].pwszSanitizedConfig);
|
|
|
|
pwszSanitizedConfig = m_pCertAuthorityInfo[i].pwszSanitizedConfig;
|
|
|
|
if (CC_LOCALCONFIG == Flags || CC_LOCALACTIVECONFIG == Flags)
|
|
{
|
|
DWORD InfoFlags;
|
|
|
|
InfoFlags = m_pCertAuthorityInfo[i].Flags;
|
|
if (0 == (CAIF_LOCAL & InfoFlags))
|
|
{
|
|
continue;
|
|
}
|
|
if (0 == (CAIF_REGISTRY & InfoFlags))
|
|
{
|
|
LONG j;
|
|
|
|
for (j = i + 1; j < m_Count; j++)
|
|
{
|
|
InfoFlags = m_pCertAuthorityInfo[j].Flags;
|
|
|
|
if ((CAIF_LOCAL & InfoFlags) &&
|
|
(CAIF_REGISTRY & InfoFlags))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j < m_Count)
|
|
{
|
|
i = j;
|
|
}
|
|
}
|
|
}
|
|
if (CC_LOCALCONFIG == Flags)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = myRevertSanitizeName(pwszSanitizedConfig, &pwszConfigRevert);
|
|
_JumpIfError(hr, error, "myRevertSanitizeName");
|
|
|
|
hr = myPingCertSrv(
|
|
pwszConfigRevert,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
// update index
|
|
Reset(i + 1, &cCA);
|
|
break; // take it
|
|
}
|
|
if (NULL != pwszConfigRevert)
|
|
{
|
|
LocalFree(pwszConfigRevert);
|
|
pwszConfigRevert = NULL;
|
|
}
|
|
}
|
|
if (S_OK != hr || i >= m_Count)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
|
|
_JumpError(hr, error, "No matching CA");
|
|
}
|
|
break;
|
|
|
|
case CC_FIRSTCONFIG:
|
|
if (NULL == m_pCertAuthorityInfo)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "no CAs");
|
|
}
|
|
pwszSanitizedConfig = m_pCertAuthorityInfo[0].pwszSanitizedConfig;
|
|
// update index
|
|
Reset(1, &cCA);
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Flags");
|
|
}
|
|
|
|
if(!*pstrOut)
|
|
{
|
|
if (NULL == pwszConfigRevert)
|
|
{
|
|
// always revert
|
|
|
|
hr = myRevertSanitizeName(pwszSanitizedConfig, &pwszConfigRevert);
|
|
_JumpIfError(hr, error, "myRevertSanitizeName");
|
|
}
|
|
if (!ConvertWszToBstr(pstrOut, pwszConfigRevert, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hMod)
|
|
{
|
|
FreeLibrary(hMod);
|
|
if (NULL != pwszSanitizedConfig)
|
|
{
|
|
LocalFree(pwszSanitizedConfig);
|
|
}
|
|
}
|
|
if (NULL != pwszConfigRevert)
|
|
{
|
|
LocalFree(pwszConfigRevert);
|
|
}
|
|
if (NULL != pwszSanitize)
|
|
{
|
|
LocalFree(pwszSanitize);
|
|
}
|
|
if (NULL != pCAContext)
|
|
{
|
|
CryptUIDlgFreeCAContext(pCAContext);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// CCertConfigPrivate::SetSharedFolder -- set the shared folder
|
|
//
|
|
// strSharedFolder is the new shared folder dorectory path.
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CCertConfigPrivate::SetSharedFolder(
|
|
/* [in] */ const BSTR strSharedFolder)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwsz;
|
|
|
|
pwsz = NULL;
|
|
if (NULL != strSharedFolder)
|
|
{
|
|
hr = myDupString(strSharedFolder, &pwsz);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
if (NULL != m_pwszSharedFolder)
|
|
{
|
|
LocalFree(m_pwszSharedFolder);
|
|
}
|
|
m_pwszSharedFolder = pwsz;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT WINAPI
|
|
certLoadFile(
|
|
WCHAR const *pwszfn,
|
|
BYTE **ppbData,
|
|
DWORD *pcbData)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD cbLow, cbHigh, cbRead;
|
|
HRESULT hr;
|
|
|
|
hFile = CreateFile(
|
|
pwszfn,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0);
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "CreateFile", pwszfn);
|
|
}
|
|
|
|
cbLow = GetFileSize(hFile, &cbHigh);
|
|
if (0xffffffff == cbLow)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "GetFileSize");
|
|
}
|
|
|
|
*ppbData = (BYTE *) LocalAlloc(LMEM_FIXED, cbLow + 1);
|
|
if (NULL == *ppbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
if (!ReadFile(hFile, *ppbData, cbLow, &cbRead, NULL))
|
|
{
|
|
hr = myHLastError();
|
|
LocalFree(*ppbData);
|
|
*ppbData = NULL;
|
|
_JumpError(hr, error, "ReadFile");
|
|
}
|
|
(*ppbData)[cbLow] = '\0';
|
|
*pcbData = cbLow;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// certTrimToken -- trim white space from the beginning and end of a line.
|
|
// Bump caller's string pointer, reduce the caller's input buffer count,
|
|
// and L'\0' terminate the result -- IN PLACE!
|
|
|
|
VOID
|
|
certTrimToken(
|
|
WCHAR **ppwsz)
|
|
{
|
|
WCHAR *pwsz;
|
|
WCHAR *pwszEnd;
|
|
static WCHAR wszTrim[] = L" \t\r\n";
|
|
|
|
pwsz = *ppwsz;
|
|
while (L'\0' != *pwsz)
|
|
{
|
|
if (NULL == wcschr(wszTrim, *pwsz))
|
|
{
|
|
break;
|
|
}
|
|
pwsz++;
|
|
}
|
|
|
|
pwszEnd = wcschr(pwsz, L'\0');
|
|
assert(NULL != pwszEnd);
|
|
|
|
while (pwsz < pwszEnd)
|
|
{
|
|
if (NULL == wcschr(wszTrim, *--pwszEnd))
|
|
{
|
|
break;
|
|
}
|
|
*pwszEnd = L'\0';
|
|
}
|
|
*ppwsz = pwsz;
|
|
}
|
|
|
|
|
|
BOOL
|
|
certExtractToken(
|
|
WCHAR **ppwszIn,
|
|
WCHAR const **ppwszOut)
|
|
{
|
|
WCHAR *pwsz;
|
|
WCHAR *pwszNext;
|
|
WCHAR *pwsz2;
|
|
BOOL fQuoted = FALSE;
|
|
|
|
pwsz = *ppwszIn;
|
|
while (L' ' == *pwsz || L'\t' == *pwsz)
|
|
{
|
|
pwsz++;
|
|
}
|
|
|
|
pwszNext = pwsz;
|
|
if (L'"' == *pwsz)
|
|
{
|
|
fQuoted = TRUE;
|
|
pwsz++;
|
|
pwszNext++;
|
|
|
|
while (TRUE)
|
|
{
|
|
// Find a mid-string escaped quote or the terminating quote.
|
|
|
|
pwszNext = wcschr(pwszNext, L'"');
|
|
|
|
if (NULL == pwszNext)
|
|
{
|
|
break; // missing terminating quote!
|
|
}
|
|
|
|
// If a terminating quote, terminate the string with L'\0',
|
|
// and point past the quoted string. Break to search for a comma.
|
|
|
|
if (L'"' != pwszNext[1])
|
|
{
|
|
*pwszNext++ = L'\0';
|
|
break;
|
|
}
|
|
|
|
// Found a mid-string escaped quote. Move the first part of the
|
|
// string forward one character position, overwriting the first
|
|
// quote character. Bump the string pointer to the new location,
|
|
// point pwszNext past the remaining quote character, and loop.
|
|
|
|
MoveMemory(
|
|
&pwsz[1],
|
|
pwsz,
|
|
SAFE_SUBTRACT_POINTERS(pwszNext, pwsz) * sizeof(*pwsz));
|
|
pwsz++;
|
|
pwszNext += 2;
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszNext)
|
|
{
|
|
pwszNext = wcschr(pwszNext, L',');
|
|
}
|
|
if (NULL != pwszNext)
|
|
{
|
|
*pwszNext++ = L'\0';
|
|
}
|
|
else
|
|
{
|
|
pwszNext = wcschr(pwsz, L'\0');
|
|
assert(NULL != pwszNext);
|
|
}
|
|
|
|
certTrimToken(&pwsz);
|
|
|
|
*ppwszOut = pwsz;
|
|
*ppwszIn = pwszNext;
|
|
|
|
return(fQuoted || L'\0' != *pwsz);
|
|
}
|
|
|
|
|
|
// certExtractLine -- convert one line to Unicode and return it in a L'\0'
|
|
// terminated output buffer. Bump caller's input buffer pointer and reduce
|
|
// the caller's input buffer count.
|
|
|
|
HRESULT
|
|
certExtractLine(
|
|
IN char const **ppchLine,
|
|
IN OUT LONG *pcchLine,
|
|
OUT WCHAR *pwc,
|
|
IN OUT LONG *pcwc)
|
|
{
|
|
char const *pch;
|
|
char const *pchEnd;
|
|
LONG cch;
|
|
HRESULT hr = S_OK;
|
|
int cwc;
|
|
|
|
pch = *ppchLine;
|
|
cch = *pcchLine;
|
|
pchEnd = &pch[cch];
|
|
|
|
while (pch < pchEnd)
|
|
{
|
|
if ('\n' == *pch++)
|
|
{
|
|
pchEnd = pch;
|
|
cch = SAFE_SUBTRACT_POINTERS(pchEnd, *ppchLine);
|
|
break;
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
cwc = MultiByteToWideChar(GetACP(), 0, *ppchLine, cch, pwc, *pcwc - 1);
|
|
if (0 == cwc)
|
|
{
|
|
hr = myHLastError();
|
|
break;
|
|
}
|
|
pwc[cwc] = L'\0';
|
|
*pcwc = cwc;
|
|
*pcchLine -= cch;
|
|
*ppchLine = pchEnd;
|
|
} while (FALSE);
|
|
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Format of each line is:
|
|
// <name>, <OrgUnit>, <Organization>, <Locality>, <State>, <Country>, <Server Name>, <Exchange Cert>, <Self signed cert>, <Comment>
|
|
|
|
HRESULT
|
|
certParseLine(
|
|
char const **ppchLine,
|
|
LONG *pcchLine,
|
|
CERT_AUTHORITY_INFO *pcai,
|
|
WCHAR *pwsz,
|
|
LONG *pcwc)
|
|
{
|
|
HRESULT hr;
|
|
LONG cwc;
|
|
|
|
do
|
|
{
|
|
if (0 == *pcchLine)
|
|
{
|
|
hr = S_OK;
|
|
*pcwc = 0;
|
|
goto error;
|
|
}
|
|
cwc = *pcwc;
|
|
hr = certExtractLine(ppchLine, pcchLine, pwsz, &cwc);
|
|
if (S_OK != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
*pcwc = cwc + 1;
|
|
certTrimToken(&pwsz);
|
|
} while (L'\0' == *pwsz || L'#' == *pwsz);
|
|
|
|
if (!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedName) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedOrgUnit) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedOrganization) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedLocality) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedState) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedCountry) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedConfig) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedExchangeCertificate) ||
|
|
!certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedSignatureCertificate))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto error;
|
|
}
|
|
certExtractToken(&pwsz, (WCHAR const **) &pcai->pwszSanitizedDescription);
|
|
pcai->Flags = CAIF_SHAREDFOLDERENTRY;
|
|
|
|
error:
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
LONG
|
|
certSkipLine(
|
|
IN char const **ppchData,
|
|
IN LONG *pcchData)
|
|
{
|
|
LONG cb = 0;
|
|
HRESULT hr;
|
|
|
|
do
|
|
{
|
|
CERT_AUTHORITY_INFO cai;
|
|
WCHAR awcLine[cwcCONFIGLINEMAX];
|
|
LONG cwc;
|
|
char const *pchData;
|
|
LONG cchData;
|
|
|
|
pchData = *ppchData;
|
|
cchData = *pcchData;
|
|
cwc = sizeof(awcLine)/sizeof(awcLine[0]);
|
|
hr = certParseLine(&pchData, &cchData, &cai, awcLine, &cwc);
|
|
if (S_OK != hr || 0 == cwc)
|
|
{
|
|
break;
|
|
}
|
|
cb = sizeof(cai) + cwc * sizeof(WCHAR);
|
|
*ppchData = pchData;
|
|
*pcchData = cchData;
|
|
} while (FALSE);
|
|
//printf("certSkipLine: %u bytes\n", cb);
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(cb);
|
|
}
|
|
|
|
|
|
VOID
|
|
certAppendBSFileName(
|
|
IN OUT WCHAR *pwszPath,
|
|
IN WCHAR *pwszBSFN) // backslash + filename.ext
|
|
{
|
|
DWORD cwc;
|
|
|
|
cwc = wcslen(pwszPath);
|
|
if (0 < cwc--)
|
|
{
|
|
if (L'\\' == pwszPath[cwc])
|
|
{
|
|
pwszPath[cwc] = L'\0';
|
|
}
|
|
}
|
|
wcscat(pwszPath, pwszBSFN);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
certGetConfigFileName(
|
|
OUT WCHAR **ppwszFileConfig)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwLen;
|
|
DWORD dwType;
|
|
HKEY hKeyConfig = NULL;
|
|
WCHAR *pwszFileName = NULL;
|
|
|
|
*ppwszFileConfig = NULL;
|
|
|
|
do
|
|
{
|
|
hr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
wszREGKEYCONFIGPATH,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyConfig);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"RegOpenKeyEx",
|
|
wszREGKEYCONFIGPATH,
|
|
ERROR_FILE_NOT_FOUND);
|
|
break;
|
|
}
|
|
|
|
// Get the size of the value first
|
|
|
|
hr = RegQueryValueEx(
|
|
hKeyConfig,
|
|
g_wszRegDirectory,
|
|
0,
|
|
&dwType,
|
|
NULL,
|
|
&dwLen);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"RegQueryValueEx",
|
|
g_wszRegDirectory,
|
|
ERROR_FILE_NOT_FOUND);
|
|
break;
|
|
}
|
|
|
|
if (0 == dwLen)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_PrintErrorStr2(hr, "RegQueryValueEx", g_wszRegDirectory, hr);
|
|
break;
|
|
}
|
|
|
|
// Allocate enough memory for the directory path plus the file name.
|
|
|
|
pwszFileName = (WCHAR *) LocalAlloc(LMEM_FIXED,
|
|
dwLen + (wcslen(g_wszConfigFile) + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszFileName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_PrintError2(hr, "LocalAlloc", hr);
|
|
break;
|
|
}
|
|
|
|
hr = RegQueryValueEx(
|
|
hKeyConfig,
|
|
g_wszRegDirectory,
|
|
0,
|
|
&dwType,
|
|
(BYTE *) pwszFileName,
|
|
&dwLen);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr(hr, "RegQueryValueEx", g_wszRegDirectory);
|
|
break;
|
|
}
|
|
if (L'\0' == *pwszFileName)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
// Place config file name on end of path to open
|
|
|
|
certAppendBSFileName(pwszFileName, g_wszConfigFile);
|
|
*ppwszFileConfig = pwszFileName;
|
|
pwszFileName = NULL;
|
|
|
|
} while (FALSE);
|
|
|
|
if (NULL != pwszFileName)
|
|
{
|
|
LocalFree(pwszFileName);
|
|
}
|
|
if (NULL != hKeyConfig)
|
|
{
|
|
RegCloseKey(hKeyConfig);
|
|
}
|
|
return(myHError(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
certLoadConfigFile(
|
|
IN WCHAR const *pwszSharedFolder,
|
|
OUT BYTE **ppchData,
|
|
OUT DWORD *pcchData)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszfn = NULL;
|
|
|
|
*ppchData = NULL;
|
|
*pcchData = 0;
|
|
|
|
if (NULL == pwszSharedFolder)
|
|
{
|
|
hr = certGetConfigFileName(&pwszfn);
|
|
_JumpIfError2(
|
|
hr,
|
|
error,
|
|
"certGetConfigFileName",
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
}
|
|
else
|
|
{
|
|
pwszfn = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pwszSharedFolder) + wcslen(g_wszConfigFile) + 1) *
|
|
sizeof(WCHAR));
|
|
if (NULL == pwszfn)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwszfn, pwszSharedFolder);
|
|
certAppendBSFileName(pwszfn, g_wszConfigFile);
|
|
}
|
|
if (NULL != pwszfn)
|
|
{
|
|
hr = certLoadFile(pwszfn, ppchData, pcchData);
|
|
_JumpIfError3(
|
|
hr,
|
|
error,
|
|
"certLoadFile",
|
|
HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE),
|
|
HRESULT_FROM_WIN32(ERROR_INVALID_NETNAME));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszfn)
|
|
{
|
|
LocalFree(pwszfn);
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// certRequestGetConfig -- return config data for all requested authorities.
|
|
//
|
|
// *pIndex should be set to 0 prior to the first call. It will be modified by
|
|
// certRequestGetConfig to index the next entry after those returned.
|
|
//
|
|
// *pCount is a pointer to the number of authorities for which information is
|
|
// requested. Upon successful completion, *pCount will contain the number of
|
|
// authorities for which information is returned. If the returned value is
|
|
// less than requested (or 0) no more entries are available.
|
|
//
|
|
// ppCertAuthorityInfo is a pointer to an uninitialized pointer on input.
|
|
// Upon successful completion, a pointer to an array of CERT_AUTHORITY_INFO
|
|
// structures is returned. When the caller no longer needs the array, it must
|
|
// be freed by calling CertFreeMemory.
|
|
//
|
|
// Returns S_OK on success.
|
|
//+--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
certRequestGetConfigInfo(
|
|
IN WCHAR *pwszSharedFolder,
|
|
IN OUT LONG *pIndex,
|
|
IN OUT LONG *pCount,
|
|
OUT CERT_AUTHORITY_INFO **ppCertAuthorityInfo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG cSkip = *pIndex;
|
|
LONG cLine = *pCount;
|
|
DWORD cchData;
|
|
char const *pchData = NULL;
|
|
LONG cLineReturned = 0;
|
|
CERT_AUTHORITY_INFO *pcaiBase = NULL;
|
|
|
|
*ppCertAuthorityInfo = NULL;
|
|
|
|
do
|
|
{
|
|
char const *pch;
|
|
LONG cch;
|
|
char const *pchSave;
|
|
LONG cchSave;
|
|
LONG cbTotal;
|
|
CERT_AUTHORITY_INFO *pcai;
|
|
WCHAR *pwc;
|
|
LONG cwc;
|
|
LONG cwcRemain;
|
|
LONG i;
|
|
|
|
hr = certLoadConfigFile(pwszSharedFolder, (BYTE **) &pchData, &cchData);
|
|
if (S_OK != hr || (NULL == pchData && 0 == cchData))
|
|
{
|
|
break;
|
|
}
|
|
pch = pchData;
|
|
cch = cchData;
|
|
|
|
// Skip cSkip entries:
|
|
|
|
//printf("Skipping lines:\n");
|
|
for (i = 0; i < cSkip; i++)
|
|
{
|
|
if (0 == certSkipLine(&pch, &cch))
|
|
{
|
|
break; // ran out of config data
|
|
}
|
|
}
|
|
if (i < cSkip)
|
|
{
|
|
break; // no data to return
|
|
}
|
|
pchSave = pch;
|
|
cchSave = cch;
|
|
|
|
// Compute total size of cLine entries:
|
|
|
|
//printf("Sizing lines:\n");
|
|
cbTotal = 0;
|
|
for (i = 0; i < cLine; i++)
|
|
{
|
|
LONG cb;
|
|
|
|
cb = certSkipLine(&pch, &cch);
|
|
if (0 == cb)
|
|
{
|
|
cLine = i; // reduce return line count
|
|
break; // ran out of config data
|
|
}
|
|
cbTotal += cb;
|
|
}
|
|
if (0 == cLine)
|
|
{
|
|
break; // no data to return
|
|
}
|
|
|
|
pcaiBase = (CERT_AUTHORITY_INFO *) LocalAlloc(LMEM_FIXED, cbTotal);
|
|
if (NULL == pcaiBase)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
//printf("Returning lines:\n");
|
|
pch = pchSave;
|
|
cch = cchSave;
|
|
pcai = pcaiBase;
|
|
pwc = (WCHAR *) &pcai[cLine];
|
|
cwcRemain = (cbTotal - sizeof(*pcai) * cLine)/sizeof(*pwc);
|
|
for (i = 0; i < cLine; i++)
|
|
{
|
|
cwc = cwcRemain;
|
|
hr = certParseLine(&pch, &cch, pcai, pwc, &cwc);
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
pcai++;
|
|
pwc += cwc;
|
|
cwcRemain -= cwc;
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
cLineReturned = cLine;
|
|
*ppCertAuthorityInfo = pcaiBase;
|
|
pcaiBase = NULL;
|
|
hr = S_OK;
|
|
} while (FALSE);
|
|
|
|
*pIndex += cLineReturned;
|
|
*pCount = cLineReturned;
|
|
|
|
if (NULL != pcaiBase)
|
|
{
|
|
LocalFree(pcaiBase);
|
|
}
|
|
if (NULL != pchData)
|
|
{
|
|
LocalFree(const_cast<char *>(pchData));
|
|
}
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myGetConfigFromPicker(
|
|
OPTIONAL IN HWND hwndParent,
|
|
OPTIONAL IN WCHAR const *pwszPrompt,
|
|
OPTIONAL IN WCHAR const *pwszTitle,
|
|
OPTIONAL IN WCHAR const *pwszSharedFolder,
|
|
IN BOOL fUseDS,
|
|
IN BOOL fCountOnly,
|
|
OUT DWORD *pdwCACount,
|
|
OUT CRYPTUI_CA_CONTEXT const **ppCAContext)
|
|
{
|
|
HRESULT hr;
|
|
CCertConfigPrivate configPrivate;
|
|
|
|
hr = configPrivate.GetConfigFromPicker(
|
|
hwndParent,
|
|
pwszPrompt,
|
|
pwszTitle,
|
|
pwszSharedFolder,
|
|
fUseDS,
|
|
fCountOnly,
|
|
pdwCACount,
|
|
ppCAContext);
|
|
_JumpIfError(hr, error, "configPrivate.GetConfigFromPicker");
|
|
|
|
error:
|
|
CSASSERT(S_OK == hr || FAILED(hr));
|
|
return(hr);
|
|
}
|