2025-04-27 07:49:33 -04:00

5589 lines
125 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: ds.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <winldap.h>
#include <wininet.h>
#include <winineti.h> // for MAX_CACHE_ENTRY_INFO_SIZE
#include <setupapi.h>
#include <ocmanage.h>
#include <certca.h>
#include <autoenr.h>
#include <ntdsapi.h>
#include <dsgetdc.h>
#include <lmerr.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include "initcert.h"
#include "cainfop.h"
#include "csldap.h"
#include "certtype.h"
#include "certacl.h"
#include "csber.h"
WCHAR const s_wszLDAP[] = L"ldap:///";
HRESULT
cuGetTemplateNames(
IN WCHAR const *pwszTemplate,
OUT WCHAR **ppwszCN,
OUT WCHAR **ppwszDisplayName)
{
HRESULT hr;
WCHAR *pwszCN = NULL;
WCHAR *pwszDisplayName = NULL;
HCERTTYPE hCertType = NULL;
DWORD dwFlags;
WCHAR **apwszCertTypeName = NULL;
WCHAR **apwszCertTypeCN = NULL;
*ppwszCN = NULL;
*ppwszDisplayName = NULL;
dwFlags = CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES;
if (!g_fUserRegistry)
{
dwFlags |= CT_FIND_LOCAL_SYSTEM;
}
if (g_fForce)
{
dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
}
hr = CAFindCertTypeByName(pwszTemplate, NULL, dwFlags, &hCertType);
if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
{
hr = CAFindCertTypeByName(
pwszTemplate,
NULL,
CT_FIND_BY_OID | dwFlags,
&hCertType);
}
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", pwszTemplate);
hr = CAGetCertTypeProperty(
hCertType,
CERTTYPE_PROP_CN,
&apwszCertTypeCN);
_JumpIfError(hr, error, "CAGetCertTypeProperty");
if (NULL != apwszCertTypeCN && NULL != apwszCertTypeCN[0])
{
hr = myDupString(apwszCertTypeCN[0], &pwszCN);
_JumpIfError(hr, error, "myDupString");
}
hr = CAGetCertTypeProperty(
hCertType,
CERTTYPE_PROP_FRIENDLY_NAME,
&apwszCertTypeName);
_JumpIfError(hr, error, "CAGetCertTypeProperty");
if (NULL != apwszCertTypeName && NULL != apwszCertTypeName[0])
{
hr = myDupString(apwszCertTypeName[0], &pwszDisplayName);
_JumpIfError(hr, error, "myDupString");
}
if (NULL != pwszCN)
{
*ppwszCN = pwszCN;
pwszCN = NULL;
}
if (NULL != pwszDisplayName)
{
*ppwszDisplayName = pwszDisplayName;
pwszDisplayName = NULL;
}
hr = S_OK;
error:
if (NULL != hCertType)
{
if (NULL != apwszCertTypeName)
{
CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
}
if (NULL != apwszCertTypeCN)
{
CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
}
CACloseCertType(hCertType);
}
if (NULL != pwszCN)
{
LocalFree(pwszCN);
}
if (NULL != pwszDisplayName)
{
LocalFree(pwszDisplayName);
}
return(hr);
}
HRESULT
DumpDSStore(
OPTIONAL IN WCHAR const *pwszDN,
IN BOOL fCRL,
IN BOOL fDeltaCRL,
IN DWORD iCert,
IN DWORD iCRL,
OPTIONAL IN WCHAR const *pwszfnOut)
{
HRESULT hr;
HCERTSTORE hStoreDS = NULL;
WCHAR *pwszServer = NULL;
WCHAR *pwszCAName = NULL;
WCHAR *pwszSanitizedName = NULL;
WCHAR *pwszURL = NULL;
WCHAR *pwszTemplateAlloc = NULL;
WCHAR const *pwszTemplate;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
LDAP *pld = NULL;
//if (NULL != pwszDN) wprintf(L"pwszDN = \"%ws\"\n", pwszDN);
// Get the object name and open its cert or CRL store
if (NULL == pwszDN)
{
if (NULL == g_pwszConfig)
{
hr = cuSetConfig();
_JumpIfError(hr, error, "cuSetConfig");
}
pwszTemplate = fCRL?
g_wszzLDAPRevocationURLTemplate : g_wszzLDAPIssuerCertURLTemplate;
hr = mySplitConfigString(g_pwszConfig, &pwszServer, &pwszCAName);
_JumpIfError(hr, error, "mySplitConfigString");
hr = mySanitizeName(pwszCAName, &pwszSanitizedName);
_JumpIfError(hr, error, "mySanitizeName");
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
}
else
{
pwszTemplate = fCRL?
wszFCSAPARM_DSCRLATTRIBUTE :
(g_fEnterpriseRegistry?
wszFCSAPARM_DSCROSSCERTPAIRATTRIBUTE :
(g_fUserRegistry?
wszFCSAPARM_DSUSERCERTATTRIBUTE :
wszFCSAPARM_DSCACERTATTRIBUTE));
pwszTemplateAlloc = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(s_wszLDAP) +
wcslen(pwszDN) +
wcslen(pwszTemplate) + 1) * sizeof(WCHAR));
if (NULL == pwszTemplateAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszTemplateAlloc, s_wszLDAP);
wcscat(pwszTemplateAlloc, pwszDN);
wcscat(pwszTemplateAlloc, pwszTemplate);
pwszTemplate = pwszTemplateAlloc;
}
hr = myFormatCertsrvStringArray(
FALSE, // fURL
NULL != pwszServer? pwszServer : g_wszEmpty, // pwszServerName_p1_2
NULL != pwszSanitizedName? pwszSanitizedName : g_wszEmpty,
// pwszSanitizedName_p3_7
0, // iCert_p4
NULL != strDomainDN? strDomainDN : g_wszEmpty, // pwszDomainDN_p5
NULL != strConfigDN? strConfigDN : g_wszEmpty, // pwszConfigDN_p6
iCRL, // iCRL_p8
fDeltaCRL, // fDeltaCRL_p9
TRUE, // fDSAttrib_p10_11
1, // cStrings
&pwszTemplate, // apwszStringsIn
&pwszURL); // apwszStringsOut
_JumpIfError(hr, error, "myFormatCertsrvStringArray");
wprintf(L"\n%ws:\n", pwszURL);
hStoreDS = CertOpenStore(
CERT_STORE_PROV_LDAP_W,
X509_ASN_ENCODING,
NULL,
CERT_STORE_READONLY_FLAG |
CERT_STORE_ENUM_ARCHIVED_FLAG,
(VOID *) pwszURL);
if (NULL == hStoreDS)
{
hr = myHLastError();
_JumpErrorStr(hr, error, "CertOpenStore", pwszURL);
}
if (fCRL)
{
iCRL = MAXDWORD;
if (NULL != pwszfnOut)
{
iCRL = 0;
}
}
hr = cuDumpAndVerifyStore(
hStoreDS,
DVNS_VERIFYCERT | DVNS_CASTORE | DVNS_DUMPPROPERTIES,
NULL, // pwszCertName
iCert,
iCRL,
MAXDWORD, // iCTL
pwszfnOut,
NULL);
_JumpIfError(hr, error, "cuDumpAndVerifyStore");
error:
if (NULL != pwszTemplateAlloc)
{
LocalFree(pwszTemplateAlloc);
}
if (NULL != pwszSanitizedName)
{
LocalFree(pwszSanitizedName);
}
if (NULL != pwszServer)
{
LocalFree(pwszServer);
}
if (NULL != pwszCAName)
{
LocalFree(pwszCAName);
}
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
if (NULL != hStoreDS)
{
CertCloseStore(hStoreDS, CERT_CLOSE_STORE_CHECK_FLAG);
}
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
HRESULT
verbDSCert(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszCertIndex,
OPTIONAL IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
DWORD iCert = MAXDWORD;
WCHAR const *pwszDN = NULL;
if (NULL != pwszCertIndex)
{
hr = cuGetLong(pwszCertIndex, (LONG *) &iCert);
if (S_OK != hr)
{
if (NULL != pwszfnOut)
{
_JumpError(hr, error, "CertIndex must be a number");
}
pwszDN = pwszCertIndex;
iCert = MAXDWORD;
}
}
hr = DumpDSStore(pwszDN, FALSE, FALSE, iCert, MAXDWORD, pwszfnOut);
_JumpIfError(hr, error, "DumpDSStore");
error:
return(hr);
}
HRESULT
GetCACertCount(
IN DISPATCHINTERFACE *pdiRequest,
OUT DWORD *pcCACerts)
{
HRESULT hr;
BSTR str = NULL;
DWORD cwc;
WCHAR const *pwc;
CAINFO CAInfo;
hr = Request_GetCACertificate(
pdiRequest,
GETCERT_CAINFO, // fExchangeCertificate
g_pwszConfig,
CR_OUT_BINARY,
&str);
_JumpIfError(hr, error, "Request_GetCACertificate(CAInfo)");
cwc = wcslen(str);
pwc = str;
if (!cuParseDecimal(&pwc, &cwc, (DWORD *) &CAInfo.CAType) ||
!cuParseDecimal(&pwc, &cwc, &CAInfo.cCASignatureCerts))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "cuParseDecimal");
}
*pcCACerts = CAInfo.cCASignatureCerts;
error:
if (NULL != str)
{
SysFreeString(str);
}
return(hr);
}
HRESULT
GetCRLState(
IN DISPATCHINTERFACE *pdiRequest,
IN DWORD iCRL,
OUT DWORD *pState)
{
HRESULT hr;
BSTR str = NULL;
DWORD cwc;
WCHAR const *pwc;
hr = Request_GetCACertificate(
pdiRequest,
GETCERT_CRLSTATEBYINDEX | iCRL, // fExchangeCertificate
g_pwszConfig,
CR_OUT_BINARY,
&str);
_JumpIfError(hr, error, "Request_GetCACertificate");
cwc = wcslen(str);
pwc = str;
if (!cuParseDecimal(&pwc, &cwc, pState))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "cuParseDecimal");
}
error:
if (NULL != str)
{
SysFreeString(str);
}
return(hr);
}
HRESULT
DSCRLSub(
IN BOOL fDeltaCRL,
OPTIONAL IN WCHAR const *pwszCRLIndex,
OPTIONAL IN WCHAR const *pwszfnOut)
{
HRESULT hr;
DWORD iCRL = MAXDWORD;
DISPATCHINTERFACE diRequest;
BOOL fMustRelease = FALSE;
WCHAR const *pwszDN = NULL;
if (NULL != pwszCRLIndex)
{
hr = cuGetLong(pwszCRLIndex, (LONG *) &iCRL);
if (S_OK != hr)
{
if (NULL != pwszfnOut)
{
_JumpError(hr, error, "CRLIndex must be a number");
}
pwszDN = pwszCRLIndex;
iCRL = MAXDWORD;
}
}
if (NULL == pwszDN)
{
hr = cuSetConfig();
_JumpIfError(hr, error, "cuSetConfig");
}
if (MAXDWORD == iCRL && NULL == pwszDN)
{
DWORD cCACerts;
DWORD State;
hr = Request_Init(g_DispatchFlags, &diRequest);
_JumpIfError(hr, error, "Request_Init");
fMustRelease = TRUE;
hr = GetCACertCount(&diRequest, &cCACerts);
_JumpIfError(hr, error, "GetCACertCount");
for (iCRL = 0; iCRL < cCACerts; iCRL++)
{
hr = GetCRLState(&diRequest, iCRL, &State);
_JumpIfError(hr, error, "GetCRLState");
if (CA_DISP_VALID != State)
{
//wprintf(L"Skipping CRL.%u\n", iCRL);
continue;
}
hr = DumpDSStore(NULL, TRUE, fDeltaCRL, MAXDWORD, iCRL, NULL);
_JumpIfError(hr, error, "DumpDSStore");
}
}
else
{
hr = DumpDSStore(pwszDN, TRUE, fDeltaCRL, MAXDWORD, iCRL, pwszfnOut);
_JumpIfError(hr, error, "DumpDSStore");
}
error:
if (fMustRelease)
{
Request_Release(&diRequest);
}
return(hr);
}
HRESULT
verbDSCRL(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszCRLIndex,
OPTIONAL IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
hr = DSCRLSub(FALSE, pwszCRLIndex, pwszfnOut);
_JumpIfError(hr, error, "DSCRLSub");
error:
return(hr);
}
HRESULT
verbDSDeltaCRL(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszCRLIndex,
OPTIONAL IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
hr = DSCRLSub(TRUE, pwszCRLIndex, pwszfnOut);
_JumpIfError(hr, error, "DSCRLSub");
error:
return(hr);
}
#define wszCOMMA L","
#define wszCNEQUALS L"CN="
BOOL
CACNBaseNameMatch(
IN WCHAR const *pwszCNMatch,
IN WCHAR const *pwszCN)
{
HRESULT hr;
WCHAR *pwszDup = NULL;
BOOL fMatch = FALSE;
BOOL fDigit;
WCHAR *pwsz;
hr = myDupString(pwszCN, &pwszDup);
_JumpIfError(hr, error, "myDupString");
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
pwsz = &pwszDup[wcslen(pwszDup) - 1];
if (pwsz > pwszDup && wcRPAREN == *pwsz)
{
pwsz--;
fDigit = FALSE;
while (pwsz > pwszDup && iswdigit(*pwsz))
{
fDigit = TRUE;
pwsz--;
}
if (!fDigit || pwsz <= pwszDup || wcLPAREN != *pwsz)
{
_JumpError2(hr, error, "fDigit or wcLPAREN", hr);
}
*pwsz-- = L'\0'; // truncate trailing "(#)"
}
pwsz -= WSZARRAYSIZE(L"-CDP") - 1;
if (pwsz > pwszDup && 0 == lstrcmpi(pwsz, L"-CDP"))
{
*pwsz = '\0'; // truncate trailing L"-CDP"
}
if (0 != lstrcmpi(pwszCNMatch, pwszDup)) // compare base name
{
_JumpError2(hr, error, "no base name match", hr);
}
fMatch = TRUE;
error:
if (NULL != pwszDup)
{
LocalFree(pwszDup);
}
return(fMatch);
}
BOOL
CACNMatches(
OPTIONAL IN WCHAR const *pwszCNMatch,
OPTIONAL IN WCHAR const *pwszOIDCN,
IN WCHAR const *pwszRevertCN,
IN WCHAR const *pwszSanitizedCN,
OPTIONAL IN WCHAR const *pwszDisplayName,
OPTIONAL IN WCHAR const *pwszAlternateCN)
{
BOOL fMatch = TRUE;
// If no match criteria, match everything
if (NULL == pwszCNMatch)
{
goto match;
}
// Check against the Desanitized short name or Sanitized short name.
if (0 == lstrcmpi(pwszCNMatch, pwszRevertCN) ||
0 == lstrcmpi(pwszCNMatch, pwszSanitizedCN))
{
goto match;
}
// Check against the displayName
if (NULL != pwszDisplayName && 0 == lstrcmpi(pwszCNMatch, pwszDisplayName))
{
goto match;
}
// Check against the alternate CN (msPKI-Cert-Template-OID)
if (NULL != pwszAlternateCN && 0 == lstrcmpi(pwszCNMatch, pwszAlternateCN))
{
goto match;
}
// Check against the OID converted to a CN
if (NULL != pwszOIDCN &&
0 == lstrcmpi(pwszOIDCN, pwszRevertCN))
{
goto match;
}
// Check against the Desanitized short name or Sanitized short name,
// stripped of the key index and CDP tags.
if (CACNBaseNameMatch(pwszCNMatch, pwszRevertCN) ||
CACNBaseNameMatch(pwszCNMatch, pwszSanitizedCN))
{
goto match;
}
fMatch = FALSE; // can't say we didn't try...
match:
return(fMatch);
}
HRESULT
BuildDN(
IN WCHAR const *pwszRDN,
IN WCHAR const *pwszContainer,
IN BOOL fAddCNEquals,
OUT WCHAR **ppwszDN)
{
HRESULT hr;
WCHAR *pwszDN = NULL;
DWORD cwc;
*ppwszDN = NULL;
cwc = wcslen(pwszRDN) + 1 + wcslen(pwszContainer) + 1;
if (fAddCNEquals)
{
cwc += WSZARRAYSIZE(wszCNEQUALS);
}
pwszDN = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
if (NULL == pwszDN)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
*pwszDN = L'\0';
if (fAddCNEquals)
{
wcscpy(pwszDN, wszCNEQUALS);
}
wcscat(pwszDN, pwszRDN);
wcscat(pwszDN, wszCOMMA);
wcscat(pwszDN, pwszContainer);
*ppwszDN = pwszDN;
pwszDN = NULL;
hr = S_OK;
error:
if (NULL != pwszDN)
{
LocalFree(pwszDN);
}
return(hr);
}
HRESULT
DeleteDN(
IN LDAP *pld,
IN WCHAR const *pwszRDN,
IN WCHAR const *pwszContainer)
{
WCHAR *pwszDN = NULL;
HRESULT hr;
hr = BuildDN(pwszRDN, pwszContainer, TRUE, &pwszDN);
_JumpIfError(hr, error, "BuildDN");
hr = ldap_delete_s(pld, pwszDN);
if (S_OK != hr)
{
hr = myHLdapError(pld, hr, NULL);
_JumpErrorStr(hr, error, "ldap_delete_s", pwszDN);
}
error:
if (NULL != pwszDN)
{
LocalFree(pwszDN);
}
return(hr);
}
#define DSAF_STRING 0x00000001
#define DSAF_FLAGS 0x00000002
#define DSAF_BINARY 0x00000003
#define DSAF_GUID 0x00000004
#define DSAF_ASNDATE 0x00000005
#define DSAF_ASN 0x00000006
#define DSAF_FILETIME 0x00000007
#define DSAF_EXTENSION 0x00000008 // see pszObjId
typedef struct _EXTTEMPLATE
{
WCHAR const *pwszObjId; // wszOID_*
BYTE const *pbTemplate; // Template
DWORD cbTemplate; // Template length
DWORD cbAdd; // Additional encoded length
} EXTTEMPLATE;
typedef struct _DSATTR
{
WCHAR const *pwszName; // Attribute name
DWORD Flags; // DSAF_*
UINT idMsg; // IDS_FORMAT_*
EXTTEMPLATE *pExtension;
} DSATTR;
BYTE s_abTemplateKeyUsage[] = { BER_BIT_STRING, 0x00, 0x00 };
EXTTEMPLATE s_ExtKeyUsage =
{
TEXT(szOID_KEY_USAGE),
s_abTemplateKeyUsage,
sizeof(s_abTemplateKeyUsage),
1
};
DSATTR s_DSAttrBinary =
{
L"",
DSAF_BINARY,
0,
NULL,
};
DSATTR s_DSAttrString =
{
L"",
DSAF_STRING,
0,
NULL,
};
DSATTR s_aDSAttr[] =
{
{ wszDSUSERCERTATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
{ wszDSCACERTATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
{ wszDSCROSSCERTPAIRATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
{ wszDSAUTHORITYCRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
{ wszDSBASECRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
{ wszDSDELTACRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
{ CERTTYPE_PROP_CN, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_DN, DSAF_STRING, 0, NULL, },
{ L"name", DSAF_STRING, 0, NULL, },
{ L"showInAdvancedViewOnly", DSAF_STRING, 0, NULL, },
{ L"memberOf", DSAF_STRING, 0, NULL, },
{ L"operatingSystem", DSAF_STRING, 0, NULL, },
{ L"operatingSystemVersion", DSAF_STRING, 0, NULL, },
{ L"servicePrincipalName", DSAF_STRING, 0, NULL, },
{ L"sAMAccountName", DSAF_STRING, 0, NULL, },
{ L"description", DSAF_STRING, 0, NULL, },
{ L"isCriticalSystemObject", DSAF_STRING, 0, NULL, },
//{ L"uSNChanged", DSAF_STRING, 0, NULL, },
//{ L"uSNCreated", DSAF_STRING, 0, NULL, },
//{ L"instanceType", DSAF_STRING, 0, NULL, },
{ L"objectCategory", DSAF_STRING, 0, NULL, },
{ wszDSOBJECTCLASSATTRIBUTE, DSAF_STRING, 0, NULL, },
{ L"objectGUID", DSAF_GUID, 0, NULL, },
{ L"whenChanged", DSAF_ASNDATE, 0, NULL, },
{ L"whenCreated", DSAF_ASNDATE, 0, NULL, },
{ L"dSCorePropagationData", DSAF_ASNDATE, 0, NULL, },
{ CA_PROP_CERT_DN, DSAF_STRING, 0, NULL, },
{ CA_PROP_CERT_TYPES, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_FRIENDLY_NAME, DSAF_STRING, 0, NULL, },
{ CA_PROP_DNSNAME, DSAF_STRING, 0, NULL, },
{ OID_PROP_LOCALIZED_NAME, DSAF_STRING, 0, NULL, },
{ OID_PROP_CPS, DSAF_STRING, 0, NULL, },
// Template Schema Version 1 properties:
{ CERTTYPE_PROP_FLAGS, DSAF_FLAGS, 0, NULL, },
{ CERTTYPE_PROP_CSP_LIST, DSAF_STRING, 0, NULL, },
//{ CERTTYPE_PROP_DEFAULT_KEYSPEC, DSAF_STRING, 0, NULL, },
//{ CERTTYPE_PROP_EXTENDED_KEY_USAGE, DSAF_STRING, 0, NULL, },
//{ CERTTYPE_PROP_CRITICAL_EXTENSIONS, DSAF_STRING, 0, NULL, },
//{ CERTTYPE_PROP_MAX_DEPTH, DSAF_STRING, 0, NULL, },
//{ CERTTYPE_PROP_REVISION, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_EXPIRATION, DSAF_FILETIME, 0, NULL, },
{ CERTTYPE_PROP_OVERLAP, DSAF_FILETIME, 0, NULL, },
{ CERTTYPE_PROP_KU, DSAF_EXTENSION, 0, &s_ExtKeyUsage, },
// Template Schema Version 2 properties:
{ CERTTYPE_RPOP_ENROLLMENT_FLAG, DSAF_FLAGS, 0, NULL, },
{ CERTTYPE_PROP_NAME_FLAG, DSAF_FLAGS, 0, NULL, },
{ CERTTYPE_PROP_PRIVATE_KEY_FLAG, DSAF_FLAGS, 0, NULL, },
{ CERTTYPE_PROP_SCHEMA_VERSION, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_MINOR_REVISION, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_RA_SIGNATURE, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_MIN_KEY_SIZE, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_OID, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_SUPERSEDE, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_RA_POLICY, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_RA_APPLICATION_POLICY, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_POLICY, DSAF_STRING, 0, NULL, },
{ CERTTYPE_PROP_APPLICATION_POLICY, DSAF_STRING, 0, NULL, },
};
#define ISEMPTYATTR(pberval) \
(0 == (pberval)->bv_len || \
(1 == (pberval)->bv_len && 0 == *(BYTE const *) (pberval)->bv_val))
WCHAR const s_wszPad0[] = L" ";
WCHAR const s_wszPad1[] = L"\t";
#define wszPUBLICKEYSERVICESCONTAINER \
L"CN=Public Key Services," \
L"CN=Services"
WCHAR const g_wszCNAuthoritiesOld[] =
L"CN=Certification Authorities";
WCHAR const g_wszCNAuthorities[] =
L"CN=Certification Authorities,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszEnterpriseCAs[] =
//L"CN=NTAuthCertificates,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNKRA[] =
L"CN=KRA,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNEnrollment[] =
L"CN=Enrollment Services,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNAIA[] =
L"CN=AIA,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNOID[] =
L"CN=OID,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNCDP[] =
L"CN=CDP,"
wszPUBLICKEYSERVICESCONTAINER;
WCHAR const g_wszCNTemplates[] =
L"CN=Certificate Templates,"
wszPUBLICKEYSERVICESCONTAINER;
typedef struct _DSDN
{
DWORD Flags;
WCHAR const *pwszCN;
WCHAR const *pwszChild;
WCHAR const *pwszAlternateCNAttribute;
} DSDN;
#define DSDF_ADDCNEQUALS 0x00000001
#define DSDF_RECURSEONELEVEL 0x00000002
#define DSDF_DELETE 0x00000004
#define DSDF_INFDUMP 0x00000008
#define DSDF_DOMAINDN 0x00000010
#define DSDF_BASE 0x00000020
#define DSDF_CA 0x00000100
#define DSDF_TEMPLATE 0x00000200
#define DSDF_OID 0x00000400
#define DSDF_TYPEMASK 0x00000700
DSDN s_aDSDN[] =
{
{ 0, wszPUBLICKEYSERVICESCONTAINER, L"NTAuthCertificates", NULL },
{ DSDF_CA | DSDF_DOMAINDN, g_wszCNAuthoritiesOld, NULL, NULL },
{ DSDF_CA, g_wszCNAuthorities, NULL, NULL },
{ 0, g_wszCNKRA, NULL, NULL },
{ DSDF_CA, g_wszCNEnrollment, NULL, NULL },
{ DSDF_CA, g_wszCNAIA, NULL, NULL },
{ DSDF_CA | DSDF_RECURSEONELEVEL, g_wszCNCDP, NULL, NULL },
{ DSDF_OID, g_wszCNOID, NULL, OID_PROP_OID },
{ DSDF_TEMPLATE, g_wszCNTemplates, NULL, CERTTYPE_PROP_OID },
};
HRESULT
dumpDSStringAttribute(
IN LDAP *pld,
IN LDAPMessage *pres,
IN DWORD dwFlags,
IN WCHAR const *pwszAttrName,
IN DSATTR const *pdsa)
{
HRESULT hr;
WCHAR **rgpwszval = NULL;
BOOL fInfDump = 0 != (DSDF_INFDUMP & dwFlags);
rgpwszval = ldap_get_values(pld, pres, (WCHAR * const) pwszAttrName);
if (NULL != rgpwszval)
{
LONG lVal;
BOOL fValidNumber;
WCHAR const *pwszVal;
BOOL fCompact;
DWORD i;
WCHAR const *pwszSep;
fCompact = fInfDump ||
(1 >= g_fVerbose && (NULL == rgpwszval[0] || NULL == rgpwszval[1]));
if (!fCompact)
{
wprintf(L"%ws%ws\n", s_wszPad0, pwszAttrName);
}
for (i = 0; NULL != (pwszVal = rgpwszval[i]); i++)
{
pwszSep = L"";
if (fCompact)
{
if (0 == i)
{
wprintf(L"%ws%ws =", s_wszPad0, pwszAttrName);
}
else
{
pwszSep = L",";
}
}
else
{
wprintf(s_wszPad1);
wprintf(
myLoadResourceString(IDS_FORMAT_ELEMENT), // "Element %u:"
i);
}
wprintf(L"%ws \"%ws\"", pwszSep, pwszVal);
if (iswdigit(pwszVal[0]) || L'-' == pwszVal[0])
{
if (L'-' == pwszVal[0])
{
lVal = myWtoI(&pwszVal[1], &fValidNumber);
lVal = -lVal;
}
else
{
lVal = myWtoI(pwszVal, &fValidNumber);
}
if (!fInfDump || g_fVerbose)
{
if (fValidNumber)
{
if (0 > lVal || 9 < lVal)
{
wprintf(L" 0x%x", lVal);
}
if (DSAF_FLAGS == pdsa->Flags)
{
WCHAR const *pwsz;
pwsz = pdsa->pwszName;
if (0 == lstrcmpi(CERTTYPE_PROP_FLAGS, pwsz))
{
if (DSDF_CA & dwFlags)
{
pwsz = wszCUREGDSCAFLAGS;
}
else if (DSDF_TEMPLATE & dwFlags)
{
pwsz = wszCUREGDSTEMPLATEFLAGS;
}
else if (DSDF_OID & dwFlags)
{
pwsz = wszCUREGDSOIDFLAGS;
}
}
wprintf(wszNewLine);
cuRegPrintDwordValue(FALSE, pwsz, pwsz, lVal);
}
}
else
{
cuPrintPossibleObjectIdName(pwszVal);
}
}
}
if (DSAF_ASNDATE == pdsa->Flags)
{
WCHAR const *pwszT;
FILETIME ft;
DWORD cbft;
DWORD cb;
BYTE ab[MAX_PATH];
cb = 0;
ab[cb++] = BER_GENERALIZED_TIME;
ab[cb++] = (BYTE) wcslen(pwszVal);
for (pwszT = pwszVal; L'\0' != *pwszT; pwszT++)
{
ab[cb++] = (BYTE) *pwszT;
}
cbft = sizeof(FILETIME);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_CHOICE_OF_TIME,
ab,
cb,
0,
&ft,
&cbft))
{
wprintf(L"\n");
hr = myHLastError();
_PrintIfError(hr, "CryptDecodeObject");
}
else if (!fInfDump || g_fVerbose)
{
cuDumpFileTime(0, NULL, &ft);
}
}
else if (!fInfDump)
{
wprintf(L"\n");
}
if (1 < g_fVerbose)
{
DumpHex(
DH_NOADDRESS | DH_NOTABPREFIX | 12,
(BYTE const *) pwszVal,
wcslen(pwszVal) * sizeof(WCHAR));
}
}
if (fInfDump)
{
wprintf(L"\n");
}
}
hr = S_OK;
//error:
if (NULL != rgpwszval)
{
ldap_value_free(rgpwszval);
}
return(hr);
}
BOOL
isStringAttribute(
berval **rgpberval)
{
BOOL fString = FALSE;
DWORD i;
DWORD cbTotal = 0;
for (i = 0; NULL != rgpberval[i]; i++)
{
BYTE const *pb = (BYTE const *) rgpberval[i]->bv_val;
DWORD cb = rgpberval[i]->bv_len;
cbTotal += cb;
if (0 < cb && '-' == *pb)
{
pb++;
cb--;
}
while (0 < cb--)
{
if (('0' > *pb || '9' < *pb) && '.' != *pb)
{
goto error;
}
pb++;
}
}
if (0 < cbTotal)
{
fString = TRUE;
}
error:
return(fString);
}
HRESULT
dumpDSBinaryAttribute(
IN LDAP *pld,
IN LDAPMessage *pres,
IN DWORD dwFlags,
IN WCHAR const *pwszAttrName,
IN DSATTR const *pdsa)
{
HRESULT hr;
berval **rgpberval = NULL;
BOOL fNewLine = FALSE;
BOOL fInfDump = 0 != (DSDF_INFDUMP & dwFlags);
rgpberval = ldap_get_values_len(pld, pres, (WCHAR * const) pwszAttrName);
if (NULL != rgpberval)
{
BOOL fCompact;
DWORD i;
WCHAR const *pwszInfQuote = fInfDump? L"\"" : L"";
if (&s_DSAttrBinary == pdsa && isStringAttribute(rgpberval))
{
hr = dumpDSStringAttribute(
pld,
pres,
dwFlags,
pwszAttrName,
&s_DSAttrString);
_PrintIfError(hr, "dumpDSStringAttribute");
goto error;
}
fCompact = fInfDump ||
(1 >= g_fVerbose && (NULL == rgpberval[0] || NULL == rgpberval[1]));
if (!fCompact)
{
wprintf(L"%ws%ws\n", s_wszPad0, pwszAttrName);
}
for (i = 0; NULL != rgpberval[i]; i++)
{
BOOL fEmpty = ISEMPTYATTR(rgpberval[i]);
WCHAR const *pwszSep;
if (fCompact)
{
wprintf(L"%ws%ws", s_wszPad0, pwszAttrName);
pwszSep = L" = ";
}
else
{
wprintf(s_wszPad1);
wprintf(
myLoadResourceString(IDS_FORMAT_ELEMENT), // "Element %u:"
i);
wprintf(
L" %u %ws",
rgpberval[i]->bv_len,
myLoadResourceString(IDS_BYTES)); // "Bytes"
pwszSep = L" ";
}
if (fEmpty)
{
wprintf(
L"%ws%ws\n",
pwszSep,
fInfDump?
L"\"\"" :
myLoadResourceString(IDS_PROP_EMPTY)); // "EMPTY"
}
else
{
BOOL fHex = TRUE;
if (DSAF_ASN == pdsa->Flags)
{
if (!fInfDump)
{
BOOL fVerboseOld = g_fVerbose;
wprintf(wszNewLine);
CSASSERT(g_fVerbose);
g_fVerbose--;
g_fQuiet = !g_fVerbose;
if (g_fVerbose)
{
g_fVerbose--;
}
if (0 != pdsa->idMsg)
{
wprintf(
myLoadResourceString(pdsa->idMsg),
i);
wprintf(wszNewLine);
}
hr = cuDumpAsnBinary(
(BYTE const *) rgpberval[i]->bv_val,
rgpberval[i]->bv_len,
MAXDWORD);
_PrintIfError(hr, "cuDumpAsnBinary");
if (S_OK == hr)
{
fHex = FALSE;
}
g_fVerbose = fVerboseOld;
fNewLine = TRUE;
}
}
else if (DSAF_FILETIME == pdsa->Flags)
{
FILETIME ft;
if (sizeof(ft) == rgpberval[i]->bv_len)
{
wprintf(pwszSep);
CopyMemory(&ft, rgpberval[i]->bv_val, sizeof(ft));
hr = cuDumpFileTimeOrPeriod(0, pwszInfQuote, &ft);
if (S_OK == hr)
{
fHex = FALSE;
}
}
}
else if (DSAF_EXTENSION == pdsa->Flags)
{
if (!fInfDump)
{
BOOL fQuietOld = g_fQuiet;
DWORD cb;
BYTE ab[MAX_PATH];
cb = pdsa->pExtension->cbTemplate;
CopyMemory(
ab,
pdsa->pExtension->pbTemplate,
cb);
CopyMemory(
&ab[cb],
rgpberval[i]->bv_val,
rgpberval[i]->bv_len);
ab[1] = (BYTE) (pdsa->pExtension->cbAdd + rgpberval[i]->bv_len);
cb += rgpberval[i]->bv_len;
wprintf(pwszSep);
g_fQuiet = TRUE;
if (!cuDumpFormattedExtension(
pdsa->pExtension->pwszObjId,
ab,
cb))
{
hr = myHLastError();
_PrintError(hr, "cuDumpFormattedExtension");
}
else
{
fHex = FALSE;
}
g_fQuiet = fQuietOld;
wprintf(wszNewLine);
}
}
else if (DSAF_GUID == pdsa->Flags)
{
if (sizeof(GUID) == rgpberval[i]->bv_len)
{
WCHAR *pwszGUID;
hr = myCLSIDToWsz(
(GUID *) rgpberval[i]->bv_val,
&pwszGUID);
_PrintIfError(hr, "myCLSIDToWsz");
if (S_OK == hr)
{
wprintf(
L"%ws%ws%ws%ws",
pwszSep,
pwszInfQuote,
pwszGUID,
pwszInfQuote);
LocalFree(pwszGUID);
fHex = FALSE;
}
}
wprintf(wszNewLine);
}
else
{
wprintf(wszNewLine);
}
if (fHex || 1 < g_fVerbose)
{
if (fInfDump)
{
BSTR strHex = NULL;
hr = MultiByteIntegerToBstr(
TRUE,
rgpberval[i]->bv_len,
(BYTE const *) rgpberval[i]->bv_val,
&strHex);
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
wprintf(L"%ws\"%ws\"\n", pwszSep, strHex);
SysFreeString(strHex);
}
else
{
DumpHex(
DH_NOADDRESS | DH_NOTABPREFIX | 12,
(BYTE const *) rgpberval[i]->bv_val,
rgpberval[i]->bv_len);
}
}
}
}
}
if (fNewLine)
{
wprintf(wszNewLine);
}
hr = S_OK;
error:
if (NULL != rgpberval)
{
ldap_value_free_len(rgpberval);
}
return(hr);
}
HRESULT
dumpDSAttributes(
IN LDAP *pld,
IN LDAPMessage *pres,
IN DWORD dwFlags)
{
HRESULT hr;
WCHAR *pwszAttrName;
BerElement *pber = NULL;
for (pwszAttrName = ldap_first_attribute(pld, pres, &pber);
pwszAttrName != NULL;
pwszAttrName = ldap_next_attribute(pld, pres, pber))
{
DSATTR const *pdsa;
for (pdsa = s_aDSAttr; ; pdsa++)
{
if (pdsa >= &s_aDSAttr[ARRAYSIZE(s_aDSAttr)])
{
pdsa = &s_DSAttrBinary; // Unknown attribute
break;
}
if (0 == lstrcmpi(pwszAttrName, pdsa->pwszName))
{
break;
}
}
switch (pdsa->Flags)
{
case DSAF_ASNDATE:
case DSAF_STRING:
case DSAF_FLAGS:
hr = dumpDSStringAttribute(
pld,
pres,
dwFlags,
pwszAttrName,
pdsa);
_PrintIfError(hr, "dumpDSStringAttribute");
break;
case DSAF_GUID:
case DSAF_FILETIME:
case DSAF_EXTENSION:
case DSAF_BINARY:
case DSAF_ASN:
hr = dumpDSBinaryAttribute(
pld,
pres,
dwFlags,
pwszAttrName,
pdsa);
_PrintIfError(hr, "dumpDSBinaryAttribute");
break;
default:
CSASSERT(FALSE && pdsa->Flags);
break;
}
ldap_memfree(pwszAttrName);
pwszAttrName = NULL;
}
wprintf(L"\n");
hr = S_OK;
//error:
if (NULL != pber)
{
//ber_free(pber, 0);
}
return(hr);
}
HRESULT
AddCNList(
IN WCHAR const *pwszCN,
IN OUT WCHAR ***pppwsz)
{
HRESULT hr;
DWORD cpwsz = 0;
WCHAR **ppwsz = *pppwsz;
WCHAR **ppwszAlloc = NULL;
WCHAR *pwszDup = NULL;
hr = myDupString(pwszCN, &pwszDup);
_JumpIfError(hr, error, "myDupString");
if (NULL != ppwsz)
{
for ( ; NULL != ppwsz[cpwsz]; cpwsz++)
;
}
if (NULL == ppwsz)
{
ppwszAlloc = (WCHAR **) LocalAlloc(
LMEM_FIXED,
2 * sizeof(*ppwszAlloc));
}
else
{
ppwszAlloc = (WCHAR **) LocalReAlloc(
ppwsz,
(cpwsz + 2) * sizeof(*ppwszAlloc),
LMEM_MOVEABLE | LMEM_ZEROINIT);
}
if (NULL == ppwszAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(
hr,
error,
NULL == ppwsz? "LocalAlloc" : "LocalReAlloc");
}
ppwszAlloc[cpwsz] = pwszDup;
ppwszAlloc[cpwsz + 1] = NULL;
pwszDup = NULL;
*pppwsz = ppwszAlloc;
hr = S_OK;
error:
if (NULL != pwszDup)
{
LocalFree(pwszDup);
}
return(hr);
}
HRESULT
dumpDSDNs(
IN LDAP *pld,
IN DWORD dwFlags,
IN WCHAR const *pwszAlternateCNAttribute,
IN WCHAR const *pwszCNMatch,
IN WCHAR const *pwszRDN,
OPTIONAL IN WCHAR const *pwszContainer,
OPTIONAL OUT WCHAR ***pppwsz)
{
HRESULT hr;
WCHAR *pwszDNAlloc = NULL;
WCHAR const *pwszDN;
DWORD cwc;
DWORD cres;
LDAP_TIMEVAL timeval;
LDAPMessage *pmsg = NULL;
LDAPMessage *pres;
WCHAR *pwszOIDCN = NULL;
WCHAR *pwszAlternateCN = NULL;
WCHAR *pwszDisplayName = NULL;
WCHAR *pwszRevertCN = NULL;
BOOL fFirst = TRUE;
WCHAR **ppwszLdapVal = NULL;
if (NULL != pppwsz)
{
*pppwsz = NULL;
}
if (NULL == pwszContainer)
{
pwszDN = pwszRDN;
}
else
{
hr = BuildDN(
pwszRDN,
pwszContainer,
0 != (DSDF_ADDCNEQUALS & dwFlags),
&pwszDNAlloc);
_JumpIfError(hr, error, "BuildDN");
pwszDN = pwszDNAlloc;
}
if (NULL != pwszCNMatch && iswdigit(*pwszCNMatch))
{
hr = myOIDHashOIDToString(pwszCNMatch, &pwszOIDCN);
//_PrintIfError2(hr, "myOIDHashOIDToString", hr);
_PrintIfError2(hr, "myOIDHashOIDToString", E_INVALIDARG);
}
timeval.tv_sec = csecLDAPTIMEOUT;
timeval.tv_usec = 0;
hr = ldap_search_st(
pld, // ld
const_cast<WCHAR *>(pwszDN), // base
(DSDF_BASE & dwFlags)? LDAP_SCOPE_BASE : LDAP_SCOPE_ONELEVEL,
NULL, // filter
NULL, // attrs
FALSE, // attrsonly
&timeval, // timeout
&pmsg); // res
if (S_OK != hr)
{
hr = myHLdapError2(pld, hr, LDAP_NO_SUCH_OBJECT, NULL);
_JumpErrorStr2(
hr,
error,
"ldap_search_st",
pwszDN,
HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
}
cres = ldap_count_entries(pld, pmsg);
if (0 == cres)
{
// No entries were found.
goto error;
}
for (pres = ldap_first_entry(pld, pmsg);
NULL != pres;
pres = ldap_next_entry(pld, pres))
{
if (NULL != pwszDisplayName)
{
LocalFree(pwszDisplayName);
pwszDisplayName = NULL;
}
if (NULL != pwszAlternateCN)
{
LocalFree(pwszAlternateCN);
pwszAlternateCN = NULL;
}
if (NULL != pwszRevertCN)
{
LocalFree(pwszRevertCN);
pwszRevertCN = NULL;
}
CSASSERT(NULL == ppwszLdapVal);
ppwszLdapVal = ldap_get_values(pld, pres, CA_PROP_DISPLAY_NAME);
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0])
{
hr = myDupString(ppwszLdapVal[0], &pwszDisplayName);
_JumpIfError(hr, error, "myDupString");
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
CSASSERT(NULL == ppwszLdapVal);
if (NULL != pwszAlternateCNAttribute)
{
ppwszLdapVal = ldap_get_values(
pld,
pres,
const_cast<WCHAR *>(pwszAlternateCNAttribute));
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0])
{
hr = myDupString(ppwszLdapVal[0], &pwszAlternateCN);
_JumpIfError(hr, error, "myDupString");
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
}
CSASSERT(NULL == ppwszLdapVal);
ppwszLdapVal = ldap_get_values(pld, pres, CERTTYPE_PROP_CN);
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0])
{
hr = myRevertSanitizeName(ppwszLdapVal[0], &pwszRevertCN);
_JumpIfError(hr, error, "myRevertSanitizeName");
if (CACNMatches(
pwszCNMatch,
pwszOIDCN,
pwszRevertCN,
ppwszLdapVal[0],
pwszDisplayName,
pwszAlternateCN))
{
if (NULL != pppwsz)
{
hr = AddCNList(ppwszLdapVal[0], pppwsz);
_JumpIfError(hr, error, "AddCNList");
}
if (DSDF_INFDUMP & dwFlags)
{
wprintf(L"\n[%ws]\n", ppwszLdapVal[0]);
}
else
{
if (fFirst)
{
wprintf(L"%ws:\n", pwszDN);
}
wprintf(
L" %ws%ws%ws",
(DSDF_DELETE & dwFlags)?
myLoadResourceString(IDS_DELETING) : // "Deleting"
L"",
(DSDF_DELETE & dwFlags)? L" " : L"",
pwszRevertCN);
if (0 != lstrcmpi(pwszRevertCN, ppwszLdapVal[0]))
{
wprintf(L" -- %ws", ppwszLdapVal[0]);
}
wprintf(L"\n");
if (!g_fVerbose &&
NULL != pwszAlternateCN &&
0 != lstrcmpi(pwszRevertCN, pwszAlternateCN))
{
wprintf(L" %ws\n", pwszAlternateCN);
}
if (!g_fVerbose &&
NULL != pwszDisplayName &&
0 != lstrcmpi(pwszRevertCN, pwszDisplayName))
{
wprintf(L" %ws\n", pwszDisplayName);
}
}
if (DSDF_DELETE & dwFlags)
{
DeleteDN(pld, ppwszLdapVal[0], pwszDN);
}
else if (g_fVerbose || (DSDF_INFDUMP & dwFlags))
{
dumpDSAttributes(pld, pres, dwFlags);
}
fFirst = FALSE;
}
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
}
if (!fFirst)
{
wprintf(wszNewLine);
}
if (DSDF_RECURSEONELEVEL & dwFlags)
{
for (pres = ldap_first_entry(pld, pmsg);
NULL != pres;
pres = ldap_next_entry(pld, pres))
{
CSASSERT(NULL == ppwszLdapVal);
ppwszLdapVal = ldap_get_values(pld, pres, CERTTYPE_PROP_CN);
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0])
{
hr = dumpDSDNs(
pld,
DSDF_ADDCNEQUALS |
(~DSDF_RECURSEONELEVEL & dwFlags),
pwszAlternateCNAttribute,
pwszCNMatch,
ppwszLdapVal[0],
pwszDN,
NULL);
_PrintIfError(hr, "dumpDSDNs");
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
}
}
error:
if (NULL != ppwszLdapVal)
{
ldap_value_free(ppwszLdapVal);
}
if (NULL != pmsg)
{
ldap_msgfree(pmsg);
}
if (NULL != pwszOIDCN)
{
LocalFree(pwszOIDCN);
}
if (NULL != pwszDisplayName)
{
LocalFree(pwszDisplayName);
}
if (NULL != pwszAlternateCN)
{
LocalFree(pwszAlternateCN);
}
if (NULL != pwszRevertCN)
{
LocalFree(pwszRevertCN);
}
if (NULL != pwszDNAlloc)
{
LocalFree(pwszDNAlloc);
}
return(hr);
}
HRESULT
DumpOrDeleteFromDS(
OPTIONAL IN WCHAR const *pwszCN,
IN BOOL fDelete)
{
HRESULT hr;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
LDAP *pld = NULL;
DSDN *pDSDN;
BOOL fFullDN = FALSE;
WCHAR awcType[4]; // for "CN=\0"
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
if (NULL != pwszCN && ARRAYSIZE(awcType) - 1 <= wcslen(pwszCN))
{
CopyMemory(awcType, pwszCN, sizeof(awcType) - sizeof(WCHAR));
awcType[ARRAYSIZE(awcType) - 1] = L'\0';
if (0 == lstrcmpi(L"CN=", awcType))
{
dumpDSDNs(
pld,
DSDF_BASE | (fDelete? DSDF_DELETE : 0),
NULL,
NULL,
pwszCN,
NULL,
NULL);
fFullDN = TRUE;
}
}
if (!fFullDN)
{
for (pDSDN = s_aDSDN; pDSDN < &s_aDSDN[ARRAYSIZE(s_aDSDN)]; pDSDN++)
{
DWORD dwFlags = (DSDF_TYPEMASK | DSDF_RECURSEONELEVEL) & pDSDN->Flags;
if (fDelete)
{
dwFlags |= DSDF_DELETE;
}
if (NULL == pDSDN->pwszChild || !fDelete)
{
dumpDSDNs(
pld,
dwFlags,
pDSDN->pwszAlternateCNAttribute,
NULL != pwszCN? pwszCN : pDSDN->pwszChild,
pDSDN->pwszCN,
(DSDF_DOMAINDN & pDSDN->Flags)? strDomainDN : strConfigDN,
NULL);
}
}
}
error:
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
HRESULT
verbDS(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszCN,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
hr = DumpOrDeleteFromDS(pwszCN, FALSE);
_JumpIfError(hr, error, "DumpOrDeleteFromDS");
error:
return(hr);
}
HRESULT
verbDSDel(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszCN,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
CSASSERT(NULL != pwszCN);
hr = DumpOrDeleteFromDS(pwszCN, TRUE);
_JumpIfError(hr, error, "DumpOrDeleteFromDS");
error:
return(hr);
}
#define wszINFSECTION_TEMPLATELIST L"TemplateList"
#define wszINFKEY_TEMPLATE L"Template"
HRESULT
verbDSTemplate(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszTemplate,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
LDAP *pld = NULL;
WCHAR **ppwszTemplates = NULL;
WCHAR **ppwsz;
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
wprintf(
L"[Version]\n"
L"Signature = \"$Windows NT$\"\n"
L"\n");
dumpDSDNs(
pld,
DSDF_TEMPLATE | DSDF_INFDUMP,
CERTTYPE_PROP_OID,
pwszTemplate,
g_wszCNTemplates,
strConfigDN,
&ppwszTemplates);
if (NULL != ppwszTemplates)
{
wprintf(L"[%ws]\n", wszINFSECTION_TEMPLATELIST);
for (ppwsz = ppwszTemplates; NULL != *ppwsz; ppwsz++)
{
wprintf(L" %ws = \"%ws\"\n", wszINFKEY_TEMPLATE, *ppwsz);
}
}
error:
if (NULL != ppwszTemplates)
{
for (ppwsz = ppwszTemplates; NULL != *ppwsz; ppwsz++)
{
LocalFree(*ppwsz);
}
LocalFree(ppwszTemplates);
}
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
typedef struct _CTFLAGS {
DWORD dwOption;
WCHAR const *pwszLookupName;
WCHAR const *pwszPropName;
} CTFLAGS;
// The last entry has a prefix added to distinguish the name enough to display
// the correct symbolic names for its bit fields. "flags" is too generic.
CTFLAGS g_actf[] = {
{
CERTTYPE_ENROLLMENT_FLAG,
CERTTYPE_RPOP_ENROLLMENT_FLAG,
CERTTYPE_RPOP_ENROLLMENT_FLAG,
},
{
CERTTYPE_SUBJECT_NAME_FLAG,
CERTTYPE_PROP_NAME_FLAG,
CERTTYPE_PROP_NAME_FLAG,
},
{
CERTTYPE_PRIVATE_KEY_FLAG,
CERTTYPE_PROP_PRIVATE_KEY_FLAG,
CERTTYPE_PROP_PRIVATE_KEY_FLAG,
},
{
CERTTYPE_GENERAL_FLAG,
wszCUREGDSTEMPLATEFLAGS,
CERTTYPE_PROP_FLAGS,
},
};
typedef struct _CTPROP {
BOOL fString;
WCHAR const *pwszPropName;
} CTPROP;
CTPROP g_actProp[] = {
{ TRUE, CERTTYPE_PROP_CN, },
{ TRUE, CERTTYPE_PROP_DN, },
{ TRUE, CERTTYPE_PROP_FRIENDLY_NAME, },
{ TRUE, CERTTYPE_PROP_EXTENDED_KEY_USAGE, },
{ TRUE, CERTTYPE_PROP_CSP_LIST, },
{ TRUE, CERTTYPE_PROP_CRITICAL_EXTENSIONS, },
{ FALSE, CERTTYPE_PROP_REVISION, },
{ FALSE, CERTTYPE_PROP_SCHEMA_VERSION, },
{ FALSE, CERTTYPE_PROP_MINOR_REVISION, },
{ FALSE, CERTTYPE_PROP_RA_SIGNATURE, },
{ FALSE, CERTTYPE_PROP_MIN_KEY_SIZE, },
{ TRUE, CERTTYPE_PROP_OID, },
{ TRUE, CERTTYPE_PROP_SUPERSEDE, },
{ TRUE, CERTTYPE_PROP_RA_POLICY, },
{ TRUE, CERTTYPE_PROP_RA_APPLICATION_POLICY, },
{ TRUE, CERTTYPE_PROP_POLICY, },
{ TRUE, CERTTYPE_PROP_APPLICATION_POLICY, },
};
# if 0
BYTE ab0[sizeof(FILETIME)] =
{ 0x00, 0x80, 0x37, 0xae, 0xff, 0xf4, 0xff, 0xff }; // 2 Weeks
BYTE ab1[sizeof(FILETIME)] =
{ 0x00, 0x40, 0x39, 0x87, 0x2e, 0xe1, 0xfe, 0xff }; // 1 Years
BYTE ab2[sizeof(FILETIME)] =
{ 0x00, 0x80, 0x72, 0x0e, 0x5d, 0xc2, 0xfd, 0xff }; // 2 Years
BYTE ab3[sizeof(FILETIME)] =
{ 0x00, 0x40, 0x1e, 0xa4, 0xe8, 0x65, 0xfa, 0xff }; // 5 Years
void
dumpConstantValidityPeriod(
FILETIME const *pft)
{
if (1 < g_fVerbose)
{
wprintf(wszNewLine);
cuDumpFileTimeOrPeriod(0, NULL, pft);
DumpHex(
DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 4,
(BYTE const *) pft,
sizeof(*pft));
wprintf(wszNewLine);
}
}
void
dumpConstantValidityPeriods()
{
dumpConstantValidityPeriod((FILETIME const *) ab0);
dumpConstantValidityPeriod((FILETIME const *) ab1);
dumpConstantValidityPeriod((FILETIME const *) ab2);
dumpConstantValidityPeriod((FILETIME const *) ab3);
}
#endif
HRESULT
dsDumpTemplateInfo(
IN HCERTTYPE hCertType)
{
HRESULT hr;
DWORD i;
DWORD j;
DWORD dwValue;
DWORD dwKeySpec;
FILETIME ftExpiration;
FILETIME ftOverlap;
CERT_EXTENSIONS *pCertExtensions;
for (i = 0; i < ARRAYSIZE(g_actf); i++)
{
hr = CAGetCertTypeFlagsEx(hCertType, g_actf[i].dwOption, &dwValue);
if (S_OK != hr)
{
_PrintError(hr, "CAGetCertTypeFlagsEx");
}
else
{
cuRegPrintDwordValue(
TRUE,
g_actf[i].pwszLookupName,
g_actf[i].pwszPropName,
dwValue);
}
}
for (i = 0; i < ARRAYSIZE(g_actProp); i++)
{
WCHAR **rgpwszPropValues;
hr = CAGetCertTypePropertyEx(
hCertType,
g_actProp[i].pwszPropName,
g_actProp[i].fString?
(VOID *) &rgpwszPropValues : &dwValue);
if (S_OK != hr)
{
_PrintError(hr, "CAGetCertTypePropertyEx");
}
else
{
if (g_actProp[i].fString)
{
cuRegPrintAwszValue(
g_actProp[i].pwszPropName,
rgpwszPropValues);
CAFreeCertTypeProperty(hCertType, rgpwszPropValues);
}
else
{
cuRegPrintDwordValue(
TRUE,
g_actProp[i].pwszPropName,
g_actProp[i].pwszPropName,
dwValue);
}
}
}
hr = CAGetCertTypeKeySpec(hCertType, &dwKeySpec);
if (S_OK != hr)
{
_PrintError(hr, "CAGetCertTypeKeySpec");
}
else
{
WCHAR const *pwsz = NULL;
switch (dwKeySpec)
{
case AT_SIGNATURE: pwsz = L"AT_SIGNATURE"; break;
case AT_KEYEXCHANGE: pwsz = L"AT_KEYEXCHANGE"; break;
}
if (NULL != pwsz)
{
wprintf(L" dwKeySpec = %ws\n", pwsz);
}
}
hr = CAGetCertTypeExpiration(hCertType, &ftExpiration, &ftOverlap);
if (S_OK != hr)
{
_PrintError(hr, "CAGetCertTypeExpiration");
}
else
{
wprintf(L" " CERTTYPE_PROP_EXPIRATION L" = ");
cuDumpFileTimeOrPeriod(0, NULL, &ftExpiration);
if (g_fVerbose)
{
DumpHex(
DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 8,
(BYTE const *) &ftExpiration,
sizeof(ftExpiration));
}
wprintf(L" " CERTTYPE_PROP_OVERLAP L" = ");
cuDumpFileTimeOrPeriod(0, NULL, &ftOverlap);
if (g_fVerbose)
{
DumpHex(
DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 8,
(BYTE const *) &ftOverlap,
sizeof(ftOverlap));
}
}
hr = CAGetCertTypeExtensions(hCertType, &pCertExtensions);
if (S_OK != hr)
{
_PrintError(hr, "CAGetCertTypeExtensions");
}
else
{
wprintf(wszNewLine);
hr = cuDumpExtensionArray(
IDS_TEMPLATE_EXTENSIONS,
pCertExtensions->cExtension,
pCertExtensions->rgExtension);
_PrintIfError(hr, "cuDumpExtensionArray");
CAFreeCertTypeExtensions(hCertType, pCertExtensions);
}
hr = S_OK;
//error:
return(hr);
}
HRESULT
dsDumpTemplate(
OPTIONAL IN HCAINFO hCAInfo,
OPTIONAL IN WCHAR const *pwszTemplate,
OPTIONAL OUT WCHAR **ppwszTemplate)
{
HRESULT hr;
BOOL fFound = FALSE;
WCHAR const *pwszDisplayName = NULL;
HCERTTYPE hCertType = NULL;
DWORD dwFlags = 0;
WCHAR **apwszCertTypeName = NULL;
WCHAR **apwszCertTypeCN = NULL;
if (NULL != ppwszTemplate)
{
*ppwszTemplate = NULL;
}
if (!g_fUserTemplates && !g_fMachineTemplates)
{
g_fUserTemplates = TRUE;
g_fMachineTemplates = TRUE;
}
if (g_fUserTemplates)
{
dwFlags |= CT_ENUM_USER_TYPES;
}
if (g_fMachineTemplates)
{
dwFlags |= CT_ENUM_MACHINE_TYPES;
}
if (!g_fUserRegistry)
{
dwFlags |= CT_FIND_LOCAL_SYSTEM;
}
if (g_fForce)
{
dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
}
if (NULL != pwszTemplate)
{
hr = CAFindCertTypeByName(pwszTemplate, hCAInfo, dwFlags, &hCertType);
if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
{
hr = CAFindCertTypeByName(
pwszTemplate,
hCAInfo,
CT_FIND_BY_OID | dwFlags,
&hCertType);
}
if (S_OK != hr)
{
_PrintErrorStr2(
hr,
"CAFindCertTypeByName",
pwszTemplate,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
pwszDisplayName = pwszTemplate;
}
else
{
fFound = TRUE;
}
}
if (NULL == pwszTemplate || NULL != pwszDisplayName)
{
if (NULL != hCAInfo)
{
hr = CAEnumCertTypesForCA(hCAInfo, dwFlags, &hCertType);
_JumpIfError(hr, error, "CAEnumCertTypesForCA");
if (NULL == hCertType)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CAEnumCertTypesForCA");
}
}
else
{
hr = CAEnumCertTypes(dwFlags, &hCertType);
_JumpIfError(hr, error, "CAEnumCertTypes");
if (NULL == hCertType)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CAEnumCertTypes");
}
}
}
while (TRUE)
{
HCERTTYPE hCertTypeNext;
WCHAR const *pwszError = NULL;
hr = CAGetCertTypeProperty(
hCertType,
CERTTYPE_PROP_FRIENDLY_NAME,
&apwszCertTypeName);
_JumpIfError(hr, error, "CAGetCertTypeProperty");
hr = CAGetCertTypeProperty(
hCertType,
CERTTYPE_PROP_CN,
&apwszCertTypeCN);
_JumpIfError(hr, error, "CAGetCertTypeProperty");
if (NULL != pwszDisplayName &&
(0 == lstrcmpi(pwszDisplayName, apwszCertTypeName[0]) ||
0 == lstrcmpi(pwszDisplayName, apwszCertTypeCN[0])))
{
fFound = TRUE;
if (NULL != ppwszTemplate)
{
hr = myDupString(apwszCertTypeCN[0], ppwszTemplate);
_JumpIfError(hr, error, "myDupString");
break;
}
}
if (NULL == ppwszTemplate && (fFound || NULL == pwszDisplayName))
{
hr = CACertTypeAccessCheck(hCertType, NULL);
if (S_OK != hr)
{
pwszError = myGetErrorMessageText(hr, FALSE);
}
wprintf(L"%ws: %ws", apwszCertTypeCN[0], apwszCertTypeName[0]);
if (NULL != pwszError)
{
wprintf(L" -- %ws", pwszError);
LocalFree(const_cast<WCHAR *>(pwszError));
}
wprintf(wszNewLine);
if (g_fVerbose)
{
BOOL fVerboseOld = g_fVerbose;
g_fVerbose--;
dsDumpTemplateInfo(hCertType);
g_fVerbose = fVerboseOld;
}
}
CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
apwszCertTypeName = NULL;
CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
apwszCertTypeCN = NULL;
if (fFound)
{
break;
}
hr = CAEnumNextCertType(hCertType, &hCertTypeNext);
_JumpIfError(hr, error, "CAEnumNextCertType");
CACloseCertType(hCertType);
hCertType = hCertTypeNext;
if (NULL == hCertType)
{
break;
}
}
hr = S_OK;
error:
if (NULL != hCertType)
{
if (NULL != apwszCertTypeName)
{
CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
}
if (NULL != apwszCertTypeCN)
{
CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
}
CACloseCertType(hCertType);
}
return(hr);
}
HRESULT
verbTemplate(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszTemplate,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
hr = dsDumpTemplate(NULL, pwszTemplate, NULL);
_JumpIfError(hr, error, "dsDumpTemplate");
error:
return(hr);
}
int
dsCompareMachineNames(
IN WCHAR const *pwszServer,
IN WCHAR const *pwszDnsName)
{
HRESULT hr;
WCHAR const *pwsz;
WCHAR *pwszMachine = NULL;
int rc;
rc = lstrcmpi(pwszServer, pwszDnsName);
if (0 != rc)
{
pwsz = wcschr(pwszDnsName, '.');
if (NULL != pwsz)
{
DWORD cb;
cb = SAFE_SUBTRACT_POINTERS(pwsz, pwszDnsName) * sizeof(WCHAR);
pwszMachine = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pwszMachine)
{
_PrintError(E_OUTOFMEMORY, "LocalAlloc");
goto error;
}
CopyMemory(pwszMachine, pwszDnsName, cb);
pwszMachine[cb / sizeof(WCHAR)] = L'\0';
rc = lstrcmpi(pwszServer, pwszMachine);
}
}
error:
if (NULL != pwszMachine)
{
LocalFree(pwszMachine);
}
return(rc);
}
// Display Templates for specified CA
HRESULT
verbCATemplates(
IN WCHAR const *pwszOption,
OPTIONAL IN WCHAR const *pwszTemplate,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszCAName = NULL;
WCHAR *pwszServer = NULL;
WCHAR *pwszCANameRevert = NULL;
WCHAR *pwszCANameSanitized = NULL;
WCHAR *pwszCANameSanitizedDS = NULL;
HCAINFO hCAInfo = NULL;
DWORD dwFlags = CA_FIND_INCLUDE_UNTRUSTED;
WCHAR **apwszMachine = NULL;
BOOL fFound = FALSE;
hr = mySplitConfigString(g_pwszConfig, &pwszServer, &pwszCAName);
_JumpIfError(hr, error, "mySplitConfigString");
hr = myRevertSanitizeName(pwszCAName, &pwszCANameRevert);
_JumpIfError(hr, error, "myRevertSanitizeName");
hr = mySanitizeName(pwszCANameRevert, &pwszCANameSanitized);
_JumpIfError(hr, error, "mySanitizeName");
hr = mySanitizedNameToDSName(pwszCANameSanitized, &pwszCANameSanitizedDS);
_JumpIfError(hr, error, "mySanitizedNameToDSName");
if (!g_fUserRegistry)
{
dwFlags |= CA_FIND_LOCAL_SYSTEM;
}
hr = CAFindByName(
pwszCANameSanitizedDS,
NULL, // wszScope
dwFlags,
&hCAInfo);
_JumpIfErrorStr(hr, error, "CAFindByName", pwszCAName);
while (TRUE)
{
HCAINFO hCAInfoNext;
hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &apwszMachine);
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DNSNAME)");
if (0 == dsCompareMachineNames(pwszServer, apwszMachine[0]))
{
fFound = TRUE;
hr = dsDumpTemplate(hCAInfo, pwszTemplate, NULL);
_JumpIfError(hr, error, "dsDumpTemplate");
}
CAFreeCAProperty(hCAInfo, apwszMachine);
apwszMachine = NULL;
hr = CAEnumNextCA(hCAInfo, &hCAInfoNext);
_JumpIfError(hr, error, "CAEnumNextCA");
CACloseCA(hCAInfo);
hCAInfo = hCAInfoNext;
if (NULL == hCAInfo)
{
break;
}
}
if (!fFound)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CAEnumNextCA");
}
hr = S_OK;
error:
if (NULL != apwszMachine)
{
CAFreeCAProperty(hCAInfo, apwszMachine);
}
if (NULL != hCAInfo)
{
CACloseCA(hCAInfo);
}
if (NULL != pwszServer)
{
LocalFree(pwszServer);
}
if (NULL != pwszCAName)
{
LocalFree(pwszCAName);
}
if (NULL != pwszCANameRevert)
{
LocalFree(pwszCANameRevert);
}
if (NULL != pwszCANameSanitized)
{
LocalFree(pwszCANameSanitized);
}
if (NULL != pwszCANameSanitizedDS)
{
LocalFree(pwszCANameSanitizedDS);
}
return(hr);
}
HRESULT
dsCAFindByCertType(
IN WCHAR const *pwszTemplate,
IN DWORD dwFlags,
OUT HCAINFO *phCAInfo)
{
HRESULT hr;
WCHAR const *pwszCertType = pwszTemplate;
WCHAR *pwszAlloc = NULL;
while (TRUE)
{
hr = CAFindByCertType(
pwszCertType,
NULL, // wszScope
dwFlags,
phCAInfo);
if (S_OK == hr)
{
if (NULL == *phCAInfo)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CAFindByCertType");
}
break;
}
_PrintErrorStr2(
hr,
"CAFindByCertType",
pwszCertType,
HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
if (NULL != pwszAlloc)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "CAFindByCertType");
}
hr = dsDumpTemplate(NULL, pwszTemplate, &pwszAlloc);
_JumpIfError(hr, error, "dsDumpTemplate");
if (NULL == pwszAlloc)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
_JumpError(hr, error, "dsDumpTemplate");
}
pwszCertType = pwszAlloc;
}
error:
if (NULL != pwszAlloc)
{
LocalFree(pwszAlloc);
}
return(hr);
}
// Display CAs for specified Template
HRESULT
verbTemplateCAs(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszTemplate,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HCAINFO hCAInfo = NULL;
DWORD dwFlags = CA_FIND_INCLUDE_UNTRUSTED;
WCHAR **apwszMachine = NULL;
WCHAR **apwszCommonName = NULL;
if (!g_fUserRegistry)
{
dwFlags |= CA_FIND_LOCAL_SYSTEM;
}
hr = dsCAFindByCertType(pwszTemplate, dwFlags, &hCAInfo);
_JumpIfError(hr, error, "dsCAFindByCertType");
while (TRUE)
{
HCAINFO hCAInfoNext;
WCHAR const *pwszError = NULL;
hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &apwszMachine);
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DNSNAME)");
hr = CAGetCAProperty(
hCAInfo,
CA_PROP_DISPLAY_NAME,
&apwszCommonName);
_JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DISPLAY_NAME)");
hr = CAAccessCheck(hCAInfo, NULL);
if (S_OK != hr)
{
pwszError = myGetErrorMessageText(hr, FALSE);
}
wprintf(L"%ws\\%ws", apwszMachine[0], apwszCommonName[0]);
if (NULL != pwszError)
{
wprintf(L" -- %ws", pwszError);
LocalFree(const_cast<WCHAR *>(pwszError));
}
wprintf(wszNewLine);
CAFreeCAProperty(hCAInfo, apwszMachine);
apwszMachine = NULL;
CAFreeCAProperty(hCAInfo, apwszCommonName);
apwszCommonName = NULL;
hr = CAEnumNextCA(hCAInfo, &hCAInfoNext);
_JumpIfError(hr, error, "CAEnumNextCA");
CACloseCA(hCAInfo);
hCAInfo = hCAInfoNext;
if (NULL == hCAInfo)
{
break;
}
}
hr = S_OK;
error:
if (NULL != apwszMachine)
{
CAFreeCAProperty(hCAInfo, apwszMachine);
}
if (NULL != apwszCommonName)
{
CAFreeCAProperty(hCAInfo, apwszCommonName);
}
if (NULL != hCAInfo)
{
CACloseCA(hCAInfo);
}
return(hr);
}
typedef struct _MODTYPE
{
WCHAR const *pwszAttributeName;
DWORD dwType;
} MODTYPE;
#define MT_STRING 0
#define MT_IGNORE 1
#define MT_TIMEPERIOD 2
#define MT_BINARY 3
const MODTYPE s_amtTemplateAttributes[] =
{
{ CERTTYPE_PROP_CN, MT_IGNORE },
{ L"instanceType", MT_IGNORE },
{ CERTTYPE_PROP_DN, MT_IGNORE },
{ L"objectCategory", MT_IGNORE },
{ L"objectGUID", MT_IGNORE },
{ L"name", MT_IGNORE },
{ L"showInAdvancedViewOnly",MT_IGNORE },
{ L"uSNChanged", MT_IGNORE },
{ L"uSNCreated", MT_IGNORE },
{ L"whenChanged", MT_IGNORE },
{ L"whenCreated", MT_IGNORE },
{ L"dSCorePropagationData", MT_IGNORE },
{ CERTTYPE_PROP_EXPIRATION, MT_TIMEPERIOD },
{ CERTTYPE_PROP_OVERLAP, MT_TIMEPERIOD },
{ CERTTYPE_PROP_KU, MT_BINARY },
{ NULL, MT_STRING }
};
DWORD
ModType(
IN WCHAR const *pwszName)
{
MODTYPE const *pmt;
for (pmt = s_amtTemplateAttributes; NULL != pmt->pwszAttributeName; pmt++)
{
if (0 == lstrcmpi(pwszName, pmt->pwszAttributeName))
{
break;
}
}
return(pmt->dwType);
}
HRESULT
ConvertBinaryValue(
IN WCHAR const *pwszValue,
OUT BERVAL **ppber)
{
HRESULT hr;
BYTE *pb = NULL;
DWORD cb;
hr = WszToMultiByteInteger(TRUE, pwszValue, &cb, &pb);
_JumpIfError(hr, error, "WszToMultiByteInteger");
*ppber = (BERVAL *) LocalAlloc(LMEM_FIXED, sizeof(**ppber));
if (NULL == *ppber)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
(*ppber)->bv_len = cb;
(*ppber)->bv_val = (char *) pb;
pb = NULL;
error:
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
ParseTimePeriod(
IN WCHAR const *pwszValue,
OUT LONGLONG *pll)
{
HRESULT hr;
WCHAR *pwszDup = NULL;
WCHAR *pwszCount;
WCHAR *pwszNext;
LONGLONG ll;
DWORD lHours;
DWORD lMinutes;
DWORD lSeconds;
ll = 0;
hr = myDupString(pwszValue, &pwszDup);
_JumpIfError(hr, error, "myDupString");
pwszCount = pwszDup;
while (TRUE)
{
BOOL fValid;
WCHAR *pwszString;
DWORD dwCount;
enum ENUM_PERIOD enumPeriod;
LONG lCount;
while (L' ' == *pwszCount)
{
pwszCount++;
}
pwszNext = wcschr(pwszCount, L',');
if (NULL == pwszNext)
{
if (L'\0' == *pwszCount || NULL != wcschr(pwszCount, L':'))
{
break;
}
pwszNext = &pwszCount[wcslen(pwszCount)];
pwszString = pwszNext;
}
else
{
pwszString = pwszNext;
*pwszNext++ = L'\0';
}
while (pwszString > pwszCount && L' ' == *--pwszString)
{
*pwszString = L'\0';
}
pwszString = wcschr(pwszCount, L' ');
if (NULL == pwszString)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpErrorStr(hr, error, "bad time period", pwszCount);
}
*pwszString++ = L'\0';
while (L' ' == *pwszString)
{
pwszString++;
}
//wprintf(L"Period: '%ws' '%ws'\n", pwszCount, pwszString);
dwCount = myWtoI(pwszCount, &fValid);
if (!fValid)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "bad time period digit");
}
hr = myTranslatePeriodUnits(pwszString, dwCount, &enumPeriod, &lCount);
_JumpIfError(hr, error, "myTranslatePeriodUnits");
if (0 != dwCount)
{
if (ENUM_PERIOD_YEARS == enumPeriod)
{
// "Years" is implemented without considering leap years.
ll += (LONGLONG) (lCount * 365 * CVT_DAYS) * CVT_BASE;
}
else if (ENUM_PERIOD_MONTHS == enumPeriod)
{
// "Months" is implemented assuming 30 days per month
ll += (LONGLONG) (lCount * 30 * CVT_DAYS) * CVT_BASE;
}
else if (ENUM_PERIOD_WEEKS == enumPeriod)
{
// "Months" is implemented assuming 7 days per week
ll += (LONGLONG) (lCount * 7 * CVT_DAYS) * CVT_BASE;
}
else
{
myMakeExprDateTime((FILETIME *) &ll, lCount, enumPeriod);
}
}
pwszCount = pwszNext;
}
if (3 == swscanf(pwszCount, L"%u:%02u:%02u", &lHours, &lMinutes, &lSeconds))
{
if (0 != lHours)
{
myMakeExprDateTime((FILETIME *) &ll, lHours, ENUM_PERIOD_HOURS);
}
if (0 != lMinutes)
{
myMakeExprDateTime((FILETIME *) &ll, lMinutes, ENUM_PERIOD_MINUTES);
}
if (0 != lSeconds)
{
myMakeExprDateTime((FILETIME *) &ll, lSeconds, ENUM_PERIOD_SECONDS);
}
}
*pll = -ll;
hr = S_OK;
error:
if (NULL != pwszDup)
{
LocalFree(pwszDup);
}
return(hr);
}
HRESULT
ConvertTimePeriodValue(
IN WCHAR const *pwszValue,
OUT BERVAL **ppber)
{
HRESULT hr;
LONGLONG ll;
BYTE *pb = NULL;
hr = ParseTimePeriod(pwszValue, &ll);
_JumpIfError(hr, error, "ParseTimePeriod");
pb = (BYTE *) LocalAlloc(LMEM_FIXED, sizeof(ll));
if (NULL == pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(pb, &ll, sizeof(ll));
*ppber = (BERVAL *) LocalAlloc(LMEM_FIXED, sizeof(**ppber));
if (NULL == *ppber)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
(*ppber)->bv_len = sizeof(ll);
(*ppber)->bv_val = (char *) pb;
pb = NULL;
error:
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
VOID
FreeMods(
IN DWORD cmod,
LDAPMod *rgmod)
{
DWORD imod;
DWORD ival;
if (NULL != rgmod)
{
for (imod = 0; imod < cmod; imod++)
{
if (LDAP_MOD_BVALUES & rgmod[imod].mod_op)
{
BERVAL **rgpber = rgmod[imod].mod_bvalues;
if (NULL != rgpber)
{
for (ival = 0; NULL != rgpber[ival]; ival++)
{
if (rgpber[ival]->bv_val)
{
LocalFree(rgpber[ival]->bv_val);
}
LocalFree(rgpber[ival]);
}
LocalFree(rgpber);
}
}
else
{
WCHAR **rgpwsz = rgmod[imod].mod_values;
if (NULL != rgpwsz)
{
for (ival = 0; NULL != rgpwsz[ival]; ival++)
{
LocalFree(rgpwsz[ival]);
}
LocalFree(rgpwsz);
}
}
}
LocalFree(rgmod);
}
}
HRESULT
ConvertInfValuesToMods(
IN DWORD cInfValues,
INFVALUES const *rgInfValues,
OUT WCHAR **ppwszCN,
OUT DWORD *pcmod,
OUT LDAPMod **prgmod)
{
HRESULT hr;
LDAPMod *rgmod = NULL;
DWORD cmod = 0;
DWORD imod;
DWORD i;
WCHAR *pwszCN = NULL;
*ppwszCN = NULL;
*prgmod = NULL;
for (i = 0; i < cInfValues; i++)
{
if (MT_IGNORE != ModType(rgInfValues[i].pwszKey))
{
cmod++;
}
}
rgmod = (LDAPMod *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cmod * sizeof(rgmod[0]));
if (NULL == rgmod)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
imod = 0;
for (i = 0; i < cInfValues; i++)
{
INFVALUES const *pInfValues = &rgInfValues[i];
DWORD dwType = ModType(pInfValues->pwszKey);
WCHAR **ppwsz = NULL;
BERVAL **ppber = NULL;
DWORD ival;
if (NULL != ppwszCN &&
NULL == pwszCN &&
0 == lstrcmpi(CERTTYPE_PROP_CN, pInfValues->pwszKey))
{
hr = myDupString(pInfValues->rgpwszValues[0], &pwszCN);
_JumpIfError(hr, error, "myDupString");
}
if (MT_IGNORE != dwType)
{
rgmod[imod].mod_op = LDAP_MOD_REPLACE;
rgmod[imod].mod_type = pInfValues->pwszKey;
if (MT_STRING == dwType)
{
ppwsz = (WCHAR **) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
(pInfValues->cValues + 1) * sizeof(ppwsz[0]));
if (NULL == ppwsz)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
rgmod[imod].mod_values = ppwsz;
}
else
{
ppber = (BERVAL **) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
(pInfValues->cValues + 1) * sizeof(ppber[0]));
if (NULL == ppber)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
rgmod[imod].mod_op |= LDAP_MOD_BVALUES;
rgmod[imod].mod_bvalues = ppber;
}
for (ival = pInfValues->cValues; ival > 0; ival--)
{
WCHAR const *pwszValue = pInfValues->rgpwszValues[ival - 1];
switch (dwType)
{
case MT_BINARY:
hr = ConvertBinaryValue(pwszValue, ppber);
_JumpIfErrorStr(
hr,
error,
"ConvertBinaryValue",
pInfValues->pwszKey);
ppber++;
CSASSERT(NULL == *ppber);
break;
case MT_TIMEPERIOD:
hr = ConvertTimePeriodValue(pwszValue, ppber);
_JumpIfErrorStr(
hr,
error,
"ConvertTimePeriodValue",
pInfValues->pwszKey);
ppber++;
CSASSERT(NULL == *ppber);
break;
default:
CSASSERT(MT_STRING == dwType);
hr = myDupString(pwszValue, ppwsz);
_JumpIfErrorStr(
hr,
error,
"myDupString",
pInfValues->pwszKey);
ppwsz++;
CSASSERT(NULL == *ppwsz);
break;
}
}
imod++;
}
}
CSASSERT(imod == cmod);
*pcmod = cmod;
*prgmod = rgmod;
rgmod = NULL;
if (NULL != ppwszCN)
{
*ppwszCN = pwszCN;
pwszCN = NULL;
}
hr = S_OK;
error:
if (NULL != pwszCN)
{
LocalFree(pwszCN);
}
if (NULL != rgmod)
{
FreeMods(cmod, rgmod);
}
return(hr);
}
HRESULT
dsAddTemplate(
IN HINF hInf,
IN WCHAR const *pwszTemplate,
IN OUT BSTR *pstrConfigDN,
IN OUT LDAP **ppld)
{
HRESULT hr;
ULONG ldaperr;
DWORD cInfValues;
INFVALUES *rgInfValues = NULL;
DWORD cmod;
LDAPMod *rgmod = NULL;
LDAPMod **rgpmod = NULL;
DWORD imod;
DWORD ival;
WCHAR *pwszDNContainer = NULL;
WCHAR *pwszDNTemplate = NULL;
WCHAR *pwszCNAlloc = NULL;
WCHAR const *pwszCN;
UINT idmsg;
WCHAR *pwszError = NULL;
hr = myInfGetSectionValues(
hInf,
pwszTemplate,
&cInfValues,
&rgInfValues);
_JumpIfError(hr, error, "myInfGetSectionValues");
hr = ConvertInfValuesToMods(
cInfValues,
rgInfValues,
&pwszCNAlloc,
&cmod,
&rgmod);
_JumpIfError(hr, error, "ConvertInfValuesToMods");
rgpmod = (LDAPMod **) LocalAlloc(
LMEM_FIXED,
(cmod + 3) * sizeof(rgpmod[0]));
if (NULL == rgpmod)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
for (imod = 0; imod < cmod; imod++)
{
rgpmod[imod] = &rgmod[imod];
}
rgpmod[imod] = NULL;
pwszCN = pwszCNAlloc;
if (NULL == pwszCN)
{
pwszCN = pwszTemplate;
}
if (g_fVerbose)
{
for (imod = 0; NULL != rgpmod[imod]; imod++)
{
WCHAR const *pwszSep = L"";
wprintf(L"%ws =", rgpmod[imod]->mod_type);
if (LDAP_MOD_BVALUES & rgmod[imod].mod_op)
{
BERVAL **ppber = rgpmod[imod]->mod_bvalues;
wprintf(wszNewLine);
for (ival = 0; NULL != ppber[ival]; ival++)
{
DumpHex(
DH_NOADDRESS | DH_NOTABPREFIX | 8,
(BYTE const *) ppber[ival]->bv_val,
ppber[ival]->bv_len);
wprintf(wszNewLine);
}
}
else
{
WCHAR **ppwsz = rgpmod[imod]->mod_values;
for (ival = 0; NULL != ppwsz[ival]; ival++)
{
wprintf(L"%ws \"%ws\"", pwszSep, ppwsz[ival]);
pwszSep = L",";
}
wprintf(wszNewLine);
}
if (1 < ival)
{
wprintf(wszNewLine);
}
}
}
if (NULL == *pstrConfigDN)
{
hr = myLdapOpen(ppld, NULL, pstrConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
}
CSASSERT(NULL != *pstrConfigDN);
CSASSERT(NULL != *ppld);
hr = BuildDN(g_wszCNTemplates, *pstrConfigDN, FALSE, &pwszDNContainer);
_JumpIfError(hr, error, "BuildDN");
hr = BuildDN(pwszCN, pwszDNContainer, TRUE, &pwszDNTemplate);
_JumpIfError(hr, error, "BuildDN");
DBGPRINT((DBG_SS_CERTUTILI, "Template DN: %ws\n", pwszDNTemplate));
idmsg = IDS_CREATED_TEMPLATE; // "Created DS Template"
ldaperr = ldap_add_ext_s(*ppld, pwszDNTemplate, rgpmod, NULL, NULL);
hr = myHLdapError3(
*ppld,
ldaperr,
LDAP_ALREADY_EXISTS,
LDAP_OBJECT_CLASS_VIOLATION,
&pwszError);
_PrintIfErrorStr(hr, "ldap_add_ext_s", pwszCN);
if (LDAP_ALREADY_EXISTS == ldaperr ||
LDAP_OBJECT_CLASS_VIOLATION == ldaperr)
{
if (NULL != pwszError)
{
LocalFree(pwszError);
pwszError = NULL;
}
for (imod = 0; NULL != rgpmod[imod]; imod++)
{
rgmod[imod].mod_op =
LDAP_MOD_REPLACE | (LDAP_MOD_BVALUES & rgmod[imod].mod_op);
}
idmsg = IDS_UPDATED_TEMPLATE; // "Updated DS Template"
ldaperr = ldap_modify_ext_s(*ppld, pwszDNTemplate, rgpmod, NULL, NULL);
if (LDAP_ATTRIBUTE_OR_VALUE_EXISTS == ldaperr)
{
ldaperr = LDAP_SUCCESS;
}
hr = myHLdapError(*ppld, ldaperr, &pwszError);
_PrintIfErrorStr(hr, "ldap_modify_ext_s", pwszCN);
}
_JumpIfErrorStr(hr, error, "Add/Update", pwszCN);
wprintf(L"%ws: %ws\n", myLoadResourceString(idmsg), pwszCN);
if (NULL != pwszError)
{
wprintf(L"%ws\n", pwszError);
}
hr = S_OK;
error:
if (NULL != pwszError)
{
LocalFree(pwszError);
}
if (NULL != pwszCNAlloc)
{
LocalFree(pwszCNAlloc);
}
if (NULL != pwszDNContainer)
{
LocalFree(pwszDNContainer);
}
if (NULL != pwszDNTemplate)
{
LocalFree(pwszDNTemplate);
}
if (NULL != rgpmod)
{
LocalFree(rgpmod);
}
if (NULL != rgmod)
{
FreeMods(cmod, rgmod);
}
if (NULL != rgInfValues)
{
myInfFreeSectionValues(cInfValues, rgInfValues);
}
return(hr);
}
HRESULT
verbDSAddTemplate(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfnTemplateInf,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HINF hInf = INVALID_HANDLE_VALUE;
DWORD ErrorLine;
BOOL fCritical;
WCHAR *pwszzTemplateList = NULL;
WCHAR const *pwsz;
BSTR strConfigDN = NULL;
LDAP *pld = NULL;
hr = myInfOpenFile(pwszfnTemplateInf, &hInf, &ErrorLine);
_JumpIfError(hr, error, "myInfOpenFIle");
hr = myInfGetKeyList(
hInf,
wszINFSECTION_TEMPLATELIST,
wszINFKEY_TEMPLATE,
&fCritical,
&pwszzTemplateList);
_JumpIfErrorStr(hr, error, "myInfGetKeyList", wszINFSECTION_TEMPLATELIST);
for (pwsz = pwszzTemplateList; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
wprintf(L"[%ws]\n", pwsz);
hr = dsAddTemplate(hInf, pwsz, &strConfigDN, &pld);
_JumpIfError(hr, error, "dsAddTemplate");
}
error:
if (NULL != pwszzTemplateList)
{
LocalFree(pwszzTemplateList);
}
if (INVALID_HANDLE_VALUE != hInf)
{
myInfCloseFile(hInf);
}
myLdapClose(pld, NULL, strConfigDN);
return(hr);
}
HRESULT
dsGetCommonName(
IN CERT_NAME_BLOB const *pNameBlob,
IN BOOL fAllowDefault,
OUT WCHAR **ppwszCN)
{
HRESULT hr;
CERT_NAME_INFO *pNameInfo = NULL;
DWORD cbNameInfo;
CERT_RDN *prdn;
CERT_RDN *prdnEnd;
WCHAR const *pwszCN = NULL;
*ppwszCN = NULL;
if (!myDecodeName(
X509_ASN_ENCODING,
X509_UNICODE_NAME,
pNameBlob->pbData,
pNameBlob->cbData,
CERTLIB_USE_LOCALALLOC,
&pNameInfo,
&cbNameInfo))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeName");
}
for (
prdn = pNameInfo->rgRDN, prdnEnd = &prdn[pNameInfo->cRDN];
NULL == pwszCN && prdn < prdnEnd;
prdn++)
{
CERT_RDN_ATTR *prdna;
CERT_RDN_ATTR *prdnaEnd;
for (
prdna = prdn->rgRDNAttr, prdnaEnd = &prdna[prdn->cRDNAttr];
prdna < prdnaEnd;
prdna++)
{
CSASSERT(
prdna->dwValueType == CERT_RDN_PRINTABLE_STRING ||
prdna->dwValueType == CERT_RDN_UNICODE_STRING ||
prdna->dwValueType == CERT_RDN_TELETEX_STRING ||
prdna->dwValueType == CERT_RDN_IA5_STRING ||
prdna->dwValueType == CERT_RDN_UTF8_STRING);
if (0 != strcmp(szOID_COMMON_NAME, prdna->pszObjId) ||
NULL == prdna->Value.pbData ||
sizeof(WCHAR) > prdna->Value.cbData ||
L'\0' == *(WCHAR *) prdna->Value.pbData)
{
continue;
}
pwszCN = (WCHAR const *) prdna->Value.pbData;
break;
}
}
if (NULL == pwszCN)
{
if (!fAllowDefault)
{
hr = CERTSRV_E_BAD_REQUESTSUBJECT;
_JumpError(hr, error, "No CN");
}
pwszCN = L"Default"; // default CN
}
hr = myDupString(pwszCN, ppwszCN);
_JumpIfError(hr, error, "myDupString");
error:
if (NULL != pNameInfo)
{
LocalFree(pNameInfo);
}
return(hr);
}
#define DSP_OBJECT_NTAUTHCERT 0x00000001
#define DSP_OBJECT_ROOTTRUST 0x00000002
#define DSP_OBJECT_AIA 0x00000004
#define DSP_OBJECT_KRA 0x00000008
#define DSP_OBJECT_MASK 0x000000ff
#define DSP_ATTRIBUTE_CACERTIFICATE 0x00000100
#define DSP_ATTRIBUTE_USERCERTIFICATE 0x00000200
#define DSP_ATTRIBUTE_CROSSCERTPAIR 0x00000400
#define DSP_ATTRIBUTE_MASK 0x0000ff00
#define DSP_TYPE_KRACERT 0x00010000
#define DSP_TYPE_EECERT 0x00020000
#define DSP_TYPE_ROOTCACERT 0x00040000
#define DSP_TYPE_SUBCACERT 0x00080000
#define DSP_TYPE_MASK 0x00ff0000
typedef struct _DSOBJECTMAP {
DWORD ObjectFlags;
WCHAR const *pwszTemplate;
} DSOBJECTMAP;
DSOBJECTMAP s_rgObjectMap[] = {
{ DSP_OBJECT_NTAUTHCERT, g_wszLDAPNTAuthURLTemplate },
{ DSP_OBJECT_ROOTTRUST, g_wszLDAPRootTrustURLTemplate },
{ DSP_OBJECT_AIA, g_wszzLDAPIssuerCertURLTemplate },
{ DSP_OBJECT_KRA, g_wszzLDAPKRACertURLTemplate },
};
HRESULT
dsPublishCert(
IN CERT_CONTEXT const *pccPublish,
IN WCHAR const *pwszSanitizedCN,
IN DWORD dspFlags,
IN DWORD dwObjectType)
{
HRESULT hr;
WCHAR const *pwszAttribute;
WCHAR *pwszServerName = NULL; // Shouldn't be necessary
WCHAR *pwszURL = NULL;
LDAP *pld = NULL;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
DWORD dwDisposition;
DWORD i;
WCHAR *pwszError = NULL;
hr = myGetMachineDnsName(&pwszServerName);
_JumpIfError(hr, error, "myGetMachineDnsName");
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
switch (DSP_ATTRIBUTE_MASK & dspFlags)
{
case DSP_ATTRIBUTE_CACERTIFICATE:
pwszAttribute = wszDSCACERTATTRIBUTE;
break;
case DSP_ATTRIBUTE_USERCERTIFICATE:
pwszAttribute = wszDSUSERCERTATTRIBUTE;
break;
case DSP_ATTRIBUTE_CROSSCERTPAIR:
pwszAttribute = wszDSCROSSCERTPAIRATTRIBUTE;
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "bad attribute indicator");
}
for (i = 0; i < ARRAYSIZE(s_rgObjectMap); i++)
{
WCHAR const *pwszTemplate;
if (0 == (s_rgObjectMap[i].ObjectFlags & DSP_OBJECT_MASK & dspFlags))
{
continue;
}
pwszTemplate = s_rgObjectMap[i].pwszTemplate;
hr = myFormatCertsrvStringArray(
FALSE, // fURL
pwszServerName, // pwszServerName_p1_2
pwszSanitizedCN,// pwszSanitizedName_p3_7
0, // iCert_p4
strDomainDN, // pwszDomainDN_p5
strConfigDN, // pwszConfigDN_p6
0, // iCRL_p8
FALSE, // fDeltaCRL_p9
FALSE, // fDSAttrib_p10_11
1, // cStrings
&pwszTemplate, // apwszStringsIn
&pwszURL); // apwszStringsOut
_JumpIfError(hr, error, "myFormatCertsrvStringArray");
wprintf(L"%ws?%ws\n\n", pwszURL, pwszAttribute);
if (g_fForce)
{
dwObjectType |= LPC_CREATECONTAINER | LPC_CREATEOBJECT;
}
hr = myLdapPublishCertToDS(
pld,
pccPublish,
pwszURL,
pwszAttribute,
dwObjectType,
&dwDisposition,
&pwszError);
_JumpIfError(hr, error, "myLdapPublishCertToDS");
if (LDAP_SUCCESS == dwDisposition)
{
wprintf(
myLoadResourceString(IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
myLoadResourceString(IDS_CERTIFICATE)); // "Certificate"
}
else
{
CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
wprintf(
myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
myLoadResourceString(IDS_CERTIFICATE)); // "Certificate"
}
wprintf(wszNewLine);
wprintf(wszNewLine);
LocalFree(pwszURL);
pwszURL = NULL;
}
hr = S_OK;
error:
if (NULL != pwszError)
{
wprintf(L"%ws\n", pwszError);
LocalFree(pwszError);
}
if (NULL != pwszServerName)
{
LocalFree(pwszServerName);
}
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
HRESULT
dsPublishCRL(
OPTIONAL IN LDAP *pld,
IN CRL_CONTEXT const *pCRLPublish,
IN BOOL fDelta,
IN WCHAR const *pwszURL)
{
HRESULT hr;
WCHAR const *pwszAttribute;
LDAP *pldT = NULL;
DWORD dwDisposition;
UINT idMsg = fDelta? IDS_PROP_DELTACRL : IDS_PROP_BASECRL;
WCHAR *pwszError = NULL;
pwszAttribute = fDelta? wszDSDELTACRLATTRIBUTE : wszDSBASECRLATTRIBUTE;
wprintf(L"%ws?%ws\n\n", pwszURL, pwszAttribute);
if (NULL == pld)
{
hr = myLdapOpen(&pldT, NULL, NULL);
_JumpIfError(hr, error, "myLdapOpen");
pld = pldT;
}
hr = myLdapPublishCRLToDS(
pld,
pCRLPublish,
pwszURL,
pwszAttribute,
&dwDisposition,
&pwszError);
_JumpIfError(hr, error, "myLdapPublishCRLToDS");
if (LDAP_SUCCESS == dwDisposition)
{
wprintf(
myLoadResourceString(IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
myLoadResourceString(idMsg));
}
else
{
CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
wprintf(
myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
myLoadResourceString(idMsg));
}
wprintf(wszNewLine);
wprintf(wszNewLine);
hr = S_OK;
error:
if (NULL != pwszError)
{
wprintf(L"%ws\n", pwszError);
LocalFree(pwszError);
}
myLdapClose(pldT, NULL, NULL);
return(hr);
}
HRESULT
IsCrossCACert(
IN CERT_CONTEXT const *pCertContext,
OUT BOOL *pfCrossCA)
{
HRESULT hr;
WCHAR *pwszObjId = NULL;
HCERTTYPE hCertType = NULL;
DWORD dwValue;
*pfCrossCA = FALSE;
// CrossCA is a V2 template, so only fetch the template OID
hr = cuGetCertType(
pCertContext->pCertInfo,
NULL, // ppwszCertTypeNameV1
NULL, // ppwszDisplayNameV1
&pwszObjId, // ppwszCertTypeObjId
NULL, // ppwszCertTypeName
NULL); // ppwszDisplayName
if (S_OK != hr || NULL == pwszObjId)
{
_PrintIfError2(hr, "cuGetCertType", CRYPT_E_NOT_FOUND);
if (CRYPT_E_NOT_FOUND == hr)
{
hr = S_OK;
}
goto error;
}
hr = CAFindCertTypeByName(pwszObjId, NULL, CT_FIND_BY_OID, &hCertType);
if (S_OK != hr)
{
_PrintErrorStr2(hr, "CAFindCertTypeByName", pwszObjId, hr);
if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
{
_JumpErrorStr(hr, error, "CAFindCertTypeByName", pwszObjId);
}
}
else
{
hr = CAGetCertTypeFlagsEx(hCertType, CERTTYPE_GENERAL_FLAG, &dwValue);
_JumpIfError(hr, error, "CAGetCertTypeFlagsEx");
if (CT_FLAG_IS_CROSS_CA & dwValue)
{
*pfCrossCA = TRUE;
}
}
hr = S_OK;
error:
if (NULL != hCertType)
{
CACloseCertType(hCertType);
}
if (NULL != pwszObjId)
{
LocalFree(pwszObjId);
}
return(hr);
}
HRESULT
IsCACert(
IN CERT_CONTEXT const *pCertContext,
OUT BOOL *pfCA)
{
HRESULT hr;
CERT_EXTENSION *pExt;
*pfCA = FALSE;
pExt = CertFindExtension(
szOID_BASIC_CONSTRAINTS2,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension);
if (NULL != pExt)
{
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
DWORD cb;
cb = sizeof(Constraints);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_BASIC_CONSTRAINTS2,
pExt->Value.pbData,
pExt->Value.cbData,
0,
&Constraints,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptDecodeObject");
}
*pfCA = Constraints.fCA;
}
hr = S_OK;
error:
return(hr);
}
char const *g_apszKRAObjIds[] = {
szOID_KP_KEY_RECOVERY_AGENT,
szOID_EFS_RECOVERY,
szOID_KP_KEY_RECOVERY,
};
HRESULT
IsKRACert(
IN CERT_CONTEXT const *pCertContext,
OUT BOOL *pfKRA)
{
HRESULT hr;
CERT_EXTENSION *pExt;
CERT_ENHKEY_USAGE *pKeyUsage = NULL;
CERT_POLICIES_INFO *pPolicies = NULL;
DWORD cb;
DWORD i;
DWORD j;
*pfKRA = FALSE;
pExt = CertFindExtension(
szOID_ENHANCED_KEY_USAGE,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension);
if (NULL != pExt)
{
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_ENHANCED_KEY_USAGE,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pKeyUsage,
&cb))
{
hr = myHLastError();
_JumpIfError(hr, error, "myDecodeObject");
}
for (i = 0; i < pKeyUsage->cUsageIdentifier; i++)
{
char const *pszObjId = pKeyUsage->rgpszUsageIdentifier[i];
for (j = 0; j < ARRAYSIZE(g_apszKRAObjIds); j++)
{
if (0 == strcmp(
pszObjId,
g_apszKRAObjIds[j]))
{
*pfKRA = TRUE;
hr = S_OK;
goto error;
}
}
}
}
pExt = CertFindExtension(
szOID_APPLICATION_CERT_POLICIES,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension);
if (NULL != pExt)
{
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_CERT_POLICIES,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pPolicies,
&cb))
{
hr = myHLastError();
_JumpIfError(hr, error, "myDecodeObject");
}
for (i = 0; i < pPolicies->cPolicyInfo; i++)
{
CERT_POLICY_INFO *pPolicyInfo = &pPolicies->rgPolicyInfo[i];
for (j = 0; j < ARRAYSIZE(g_apszKRAObjIds); j++)
{
if (0 == strcmp(
pPolicyInfo->pszPolicyIdentifier,
g_apszKRAObjIds[j]))
{
*pfKRA = TRUE;
hr = S_OK;
goto error;
}
}
}
}
hr = S_OK;
error:
if (NULL != pKeyUsage)
{
LocalFree(pKeyUsage);
}
if (NULL != pPolicies)
{
LocalFree(pPolicies);
}
return(hr);
}
HRESULT
dsPublishCertFromContext(
IN CERT_CONTEXT const *pCertContext,
OPTIONAL IN WCHAR const *pwszType)
{
HRESULT hr;
BOOL fCrossCA;
BOOL fCA;
BOOL fKRA;
BOOL fRoot;
DWORD dspFlags;
DWORD dwObjectType;
WCHAR *pwszCN = NULL;
WCHAR const *pwszSanitizedCN = NULL;
WCHAR *pwszSanitizedCNAlloc = NULL;
// If a CrossCA cert, publish to the Subject CN's AIA container.
// If a CA cert, publish to the Subject CN's AIA container.
// If a KRA cert, publish to the Issuer CN's KRA container.
hr = IsCrossCACert(pCertContext, &fCrossCA);
if (S_OK != hr)
{
_PrintError(hr, "IsCrossCACert");
if (NULL == pwszType && !g_fForce)
{
goto error;
}
}
hr = IsCACert(pCertContext, &fCA);
_JumpIfError(hr, error, "IsCACert");
hr = IsKRACert(pCertContext, &fKRA);
_JumpIfError(hr, error, "IsKRACert");
fRoot = CertCompareCertificateName(
X509_ASN_ENCODING,
&pCertContext->pCertInfo->Subject,
&pCertContext->pCertInfo->Issuer);
dwObjectType = LPC_CAOBJECT;
if (NULL == pwszType || 0 == lstrcmp(L"-", pwszType))
{
if (fCrossCA)
{
// Don't publish to "Certification Authorities" (root CAs)
// because Win2k crypt32 can't handle zero byte cACertificate
// attributes, and aborts processing valid roots.
dspFlags = DSP_OBJECT_AIA |
//DSP_OBJECT_ROOTTRUST |
DSP_ATTRIBUTE_CROSSCERTPAIR |
DSP_TYPE_SUBCACERT;
}
else
if (fCA)
{
dspFlags = DSP_OBJECT_AIA | DSP_ATTRIBUTE_CACERTIFICATE;
if (fRoot)
{
dspFlags |= DSP_OBJECT_ROOTTRUST;
}
}
else
if (fKRA)
{
dspFlags = DSP_OBJECT_KRA | DSP_ATTRIBUTE_USERCERTIFICATE;
dwObjectType = LPC_KRAOBJECT;
}
#if 0
// publish User or Machine certs
dwObjectType = LPC_USEROBJECT;
dwObjectType = LPC_MACHINEOBJECT;
#endif
else
{
hr = E_INVALIDARG;
_JumpError(hr, error, "non-CA, non-KRA cert");
}
}
else
{
if (0 == lstrcmpi(L"NTAuthCA", pwszType))
{
dspFlags = DSP_OBJECT_NTAUTHCERT |
DSP_ATTRIBUTE_CACERTIFICATE |
DSP_TYPE_ROOTCACERT |
DSP_TYPE_SUBCACERT;
pwszSanitizedCN = L"NTAuthCertificates";
}
else
if (0 == lstrcmpi(L"RootCA", pwszType))
{
dspFlags = DSP_OBJECT_AIA |
DSP_OBJECT_ROOTTRUST |
DSP_ATTRIBUTE_CACERTIFICATE |
DSP_TYPE_ROOTCACERT;
}
else
if (0 == lstrcmpi(L"SubCA", pwszType))
{
dspFlags = DSP_OBJECT_AIA |
DSP_ATTRIBUTE_CACERTIFICATE |
DSP_TYPE_SUBCACERT;
}
else
if (0 == lstrcmpi(L"CrossCA", pwszType))
{
// Don't publish to "Certification Authorities" (root CAs)
// because Win2k crypt32 can't handle zero byte cACertificate
// attributes, and aborts processing valid roots.
dspFlags = DSP_OBJECT_AIA |
//DSP_OBJECT_ROOTTRUST |
DSP_ATTRIBUTE_CROSSCERTPAIR |
DSP_TYPE_SUBCACERT;
}
else
if (0 == lstrcmpi(L"KRA", pwszType))
{
dspFlags = DSP_OBJECT_KRA |
DSP_ATTRIBUTE_USERCERTIFICATE |
DSP_TYPE_KRACERT |
DSP_TYPE_EECERT;
dwObjectType = LPC_KRAOBJECT;
}
#if 0
else
if (0 == lstrcmpi(L"User", pwszType))
{
dspFlags = DSP_OBJECT_USER |
DSP_ATTRIBUTE_USERCERTIFICATE |
DSP_TYPE_EECERT;
dwObjectType = LPC_USEROBJECT;
}
else
if (0 == lstrcmpi(L"Machine", pwszType))
{
dspFlags = DSP_OBJECT_MACHINE |
DSP_ATTRIBUTE_USERCERTIFICATE |
DSP_TYPE_EECERT;
dwObjectType = LPC_MACHINEOBJECT;
}
#endif
else
{
hr = E_INVALIDARG;
_JumpErrorStr(hr, error, "pwszType", pwszType);
}
if (!fKRA && (DSP_TYPE_KRACERT & dspFlags))
{
_PrintError(S_OK, "forcing KRA");
}
if (fCA && (DSP_TYPE_EECERT & dspFlags))
{
_PrintError(S_OK, "forcing non-CA");
}
if (!fCA &&
((DSP_TYPE_ROOTCACERT | DSP_TYPE_SUBCACERT) & dspFlags))
{
_PrintError(S_OK, "forcing CA");
}
if (!fRoot &&
DSP_TYPE_ROOTCACERT ==
((DSP_TYPE_ROOTCACERT | DSP_TYPE_SUBCACERT) & dspFlags))
{
_PrintError(S_OK, "forcing Root");
}
}
if (NULL == pwszSanitizedCN)
{
hr = dsGetCommonName(
fCA?
&pCertContext->pCertInfo->Subject :
&pCertContext->pCertInfo->Issuer,
TRUE,
&pwszCN);
_JumpIfError(hr, error, "dsGetCommonName");
hr = mySanitizeName(pwszCN, &pwszSanitizedCNAlloc);
_JumpIfError(hr, error, "mySanitizeName");
pwszSanitizedCN = pwszSanitizedCNAlloc;
}
hr = dsPublishCert(
pCertContext,
pwszSanitizedCN,
dspFlags,
dwObjectType);
_JumpIfError(hr, error, "dsPublishCert");
error:
if (NULL != pwszCN)
{
LocalFree(pwszCN);
}
if (NULL != pwszSanitizedCNAlloc)
{
LocalFree(pwszSanitizedCNAlloc);
}
return(hr);
}
HRESULT
dsPublishCRLFromContext(
IN CRL_CONTEXT const *pCRLContext,
IN BOOL fDelta)
{
HRESULT hr;
HRESULT hr2;
CRL_DIST_POINTS_INFO *pcdp = NULL;
CERT_EXTENSION *pExt;
WCHAR *pwszURL = NULL;
DWORD cb;
DWORD i;
DWORD j;
pExt = CertFindExtension(
szOID_CRL_SELF_CDP,
pCRLContext->pCrlInfo->cExtension,
pCRLContext->pCrlInfo->rgExtension);
if (NULL == pExt && !fDelta)
{
pExt = CertFindExtension(
szOID_FRESHEST_CRL,
pCRLContext->pCrlInfo->cExtension,
pCRLContext->pCrlInfo->rgExtension);
}
if (NULL == pExt)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "CertFindExtension");
}
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_CRL_DIST_POINTS,
pExt->Value.pbData,
pExt->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pcdp,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
hr = S_OK;
for (i = 0; i < pcdp->cDistPoint; i++)
{
CRL_DIST_POINT const *pDistPoint = &pcdp->rgDistPoint[i];
if (CRL_DIST_POINT_FULL_NAME !=
pDistPoint->DistPointName.dwDistPointNameChoice)
{
continue;
}
for (j = 0; j < pDistPoint->DistPointName.FullName.cAltEntry; j++)
{
CERT_ALT_NAME_ENTRY const *pAltNameEntry = &pDistPoint->DistPointName.FullName.rgAltEntry[j];
#define wszLDAPCOLON L"ldap:"
WCHAR awcLDAP[ARRAYSIZE(wszLDAPCOLON)];
if (CERT_ALT_NAME_URL != pAltNameEntry->dwAltNameChoice)
{
continue;
}
if (ARRAYSIZE(awcLDAP) > wcslen(pAltNameEntry->pwszURL))
{
continue;
}
CopyMemory(awcLDAP, pAltNameEntry->pwszURL, sizeof(awcLDAP));
awcLDAP[ARRAYSIZE(awcLDAP) - 1] = L'\0';
if (0 != lstrcmpi(wszLDAPCOLON, awcLDAP))
{
continue;
}
if (NULL != pwszURL)
{
LocalFree(pwszURL);
pwszURL = NULL;
}
hr2 = myInternetUncanonicalizeURL(pAltNameEntry->pwszURL, &pwszURL);
_PrintIfError(hr2, "myInternetUncanonicalizeURL");
if (S_OK == hr)
{
hr = hr2; // Save first error
}
hr2 = dsPublishCRL(
NULL,
pCRLContext,
fDelta,
NULL != pwszURL? pwszURL : pAltNameEntry->pwszURL);
_PrintIfError(hr2, "dsPublishCRL");
if (S_OK == hr)
{
hr = hr2; // Save first error
}
}
_JumpIfError(hr, error, "dsPublishCRL");
}
error:
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
if (NULL != pcdp)
{
LocalFree(pcdp);
}
return(hr);
}
HRESULT
dsPublishCRLFromParms(
IN CRL_CONTEXT const *pCRLContext,
IN BOOL fDelta,
IN WCHAR const *pwszServerName,
OPTIONAL IN WCHAR const *pwszSanitizedCN)
{
HRESULT hr;
WCHAR *pwszServerNameAlloc = NULL; // Shouldn't be necessary
LDAP *pld = NULL;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
WCHAR *pwszCN = NULL;
WCHAR *pwszSanitizedCNAlloc = NULL;
WCHAR *pwszURL = NULL;
DWORD iCert = 0;
DWORD iCRL = 0;
WCHAR const *pwszTemplate;
if (NULL == pwszServerName)
{
hr = myGetMachineDnsName(&pwszServerNameAlloc);
_JumpIfError(hr, error, "myGetMachineDnsName");
pwszServerName = pwszServerNameAlloc;
}
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
_JumpIfError(hr, error, "myLdapOpen");
if (NULL == pwszSanitizedCN)
{
CERT_EXTENSION *pExt;
hr = dsGetCommonName(&pCRLContext->pCrlInfo->Issuer, FALSE, &pwszCN);
_JumpIfError(hr, error, "dsGetCommonName");
hr = mySanitizeName(pwszCN, &pwszSanitizedCNAlloc);
_JumpIfError(hr, error, "mySanitizeName");
pwszSanitizedCN = pwszSanitizedCNAlloc;
pExt = CertFindExtension(
szOID_CERTSRV_CA_VERSION,
pCRLContext->pCrlInfo->cExtension,
pCRLContext->pCrlInfo->rgExtension);
if (NULL != pExt)
{
DWORD NameId;
DWORD cb;
cb = sizeof(NameId);
NameId = 0;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pExt->Value.pbData,
pExt->Value.cbData,
0,
&NameId,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "CryptDecodeObject");
}
iCert = CANAMEIDTOICERT(NameId);
iCRL = CANAMEIDTOIKEY(NameId);
}
}
pwszTemplate = g_wszzLDAPRevocationURLTemplate;
hr = myFormatCertsrvStringArray(
FALSE, // fURL
pwszServerName, // pwszServerName_p1_2
pwszSanitizedCN, // pwszSanitizedName_p3_7
iCert, // iCert_p4
strDomainDN, // pwszDomainDN_p5
strConfigDN, // pwszConfigDN_p6
iCRL, // iCRL_p8
fDelta, // fDeltaCRL_p9
FALSE, // fDSAttrib_p10_11
1, // cStrings
&pwszTemplate, // apwszStringsIn
&pwszURL); // apwszStringsOut
_JumpIfError(hr, error, "myFormatCertsrvStringArray");
hr = dsPublishCRL(pld, pCRLContext, fDelta, pwszURL);
_JumpIfError(hr, error, "dsPublishCRL");
error:
if (NULL != pwszCN)
{
LocalFree(pwszCN);
}
if (NULL != pwszSanitizedCNAlloc)
{
LocalFree(pwszSanitizedCNAlloc);
}
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
if (NULL != pwszServerNameAlloc)
{
LocalFree(pwszServerNameAlloc);
}
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
// pwszType: NTAuthCA | RootCA | SubCA | CrossCA | KRA | User | Machine
// pwszDSCDPContainer: machine name
HRESULT
verbDSPublish(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszfn,
OPTIONAL IN WCHAR const *pwszTypeOrDSCDPContainer,
OPTIONAL IN WCHAR const *pwszDSCN,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
CERT_CONTEXT const *pCertContext = NULL;
CRL_CONTEXT const *pCRLContext = NULL;
CSASSERT(NULL != pwszfn);
hr = cuLoadCert(pwszfn, &pCertContext);
if (S_OK == hr)
{
if (NULL != pwszDSCN)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "non-NULL CDP parms");
}
hr = dsPublishCertFromContext(pCertContext, pwszTypeOrDSCDPContainer);
_JumpIfError(hr, error, "dsPublishCertFromContext");
}
else
{
CERT_EXTENSION *pExt;
BOOL fDelta;
hr = cuLoadCRL(pwszfn, &pCRLContext);
if (S_OK != hr)
{
cuPrintError(IDS_FORMAT_LOADCERTORCRL, hr);
#if 1
WCHAR *pwszURL = NULL;
HRESULT hr2 = myInternetUncanonicalizeURL(pwszfn, &pwszURL);
_PrintIfError(hr2, "myInternetUncanonicalizeURL");
if (NULL != pwszURL)
{
LocalFree(pwszURL);
}
#endif
goto error;
}
pExt = CertFindExtension(
szOID_DELTA_CRL_INDICATOR,
pCRLContext->pCrlInfo->cExtension,
pCRLContext->pCrlInfo->rgExtension);
fDelta = NULL != pExt;
if (NULL != pwszTypeOrDSCDPContainer)
{
hr = dsPublishCRLFromParms(
pCRLContext,
fDelta,
pwszTypeOrDSCDPContainer,
pwszDSCN);
_JumpIfError(hr, error, "dsPublishCRLFromParms");
}
else
{
hr = dsPublishCRLFromContext(pCRLContext, fDelta);
_JumpIfError(hr, error, "dsPublishCRLFromContext");
}
}
error:
cuUnloadCRL(&pCRLContext);
cuUnloadCert(&pCertContext);
return(hr);
}
HRESULT
dsDumpOIDDisplayNames(
IN LDAP *pld,
IN WCHAR const *pwszOIDDN,
IN WCHAR const *pwszObjId,
IN DWORD dwLanguageId,
IN OUT DWORD *pdwType,
OUT BOOL *pfObjectExists,
OUT BOOL *pfLangIdExists,
OPTIONAL OUT WCHAR ***pppwszLdapVal)
{
HRESULT hr;
LDAP_TIMEVAL timeval;
LDAPMessage *pmsg = NULL;
LDAPMessage *pres;
DWORD cres;
WCHAR **ppwszLdapVal = NULL;
*pfObjectExists = FALSE;
*pfLangIdExists = FALSE;
if (NULL != pppwszLdapVal)
{
*pppwszLdapVal = NULL;
}
timeval.tv_sec = csecLDAPTIMEOUT;
timeval.tv_usec = 0;
hr = ldap_search_st(
pld, // ld
const_cast<WCHAR *>(pwszOIDDN), // base
LDAP_SCOPE_BASE,
NULL, // filter
NULL, // attrs
FALSE, // attrsonly
&timeval, // timeout
&pmsg); // res
if (S_OK != hr)
{
hr = myHLdapError2(pld, hr, LDAP_NO_SUCH_OBJECT, NULL);
_PrintErrorStr2(
hr,
"ldap_search_st",
pwszOIDDN,
HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
if (HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND) != hr)
{
goto error;
}
}
else
{
cres = ldap_count_entries(pld, pmsg);
if (0 != cres)
{
for (pres = ldap_first_entry(pld, pmsg);
NULL != pres && NULL == ppwszLdapVal;
pres = ldap_next_entry(pld, pres))
{
DWORD i;
ppwszLdapVal = ldap_get_values(pld, pres, OID_PROP_OID);
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0] &&
0 == lstrcmp(pwszObjId, ppwszLdapVal[0]))
{
*pfObjectExists = TRUE;
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
if (*pfObjectExists)
{
ppwszLdapVal = ldap_get_values(pld, pres, OID_PROP_TYPE);
if (NULL != ppwszLdapVal)
{
if (NULL != ppwszLdapVal[0])
{
DWORD dw = _wtoi(ppwszLdapVal[0]);
if (*pdwType != dw)
{
if (MAXDWORD != *pdwType)
{
wprintf(myLoadResourceString(IDS_TYPE_MISMATCH)); // "Type mismatch"
wprintf(wszNewLine);
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
_JumpError(hr, error, "*pdwType mismatch");
}
*pdwType = dw;
}
}
ldap_value_free(ppwszLdapVal);
ppwszLdapVal = NULL;
}
i = 0;
ppwszLdapVal = ldap_get_values(
pld,
pres,
OID_PROP_LOCALIZED_NAME);
if (NULL != ppwszLdapVal)
{
for ( ; NULL != ppwszLdapVal[i]; i++)
{
wprintf(L" %u: %ws\n", i, ppwszLdapVal[i]);
if (!*pfLangIdExists)
{
hr = myLdapOIDIsMatchingLangId(
ppwszLdapVal[i],
dwLanguageId,
pfLangIdExists);
_PrintIfError(hr, "myLdapOIDIsMatchingLangId");
}
}
}
if (0 == i)
{
wprintf(myLoadResourceString(IDS_NO_DISPLAY_NAMES)); // "No display names"
wprintf(wszNewLine);
}
break;
}
}
}
}
if (NULL != pppwszLdapVal)
{
*pppwszLdapVal = ppwszLdapVal;
ppwszLdapVal = NULL;
}
hr = S_OK;
error:
if (NULL != ppwszLdapVal)
{
ldap_value_free(ppwszLdapVal);
}
if (NULL != pmsg)
{
ldap_msgfree(pmsg);
}
return(hr);
}
// Set OID_PROP_LOCALIZED_NAME on the appropriate OID object under g_wszCNOID.
HRESULT
verbOIDName(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszObjId,
OPTIONAL IN WCHAR const *pwszDisplayName,
OPTIONAL IN WCHAR const *pwszLanguageId,
OPTIONAL IN WCHAR const *pwszType)
{
HRESULT hr;
DWORD dwLanguageId;
DWORD dwType;
WCHAR const *pwszName;
LDAP *pld = NULL;
BSTR strDomainDN = NULL;
BSTR strConfigDN = NULL;
WCHAR *pwszOIDCN = NULL;
WCHAR *pwszOIDContainer = NULL;
WCHAR *pwszOIDDN = NULL;
WCHAR **ppwszLdapVal = NULL;
BOOL fObjectExists = FALSE;
BOOL fLangIdExists = FALSE;
WCHAR *pwszError = NULL;
if (NULL != pwszLanguageId)
{
hr = cuGetLong(pwszLanguageId, (LONG *) &dwLanguageId);
_JumpIfError(hr, error, "dwLanguageId must be a number");
if (64 * 1024 <= dwLanguageId)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "dwLanguageId too large");
}
}
else
{
dwLanguageId = GetSystemDefaultLangID();
}
if (NULL != pwszType)
{
hr = cuGetLong(pwszType, (LONG *) &dwType);
_JumpIfError(hr, error, "dwType must be a number");
}
else
{
dwType = MAXDWORD;
}
hr = myVerifyObjId(pwszObjId);
if (S_OK != hr)
{
wprintf(myLoadResourceString(IDS_INVALID_OBJECTID)); // "Invalid ObjectId"
wprintf(wszNewLine);
_JumpError(hr, error, "myVerifyObjId");
}
pwszName = cuGetOIDName(pwszObjId);
if (S_OK == hr || L'\0' != *pwszName)
{
if (L'\0' == *pwszName)
{
pwszName = myLoadResourceString(IDS_UNKNOWN_OBJECTID); // "Unknown ObjectId"
}
wprintf(L"%ws -- %ws\n", pwszObjId, pwszName);
}
hr = myOIDHashOIDToString(pwszObjId, &pwszOIDCN);
_JumpIfError(hr, error, "myOIDHashOIDToString");
hr = myLdapOpen(&pld, &strDomainDN, &strConfigDN);
if (S_OK != hr)
{
_PrintError2(hr, "myLdapOpen", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
if (NULL == pwszDisplayName)
{
hr = S_OK;
}
goto error;
}
hr = BuildDN(g_wszCNOID, strConfigDN, FALSE, &pwszOIDContainer);
_JumpIfError(hr, error, "BuildDN");
hr = BuildDN(pwszOIDCN, pwszOIDContainer, TRUE, &pwszOIDDN);
_JumpIfError(hr, error, "BuildDN");
hr = dsDumpOIDDisplayNames(
pld,
pwszOIDDN,
pwszObjId,
dwLanguageId,
&dwType,
&fObjectExists,
&fLangIdExists,
&ppwszLdapVal);
_JumpIfError(hr, error, "dsDumpOIDDisplayNames");
if (NULL != pwszDisplayName)
{
DWORD dwDisposition;
if (!fObjectExists && !g_fForce)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "ldap_first/next_entry");
}
if (fLangIdExists && !g_fForce)
{
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
_JumpError(hr, error, "ldap_get_values");
}
//wprintf(L"%u: %u,%ws\n", dwType, dwLanguageId, pwszDisplayName);
if (!fObjectExists)
{
if (MAXDWORD == dwType)
{
dwType = CERT_OID_TYPE_TEMPLATE;
}
hr = myLdapCreateOIDObject(
pld,
pwszOIDDN,
dwType,
pwszObjId,
&dwDisposition,
&pwszError);
_JumpIfError(hr, error, "myLdapCreateOIDObject");
CSASSERT(NULL == pwszError);
}
hr = myLdapAddOIDDisplayNameToAttribute(
pld,
ppwszLdapVal,
dwLanguageId,
pwszDisplayName,
pwszOIDDN,
OID_PROP_LOCALIZED_NAME,
&dwDisposition,
&pwszError);
_JumpIfError(hr, error, "myLdapAddOIDDisplayNameToAttribute");
wprintf(wszNewLine);
if (LDAP_SUCCESS == dwDisposition)
{
wprintf(
myLoadResourceString(IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
myLoadResourceString(IDS_LOCALIZEDNAME)); // "Localized name"
wprintf(wszNewLine);
hr = dsDumpOIDDisplayNames(
pld,
pwszOIDDN,
pwszObjId,
dwLanguageId,
&dwType,
&fObjectExists,
&fLangIdExists,
NULL); // pppwszLdapVal
_JumpIfError(hr, error, "dsDumpOIDDisplayNames");
}
else
{
CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
wprintf(
myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
myLoadResourceString(IDS_LOCALIZEDNAME)); // "Localized name"
wprintf(wszNewLine);
}
}
hr = S_OK;
error:
if (NULL != pwszError)
{
wprintf(L"%ws\n", pwszError);
LocalFree(pwszError);
}
if (NULL != ppwszLdapVal)
{
ldap_value_free(ppwszLdapVal);
}
if (NULL != pwszOIDCN)
{
LocalFree(pwszOIDCN);
}
if (NULL != pwszOIDDN)
{
LocalFree(pwszOIDDN);
}
if (NULL != pwszOIDContainer)
{
LocalFree(pwszOIDContainer);
}
myLdapClose(pld, strDomainDN, strConfigDN);
return(hr);
}
typedef struct _QUERY_INFO
{
WCHAR const *pwszInfo;
DWORD dwInfo;
} QUERY_INFO;
QUERY_INFO g_rgQueryInfo[] = {
#if 0
L"HTTP_QUERY_MIME_VERSION-Req",
HTTP_QUERY_MIME_VERSION | HTTP_QUERY_FLAG_REQUEST_HEADERS,
L"HTTP_QUERY_CONTENT_TYPE-Req",
HTTP_QUERY_CONTENT_TYPE | HTTP_QUERY_FLAG_REQUEST_HEADERS,
L"HTTP_QUERY_CONTENT_TRANSFER_ENCODING-Req",
HTTP_QUERY_CONTENT_TRANSFER_ENCODING | HTTP_QUERY_FLAG_REQUEST_HEADERS,
L"HTTP_QUERY_CONTENT_LENGTH-Req",
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_REQUEST_HEADERS,
#endif
L"HTTP_QUERY_MIME_VERSION", HTTP_QUERY_MIME_VERSION,
L"HTTP_QUERY_CONTENT_TYPE", HTTP_QUERY_CONTENT_TYPE,
L"HTTP_QUERY_CONTENT_TRANSFER_ENCODING",
HTTP_QUERY_CONTENT_TRANSFER_ENCODING,
L"HTTP_QUERY_CONTENT_LENGTH", HTTP_QUERY_CONTENT_LENGTH,
L"HTTP_QUERY_CONTENT_LENGTH-Num",
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
L"HTTP_QUERY_VERSION", HTTP_QUERY_VERSION,
L"HTTP_QUERY_STATUS_CODE", HTTP_QUERY_STATUS_CODE,
L"HTTP_QUERY_STATUS_CODE-Num",
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
L"HTTP_QUERY_STATUS_TEXT", HTTP_QUERY_STATUS_TEXT,
L"HTTP_QUERY_RAW_HEADERS", HTTP_QUERY_RAW_HEADERS,
L"HTTP_QUERY_RAW_HEADERS_CRLF", HTTP_QUERY_RAW_HEADERS_CRLF,
L"HTTP_QUERY_CONTENT_ENCODING", HTTP_QUERY_CONTENT_ENCODING,
L"HTTP_QUERY_LOCATION", HTTP_QUERY_LOCATION,
L"HTTP_QUERY_ORIG_URI", HTTP_QUERY_ORIG_URI,
L"HTTP_QUERY_REQUEST_METHOD", HTTP_QUERY_REQUEST_METHOD,
L"HTTP_QUERY_DATE",
HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME,
L"HTTP_QUERY_EXPIRES",
HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME,
L"HTTP_QUERY_LAST_MODIFIED",
HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME,
};
HRESULT
DisplayQueryInfo(
IN HINTERNET hInternetFile)
{
HRESULT hr;
DWORD i;
for (i = 0; i < ARRAYSIZE(g_rgQueryInfo); i++)
{
QUERY_INFO *pQuery = &g_rgQueryInfo[i];
DWORD dwIndex;
BOOL fFirst;
fFirst = TRUE;
dwIndex = 0;
while (TRUE)
{
BYTE rgbBuf[MAX_CACHE_ENTRY_INFO_SIZE];
DWORD cbBuf;
DWORD dwThisIndex = dwIndex;
BOOL fResult;
DWORD dwValue;
SYSTEMTIME st;
if (HTTP_QUERY_FLAG_NUMBER & pQuery->dwInfo)
{
cbBuf = sizeof(dwValue);
fResult = HttpQueryInfo(
hInternetFile,
pQuery->dwInfo,
&dwValue,
&cbBuf,
&dwIndex);
}
else
if (HTTP_QUERY_FLAG_SYSTEMTIME & pQuery->dwInfo)
{
cbBuf = sizeof(st);
fResult = HttpQueryInfo(
hInternetFile,
pQuery->dwInfo,
&st,
&cbBuf,
&dwIndex);
}
else
{
ZeroMemory(rgbBuf, sizeof(rgbBuf));
cbBuf = sizeof(rgbBuf);
fResult = HttpQueryInfo(
hInternetFile,
pQuery->dwInfo,
rgbBuf,
&cbBuf,
&dwIndex);
}
if (!fResult)
{
hr = myHLastError();
if (fFirst ||
HRESULT_FROM_WIN32(ERROR_HTTP_HEADER_NOT_FOUND) != hr)
{
_PrintErrorStr(hr, "HttpQueryInfo", pQuery->pwszInfo);
}
break;
}
if (HTTP_QUERY_FLAG_NUMBER & pQuery->dwInfo)
{
wprintf(
L"%ws[%d] = %x (%d)\n",
pQuery->pwszInfo,
dwThisIndex,
dwValue,
dwValue);
}
else
if (HTTP_QUERY_FLAG_SYSTEMTIME & pQuery->dwInfo)
{
FILETIME ft;
if (!SystemTimeToFileTime(&st, &ft))
{
hr = myHLastError();
_JumpErrorStr(
hr,
error,
"SystemTimeToFileTime",
pQuery->pwszInfo);
}
else
{
wprintf(L"%ws[%d] =", pQuery->pwszInfo, dwThisIndex);
hr = cuDumpFileTime(0, NULL, &ft);
wprintf(wszNewLine);
_PrintIfError(hr, "cuDumpFileTime");
}
}
else
{
wprintf(L"%ws[%d] =\n", pQuery->pwszInfo, dwThisIndex);
DumpHex(0, (BYTE const *) rgbBuf, cbBuf);
}
fFirst = FALSE;
if (dwThisIndex == dwIndex)
{
#if 0
wprintf(
L"HttpQueryInfo(%ws) dwIndex not advanced\n",
pQuery->pwszInfo);
#endif
break;
}
}
}
hr = S_OK;
error:
return(hr);
}
HRESULT
DisplayCacheEntryInfo(
IN WCHAR const *pwszURL)
{
HRESULT hr;
DWORD cbCachEntryInfo;
BYTE rgbCachEntryInfo[MAX_CACHE_ENTRY_INFO_SIZE];
INTERNET_CACHE_ENTRY_INFO *pCacheEntryInfo =
(INTERNET_CACHE_ENTRY_INFO *) &rgbCachEntryInfo[0];
cbCachEntryInfo = sizeof(rgbCachEntryInfo);
if (!GetUrlCacheEntryInfo(pwszURL, pCacheEntryInfo, &cbCachEntryInfo))
{
hr = myHLastError();
_JumpError(hr, error, "GetUrlCacheEntryInfo");
}
wprintf(
L"GetUrlCacheEntryInfo: %d %ws\n",
cbCachEntryInfo,
myLoadResourceString(IDS_BYTES));
if (0 != cbCachEntryInfo)
{
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_SOURCE_URL), pCacheEntryInfo->lpszSourceUrlName);
wprintf(wszNewLine);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_LOCAL_FILENAME), pCacheEntryInfo->lpszLocalFileName);
wprintf(wszNewLine);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_USE_COUNT), pCacheEntryInfo->dwUseCount);
wprintf(wszNewLine);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_HIT_RATE), pCacheEntryInfo->dwHitRate);
wprintf(wszNewLine);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_FILE_SIZE), pCacheEntryInfo->dwSizeLow);
wprintf(wszNewLine);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_LAST_MOD_TIME_COLON));
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastModifiedTime);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_EXPIRE_TIME_COLON));
cuDumpFileTime(0, NULL, &pCacheEntryInfo->ExpireTime);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_LAST_ACCESS_TIME_COLON));
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastAccessTime);
wprintf(g_wszPad2);
wprintf(myLoadResourceString(IDS_FORMAT_LAST_SYNC_TIME_COLON));
cuDumpFileTime(0, NULL, &pCacheEntryInfo->LastSyncTime);
}
hr = S_OK;
error:
return(hr);
}
typedef struct _DATABLOCK {
struct _DATABLOCK *pNext;
DWORD cbData;
BYTE abData[1];
} DATABLOCK;
HRESULT
AddDataBlock(
IN BYTE *pb,
IN DWORD cb,
IN OUT DATABLOCK **ppData)
{
HRESULT hr;
DATABLOCK *pData = NULL;
pData = (DATABLOCK *) LocalAlloc(LMEM_FIXED, sizeof(*pData) + cb);
if (NULL == pData)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pData->pNext = *ppData;
pData->cbData = cb;
CopyMemory(pData->abData, pb, cb);
*ppData = pData;
hr = S_OK;
error:
return(hr);
}
HRESULT
ReadURL(
HINTERNET hInternetFile)
{
HRESULT hr;
BYTE *pb = NULL;
BYTE *pb2;
DWORD cb;
DWORD cbRead;
DATABLOCK *pData = NULL;
DATABLOCK *pData2;
cb = 0;
if (!InternetQueryDataAvailable(
hInternetFile,
&cb,
0, // dwFlags
0)) // dwContext
{
hr = myHLastError();
_PrintError(hr, "InternetQueryDataAvailable");
}
cb = 0;
while (TRUE)
{
BYTE ab[4096];
if (!InternetReadFile(hInternetFile, ab, sizeof(ab), &cbRead))
{
hr = myHLastError();
_JumpError(hr, error, "InternetReadFile");
}
if (0 == cbRead)
{
break;
}
hr = AddDataBlock(ab, cbRead, &pData);
_JumpIfError(hr, error, "AddDataBlock");
cb += cbRead;
}
pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
if (NULL == pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pb2 = &pb[cb];
for (pData2 = pData; NULL != pData2; pData2 = pData2->pNext)
{
pb2 -= pData2->cbData;
CSASSERT(pb2 >= pb);
CopyMemory(pb2, pData2->abData, pData2->cbData);
}
CSASSERT(pb2 == pb);
hr = cuDumpAsnBinary(pb, cb, MAXDWORD);
if (S_OK != hr)
{
_PrintError(hr, "cuDumpAsnBinary");
DumpHex(0, pb, cb);
}
hr = S_OK;
error:
while (NULL != pData)
{
pData2 = pData;
pData = pData->pNext;
LocalFree(pData2);
}
if (NULL != pb)
{
LocalFree(pb);
}
return(hr);
}
HRESULT
verbURLCache(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszDelete,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HRESULT hr2;
HINTERNET hInternetSession = NULL;
HINTERNET hInternetFile = NULL;
if (NULL != pwszDelete)
{
if (0 != lstrcmpi(L"Delete", pwszDelete))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad delete arg");
}
if (!DeleteUrlCacheEntry(pwszURL))
{
hr = myHLastError();
_JumpError(hr, error, "DeleteUrlCacheEntry");
}
}
else
{
DWORD dwFlags = g_fForce? INTERNET_FLAG_RELOAD : INTERNET_FLAG_OFFLINE;
wprintf(
L"**** %ws ****\n",
g_fForce? L"ONLINE" : L"OFFLINE");
hInternetSession = InternetOpen(
L"CRL Agent", // lpszAgent
INTERNET_OPEN_TYPE_PRECONFIG, // dwAccessType
NULL, // lpszProxy
NULL, // lpszProxyBypass
dwFlags);
if (NULL == hInternetSession)
{
hr = myHLastError();
_JumpError(hr, error, "InternetOpen");
}
hInternetFile = InternetOpenUrl(
hInternetSession,
pwszURL,
L"Accept: */*\r\n", // lpszHeaders
MAXDWORD, // dwHeadersLength
dwFlags | INTERNET_FLAG_IGNORE_CERT_CN_INVALID,
0); // dwContext
if (NULL == hInternetFile)
{
hr = myHLastError();
_PrintError(GetLastError(), "InternetOpenUrl");
_JumpError(hr, error, "InternetOpenUrl");
}
if (g_fForce)
{
if (g_fVerbose)
{
hr = DisplayCacheEntryInfo(pwszURL);
_PrintIfError(hr, "DisplayCacheEntryInfo");
}
}
else
{
if (g_fVerbose)
{
hr = DisplayQueryInfo(hInternetFile);
_PrintIfError(hr, "DisplayQueryInfo");
}
}
hr = ReadURL(hInternetFile);
_PrintIfError(hr, "ReadURL");
if (!g_fForce && g_fVerbose)
{
hr = DisplayCacheEntryInfo(pwszURL);
_PrintIfError(hr, "DisplayCacheEntryInfo");
}
}
hr = S_OK;
error:
if (NULL != hInternetFile)
{
if (!InternetCloseHandle(hInternetFile))
{
hr2 = myHLastError();
_PrintError(hr2, "InternetCloseHandle");
if (S_OK == hr)
{
hr = hr2;
}
}
}
if (NULL != hInternetSession)
{
if (!InternetCloseHandle(hInternetSession))
{
hr2 = myHLastError();
_PrintError(hr2, "InternetCloseHandle(Session)");
if (S_OK == hr)
{
hr = hr2;
}
}
}
return(hr);
}
HRESULT
verbPulse(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszArg1,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
HANDLE hEventAE = NULL;
hEventAE = OpenEvent(
EVENT_MODIFY_STATE,
FALSE,
MACHINE_AUTOENROLLMENT_TRIGGER_EVENT);
if (NULL == hEventAE)
{
hr = myHLastError();
_JumpError(hr, error, "OpenEvent");
}
if (!PulseEvent(hEventAE))
{
hr = myHLastError();
_JumpError(hr, error, "PulseEvent");
}
hr = S_OK;
error:
if (NULL != hEventAE)
{
CloseHandle(hEventAE);
}
return(hr);
}
// This function gets the group membership for a given machine...
HRESULT
cuGetGroupMembership(
IN WCHAR const *pwszSamName)
{
HRESULT hr;
WCHAR *pwszDomain = NULL;
WCHAR *pwszMachine = NULL;
DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
GROUP_USERS_INFO_0 *pgui0 = NULL;
DWORD cGroup;
DWORD cGroupTotal;
DWORD i;
hr = mySplitConfigString(pwszSamName, &pwszDomain, &pwszMachine);
_JumpIfError(hr, error, "mySplitConfigString");
if (NULL == pwszMachine || NULL == wcschr(pwszMachine, L'$'))
{
wprintf(myLoadResourceString(IDS_ERROR_CHECK_MACHINE_NAME));
wprintf(wszNewLine);
hr = E_INVALIDARG;
_JumpError(hr, error, "bad machine name");
}
hr = DsGetDcName(
NULL,
pwszDomain,
NULL,
NULL,
DS_RETURN_FLAT_NAME,
&pDCInfo);
if (S_OK != hr)
{
hr = myHError(hr);
_JumpError(hr, error, "DsGetDcName");
}
hr = NetUserGetGroups(
pDCInfo->DomainControllerName,
pwszMachine,
0, // level
(BYTE **) &pgui0,
MAX_PREFERRED_LENGTH, // prefmaxlen
&cGroup,
&cGroupTotal);
if (S_OK != hr)
{
hr = myHError(hr);
_JumpError(hr, error, "NetUserGetGroups");
}
wprintf(
L"\n%ws\n",
myLoadResourceString(IDS_GROUP_LIST_COLON)); // "Group Memberships:"
for (i = 0; i < cGroup; i++)
{
wprintf(L" %ws\n", pgui0[i].grui0_name);
}
hr = S_OK;
error:
if (NULL != pwszDomain)
{
LocalFree(pwszDomain);
}
if (NULL != pwszMachine)
{
LocalFree(pwszMachine);
}
if (NULL != pgui0)
{
NetApiBufferFree(pgui0);
}
return(hr);
}
#define wszDSSPN L"servicePrincipalName"
#define wszDSOBJECTCATEGORY L"ObjectCategory"
#define wszDSSAMACCOUNTNAME L"sAMAccountName"
#define wszDSUSERACCOUNTCONTROL L"userAccountControl"
HRESULT
verbMachineInfo(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszMachine,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
LPWSTR pwszDC;
DWORD dwGetDCFlags = DS_GC_SERVER_REQUIRED | DS_RETURN_DNS_NAME;
DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
DS_NAME_RESULT *pNameResults = NULL;
ULONG ldaperr;
WCHAR *pwszError = NULL;
char *pszFunc = NULL;
LDAP *pld = NULL;
LDAPMessage *SearchResult = NULL;
LDAPMessage *Entry = NULL;
WCHAR *pwszAttrName = NULL;
WCHAR **prgVal = NULL;
WCHAR **prgSPN = NULL;
WCHAR **prgDNS = NULL;
berval **Values = NULL;
BerElement *bElement = NULL;
BOOL fRediscover;
HANDLE hDS = NULL;
WCHAR *apwszAttrName[] = {
CA_PROP_DNSNAME,
wszDSSPN,
wszDSOBJECTCATEGORY,
wszDSSAMACCOUNTNAME,
wszDSUSERACCOUNTCONTROL,
NULL
};
WCHAR *ObjectClassFilter = L"objectClass=computer";
// Get (and check) machine object in DS
// Check:
// 1) SPN
// 2) Group Membership
// 3) DNSHostName
// 4) Object Class
// 5) Object Category
if (NULL == wcschr(pwszMachine, L'$'))
{
wprintf(myLoadResourceString(IDS_ERROR_NO_TRAILING), pwszMachine);
wprintf(wszNewLine);
hr = E_INVALIDARG;
_JumpError(hr, error, "machine name missing $");
}
fRediscover = FALSE;
while (TRUE)
{
if (fRediscover)
{
dwGetDCFlags |= DS_FORCE_REDISCOVERY;
}
// in case we rediscovered...
if (NULL != pDCInfo)
{
NetApiBufferFree(pDCInfo);
pDCInfo = NULL;
}
if (NULL != pNameResults)
{
DsFreeNameResult(pNameResults);
pNameResults = NULL;
}
if (NULL != pld)
{
ldap_unbind(pld);
pld = NULL;
}
if (NULL != pwszError)
{
LocalFree(pwszError);
pwszError = NULL;
}
pszFunc = "DsGetDCName";
hr = DsGetDcName(NULL, NULL, NULL, NULL, dwGetDCFlags, &pDCInfo);
if (S_OK != hr)
{
hr = myHError(hr);
_JumpError(hr, error, pszFunc);
}
if (NULL == pDCInfo ||
0 == (pDCInfo->Flags & DS_GC_FLAG) ||
0 == (pDCInfo->Flags & DS_DNS_CONTROLLER_FLAG) ||
NULL == pDCInfo->DomainControllerName)
{
hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
_JumpErrorStr(hr, error, pszFunc, L"pDCInfo");
}
// Modify DC name
pwszDC = pDCInfo->DomainControllerName;
while (*pwszDC == L'\\')
{
pwszDC++;
}
pszFunc = "DsBind";
hr = DsBind(pwszDC, NULL, &hDS);
if (S_OK != hr)
{
hr = myHError(hr);
_PrintError(hr, pszFunc);
if (!fRediscover)
{
fRediscover = TRUE;
continue;
}
_JumpError(hr, error, pszFunc);
}
pszFunc = "DsCrackNames";
hr = DsCrackNames(
hDS,
DS_NAME_NO_FLAGS,
DS_NT4_ACCOUNT_NAME,
DS_FQDN_1779_NAME,
1, // cNames
&pwszMachine, // rpNames (IN)
&pNameResults);
if (S_OK != hr)
{
hr = myHError(hr);
_PrintError(hr, pszFunc);
if (!fRediscover) // only do this once
{
fRediscover = TRUE;
continue;
}
_JumpError(hr, error, pszFunc);
}
if (1 > pNameResults->cItems ||
DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
{
hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
_JumpErrorStr(hr, error, pszFunc, L"pNameResults");
}
// ldap_bind to GC
pszFunc = "ldap_init";
pld = ldap_init(pwszDC, LDAP_GC_PORT);
if (NULL == pld)
{
hr = myHLdapLastError(NULL, &pwszError);
_PrintErrorStr(hr, pszFunc, pwszError);
if (!fRediscover) // only do this once
{
fRediscover = TRUE;
continue;
}
_JumpErrorStr(hr, error, pszFunc, pwszError);
}
// do this because we're explicitly setting DC name; see bug# 347563
pszFunc = "ldap_set_option";
ldaperr = ldap_set_option(pld, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
if (LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pld, ldaperr, &pwszError);
_PrintErrorStr(hr, pszFunc, pwszError);
if (!fRediscover) // only do this once
{
fRediscover = TRUE;
continue;
}
_JumpErrorStr(hr, error, pszFunc, pwszError);
}
pszFunc = "ldap_bind_s";
ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
if (LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pld, ldaperr, &pwszError);
_PrintErrorStr(hr, pszFunc, pwszError);
if (!fRediscover) // only do this once
{
fRediscover = TRUE;
continue;
}
_JumpErrorStr(hr, error, pszFunc, pwszError);
}
break;
}
pszFunc = "ldap_searh_s";
ldaperr = ldap_search_s(
pld,
pNameResults->rItems[0].pName,
LDAP_SCOPE_BASE,
ObjectClassFilter,
apwszAttrName,
FALSE,
&SearchResult);
if (LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pld, ldaperr, &pwszError);
_JumpErrorStr(hr, error, pszFunc, pwszError);
}
// should only be 1 entry...
for (Entry = ldap_first_entry(pld, SearchResult);
NULL != Entry;
Entry = ldap_next_entry(pld, Entry))
{
for (pwszAttrName = ldap_first_attribute(pld, Entry, &bElement);
NULL != pwszAttrName;
pwszAttrName = ldap_next_attribute(pld, Entry, bElement))
{
DWORD i;
if (NULL != pwszError)
{
LocalFree(pwszError);
pwszError = NULL;
}
prgVal = ldap_get_values(pld, Entry, pwszAttrName);
if (NULL == prgVal)
{
pszFunc = "ldap_get_values";
hr = myHLdapLastError(pld, &pwszError);
_PrintErrorStr(hr, pszFunc, pwszError);
wprintf(L"%hs(%ws): %ws\n", pszFunc, pwszAttrName, pwszError);
continue;
}
// Display values & store away DNSHostName & SPN values for
// comparison.
//DisplayLdapValues(pwszAttrName, prgVal);
wprintf(L"\n%ws:\n", pwszAttrName);
for (i = 0; NULL != prgVal[i]; i++)
{
wprintf(L" %s\n", prgVal[i]);
}
if (0 == lstrcmpi(pwszAttrName, CA_PROP_DNSNAME))
{
prgDNS = prgVal;
}
else if (0 == lstrcmpi(pwszAttrName, wszDSSPN))
{
prgSPN = prgVal;
}
else if (NULL != prgVal)
{
ldap_value_free(prgVal);
prgVal = NULL;
}
}
}
// There *will* be problems w/SPNs.
// This should help determine what problems there are.
if (NULL == prgDNS)
{
wprintf(
myLoadResourceString(IDS_FORMAT_MISSING_MACHINE_ATTRIBUTE), // "Machine object missing %ws attribute."
CA_PROP_DNSNAME);
wprintf(wszNewLine);
}
if (NULL == prgSPN)
{
wprintf(
myLoadResourceString(IDS_FORMAT_MISSING_MACHINE_ATTRIBUTE), // "Machine object missing %ws attribute."
wszDSSPN);
wprintf(wszNewLine);
}
// Now let's get the group membership for this machine
hr = cuGetGroupMembership(pwszMachine);
_JumpIfError(hr, error, "cuGetGroupMembership");
error:
if (NULL != prgDNS)
{
ldap_value_free(prgDNS);
}
if (NULL != prgSPN)
{
ldap_value_free(prgSPN);
}
if (NULL != SearchResult)
{
ldap_msgfree(SearchResult);
}
if (NULL != pDCInfo)
{
NetApiBufferFree(pDCInfo);
}
if (NULL != hDS)
{
DsUnBind(&hDS);
}
if (NULL != pNameResults)
{
DsFreeNameResult(pNameResults);
}
if (NULL != pld)
{
ldap_unbind(pld);
}
if (NULL != pwszError)
{
if (NULL != pszFunc)
{
wprintf(L"%hs: ", pszFunc);
}
wprintf(L"%ws\n", pwszError);
LocalFree(pwszError);
}
return(hr);
}