5589 lines
125 KiB
C++
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);
|
|
}
|