You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6020 lines
138 KiB
6020 lines
138 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: ds.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
#include <winldap.h>
|
|
#include <autoenr.h>
|
|
#include <ntdsapi.h>
|
|
#include <dsgetdc.h>
|
|
#include <lmaccess.h>
|
|
#include <lmapibuf.h>
|
|
|
|
#include "csldap.h"
|
|
#include "certtype.h"
|
|
#include "csber.h"
|
|
#include "tmpllist.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTUTIL_DS_CPP__
|
|
|
|
|
|
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;
|
|
DWORD Mode;
|
|
|
|
//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(g_pwszDC, 0, &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(pwszDN) +
|
|
wcslen(pwszTemplate) + 1) * sizeof(WCHAR));
|
|
if (NULL == pwszTemplateAlloc)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(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
|
|
MAXDWORD, // iCertTarget_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);
|
|
|
|
Mode = DVNS_DUMP;
|
|
|
|
hr = cuOpenCertStore(pwszURL, &Mode, NULL, &hStoreDS);
|
|
_JumpIfError(hr, error, "cuOpenCertStore");
|
|
|
|
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 = myGetLong(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 = myGetLong(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="
|
|
|
|
DWORD
|
|
dsGetNumericSuffix(
|
|
IN WCHAR const *pwszName)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cwcPrefix;
|
|
BOOL fDigit;
|
|
WCHAR const *pwsz;
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
cwcPrefix = MAXDWORD;
|
|
if (NULL == pwszName || L'\0' == *pwszName)
|
|
{
|
|
_JumpError2(hr, error, "empty", hr);
|
|
}
|
|
pwsz = &pwszName[wcslen(pwszName) - 1];
|
|
if (wcRPAREN == *pwsz)
|
|
{
|
|
pwsz--;
|
|
fDigit = FALSE;
|
|
while (pwsz > pwszName && iswdigit(*pwsz))
|
|
{
|
|
fDigit = TRUE;
|
|
pwsz--;
|
|
}
|
|
if (!fDigit || pwsz <= pwszName || wcLPAREN != *pwsz)
|
|
{
|
|
_JumpError2(hr, error, "fDigit or wcLPAREN", hr);
|
|
}
|
|
cwcPrefix = SAFE_SUBTRACT_POINTERS(pwsz, pwszName);
|
|
}
|
|
|
|
error:
|
|
return(cwcPrefix);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CACNBaseNameMatch(
|
|
IN WCHAR const *pwszCNMatch,
|
|
IN WCHAR const *pwszCN)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszDup = NULL;
|
|
BOOL fMatch = FALSE;
|
|
DWORD iSuffix;
|
|
WCHAR *pwsz;
|
|
|
|
hr = myDupString(pwszCN, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
iSuffix = dsGetNumericSuffix(pwszDup);
|
|
if (MAXDWORD != iSuffix)
|
|
{
|
|
pwszDup[iSuffix] = L'\0'; // truncate trailing "(#)"
|
|
}
|
|
pwsz = &pwszDup[wcslen(pwszDup) - WSZARRAYSIZE(L"-CDP") + 1];
|
|
if (pwsz > pwszDup && 0 == LSTRCMPIS(pwsz, L"-CDP"))
|
|
{
|
|
*pwsz = '\0'; // truncate trailing L"-CDP"
|
|
}
|
|
if (0 != mylstrcmpiL(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 == mylstrcmpiL(pwszCNMatch, pwszRevertCN) ||
|
|
0 == mylstrcmpiL(pwszCNMatch, pwszSanitizedCN))
|
|
{
|
|
goto match;
|
|
}
|
|
|
|
// Check against the displayName
|
|
|
|
if (NULL != pwszDisplayName && 0 == mylstrcmpiL(pwszCNMatch, pwszDisplayName))
|
|
{
|
|
goto match;
|
|
}
|
|
|
|
// Check against the alternate CN (msPKI-Cert-Template-OID)
|
|
|
|
if (NULL != pwszAlternateCN && 0 == mylstrcmpiL(pwszCNMatch, pwszAlternateCN))
|
|
{
|
|
goto match;
|
|
}
|
|
|
|
// Check against the OID converted to a CN
|
|
|
|
if (NULL != pwszOIDCN &&
|
|
0 == mylstrcmpiL(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,
|
|
OPTIONAL IN WCHAR const *pwszRDN,
|
|
IN WCHAR const *pwszContainer)
|
|
{
|
|
WCHAR *pwszDNAlloc = NULL;
|
|
WCHAR const *pwszDN;
|
|
HRESULT hr;
|
|
|
|
pwszDN = pwszContainer;
|
|
if (NULL != pwszRDN)
|
|
{
|
|
hr = BuildDN(pwszRDN, pwszContainer, TRUE, &pwszDNAlloc);
|
|
_JumpIfError(hr, error, "BuildDN");
|
|
|
|
pwszDN = pwszDNAlloc;
|
|
}
|
|
|
|
hr = ldap_delete_s(pld, const_cast<WCHAR *>(pwszDN));
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHLdapError(pld, hr, NULL);
|
|
_JumpErrorStr(hr, error, "ldap_delete_s", pwszDN);
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszDNAlloc)
|
|
{
|
|
LocalFree(pwszDNAlloc);
|
|
}
|
|
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, },
|
|
{ L"teletexTerminalIdentifier", DSAF_ASN, 0, NULL, },
|
|
{ L"kCCStatus", DSAF_ASN, 0, 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, },
|
|
{ L"legacyExchangeDN", DSAF_STRING, 0, NULL, },
|
|
{ L"msExchADCGlobalNames", DSAF_STRING, 0, NULL, },
|
|
{ L"domainDefAltRecip", DSAF_STRING, 0, NULL, },
|
|
{ L"dXAAdminForward", DSAF_STRING, 0, NULL, },
|
|
{ L"kMServer", DSAF_STRING, 0, NULL, },
|
|
{ L"sendEMailMessage", DSAF_STRING, 0, NULL, },
|
|
{ L"serverReferenceBL", DSAF_STRING, 0, NULL, },
|
|
{ L"rIDSetReferences", DSAF_STRING, 0, NULL, },
|
|
{ L"frsComputerReferenceBL", DSAF_STRING, 0, NULL, },
|
|
{ L"serverReference", DSAF_STRING, 0, NULL, },
|
|
{ L"mailAddress", DSAF_STRING, 0, NULL, },
|
|
{ L"msDS-HasInstantiatedNCs", DSAF_STRING, 0, NULL, },
|
|
{ L"msDS-HasDomainNCs", DSAF_STRING, 0, NULL, },
|
|
{ L"msDS-hasMasterNCs", DSAF_STRING, 0, NULL, },
|
|
{ L"hasMasterNCs", DSAF_STRING, 0, NULL, },
|
|
{ L"dMDLocation", DSAF_STRING, 0, NULL, },
|
|
{ L"userPrincipalName", DSAF_STRING, 0, NULL, },
|
|
{ L"mail", DSAF_STRING, 0, NULL, },
|
|
{ L"givenName", DSAF_STRING, 0, NULL, },
|
|
{ L"sn", 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 == LSTRCMPIS(pwsz, CERTTYPE_PROP_FLAGS))
|
|
{
|
|
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;
|
|
BYTE const *pb;
|
|
DWORD cb;
|
|
|
|
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);
|
|
}
|
|
cb = rgpberval[i]->bv_len;
|
|
pb = (BYTE const *) rgpberval[i]->bv_val;
|
|
|
|
if (0 == cb ||
|
|
(1 == cb && (0 == *pb || ' ' == *pb)))
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (SZARRAYSIZE(szPROPASNTAG) < cb &&
|
|
0 == _strnicmp(
|
|
(char const *) pb,
|
|
szPROPASNTAG,
|
|
SZARRAYSIZE(szPROPASNTAG)))
|
|
{
|
|
pb += SZARRAYSIZE(szPROPASNTAG);
|
|
cb -= SZARRAYSIZE(szPROPASNTAG);
|
|
}
|
|
|
|
hr = cuDumpAsnBinary(pb, cb, 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 == mylstrcmpiS(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 != mylstrcmpiL(pwszRevertCN, ppwszLdapVal[0]))
|
|
{
|
|
wprintf(L" -- %ws", ppwszLdapVal[0]);
|
|
}
|
|
wprintf(L"\n");
|
|
if (!g_fVerbose &&
|
|
NULL != pwszAlternateCN &&
|
|
0 != mylstrcmpiL(pwszRevertCN, pwszAlternateCN))
|
|
{
|
|
wprintf(L" %ws\n", pwszAlternateCN);
|
|
}
|
|
if (!g_fVerbose &&
|
|
NULL != pwszDisplayName &&
|
|
0 != mylstrcmpiL(pwszRevertCN, pwszDisplayName))
|
|
{
|
|
wprintf(L" %ws\n", pwszDisplayName);
|
|
}
|
|
}
|
|
|
|
if (DSDF_DELETE & dwFlags)
|
|
{
|
|
DeleteDN(
|
|
pld,
|
|
(DSDF_BASE & dwFlags)? NULL : 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(g_pwszDC, 0, &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 == LSTRCMPIS(awcType, L"CN="))
|
|
{
|
|
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(g_pwszDC, 0, &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 == mylstrcmpiL(pwszDisplayName, apwszCertTypeName[0]) ||
|
|
0 == mylstrcmpiL(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 = mylstrcmpiL(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 + sizeof(WCHAR));
|
|
if (NULL == pwszMachine)
|
|
{
|
|
_PrintError(E_OUTOFMEMORY, "LocalAlloc");
|
|
goto error;
|
|
}
|
|
CopyMemory(pwszMachine, pwszDnsName, cb);
|
|
pwszMachine[cb / sizeof(WCHAR)] = L'\0';
|
|
|
|
rc = mylstrcmpiL(pwszServer, pwszMachine);
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszMachine)
|
|
{
|
|
LocalFree(pwszMachine);
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
|
|
// Enumerate matching CAs
|
|
typedef HRESULT (FNENUMCA)(
|
|
IN HCAINFO hCAInfo,
|
|
IN OUT VOID *pvArgs);
|
|
|
|
HRESULT
|
|
dsEnumCA(
|
|
IN FNENUMCA *pfnEnumCA,
|
|
IN VOID *pvArgs)
|
|
{
|
|
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_NON_TEMPLATE_CA | 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;
|
|
}
|
|
if (NULL != g_pwszDC)
|
|
{
|
|
dwFlags |= CA_FLAG_SCOPE_DNS;
|
|
}
|
|
if (g_fForce)
|
|
{
|
|
dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
|
|
}
|
|
|
|
hr = CAFindByName(
|
|
pwszCANameSanitizedDS,
|
|
g_pwszDC, // 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 = (*pfnEnumCA)(hCAInfo, pvArgs);
|
|
_JumpIfError(hr, error, "*pfnEnumCA");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
// Display Templates for specified CA
|
|
|
|
typedef struct _CATEMPLATESARGS {
|
|
OPTIONAL IN WCHAR const *pwszTemplate;
|
|
} CATEMPLATESARGS;
|
|
|
|
|
|
HRESULT
|
|
dsEnumCADumpTemplate(
|
|
IN HCAINFO hCAInfo,
|
|
IN OUT VOID *pvArgs)
|
|
{
|
|
HRESULT hr;
|
|
CATEMPLATESARGS *pArgs = (CATEMPLATESARGS *) pvArgs;
|
|
|
|
hr = dsDumpTemplate(hCAInfo, pArgs->pwszTemplate, NULL);
|
|
_JumpIfError(hr, error, "dsDumpTemplate");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
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;
|
|
CATEMPLATESARGS Args;
|
|
|
|
Args.pwszTemplate = pwszTemplate;
|
|
|
|
hr = dsEnumCA(dsEnumCADumpTemplate, &Args);
|
|
_JumpIfError(hr, error, "dsEnumCA");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Set Templates for specified CA
|
|
|
|
typedef struct _CASETTEMPLATESARGS {
|
|
IN WCHAR const *pwszTemplateList;
|
|
} CASETTEMPLATESARGS;
|
|
|
|
#define SCTOP_SET 0
|
|
#define SCTOP_ADD 1
|
|
#define SCTOP_REMOVE 2
|
|
|
|
HRESULT
|
|
dsAddCATemplates(
|
|
IN HCAINFO hCAInfo,
|
|
IN DWORD Op,
|
|
IN WCHAR const * const *ppwszList)
|
|
{
|
|
HRESULT hr;
|
|
CTemplateList CATemplateList;
|
|
CTemplateListEnum CATemplateListEnum(CATemplateList);
|
|
BOOL fSkipCache = g_fForce;
|
|
BOOL fChanged = FALSE;
|
|
WCHAR const * const *ppwsz;
|
|
HCERTTYPE hCertType = NULL;
|
|
HCERTTYPE hCertTypeT;
|
|
WCHAR **apwszCertTypeCN = NULL;
|
|
WCHAR *pwszT = NULL;
|
|
|
|
hr = myRetrieveCATemplateList(hCAInfo, TRUE, CATemplateList);
|
|
_JumpIfError(hr, error, "myRetrieveCATemplateList");
|
|
|
|
CATemplateListEnum.Reset();
|
|
|
|
while (TRUE)
|
|
{
|
|
CTemplateInfo *pTemplateInfo;
|
|
|
|
pTemplateInfo = CATemplateListEnum.Next();
|
|
if (NULL == pTemplateInfo)
|
|
{
|
|
break;
|
|
}
|
|
hCertTypeT = pTemplateInfo->GetCertType();
|
|
if (NULL == hCertTypeT)
|
|
{
|
|
CSASSERT(NULL != pTemplateInfo->GetName());
|
|
hr = CAFindCertTypeByName(
|
|
pTemplateInfo->GetName(),
|
|
NULL,
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
(fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
|
|
&hCertType);
|
|
hCertTypeT = hCertType;
|
|
|
|
// continue on errors
|
|
|
|
_PrintIfErrorStr(
|
|
hr,
|
|
"CAFindCertTypeByName",
|
|
NULL != pTemplateInfo->GetName()?
|
|
pTemplateInfo->GetName() : pTemplateInfo->GetOID());
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
fSkipCache = FALSE;
|
|
}
|
|
}
|
|
if (NULL != hCertTypeT)
|
|
{
|
|
if (SCTOP_SET == Op)
|
|
{
|
|
BOOL fFound;
|
|
|
|
fFound = FALSE;
|
|
for (ppwsz = ppwszList; NULL != *ppwsz; ppwsz++)
|
|
{
|
|
if (0 == mylstrcmpiL(*ppwsz, pTemplateInfo->GetName()) ||
|
|
0 == lstrcmp(*ppwsz, pTemplateInfo->GetOID()))
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!fFound)
|
|
{
|
|
// can't reference pTemplateInfo after it's been removed
|
|
|
|
hr = myDupString(
|
|
NULL != pTemplateInfo->GetName()?
|
|
pTemplateInfo->GetName() :
|
|
pTemplateInfo->GetOID(),
|
|
&pwszT);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pTemplateInfo = NULL;
|
|
|
|
hr = myRemoveFromCATemplateList(
|
|
hCAInfo,
|
|
CATemplateList,
|
|
hCertTypeT);
|
|
_JumpIfError(hr, error, "myRemoveFromCATemplateList");
|
|
|
|
fChanged = TRUE;
|
|
wprintf(
|
|
L"%ws: %ws\n",
|
|
pwszT,
|
|
myLoadResourceString(IDS_REMOVING)); // "Removing"
|
|
LocalFree(pwszT);
|
|
pwszT = NULL;
|
|
CATemplateListEnum.Reset(); // start over to avoid faulting
|
|
}
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
CACloseCertType(hCertType);
|
|
hCertType = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (fChanged)
|
|
{
|
|
wprintf(wszNewLine);
|
|
}
|
|
for (ppwsz = ppwszList; NULL != *ppwsz; ppwsz++)
|
|
{
|
|
UINT idmsg;
|
|
|
|
hr = CAFindCertTypeByName(
|
|
*ppwsz,
|
|
NULL,
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
(fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
|
|
&hCertType);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(hr, "CAFindCertTypeByName", *ppwsz, hr);
|
|
|
|
hr = CAFindCertTypeByName(
|
|
*ppwsz,
|
|
NULL,
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
CT_FIND_BY_OID |
|
|
(fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
|
|
&hCertType);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintAPIError(*ppwsz, hr);
|
|
_JumpErrorStr(hr, error, "CAFindCertTypeByName", *ppwsz);
|
|
}
|
|
}
|
|
fSkipCache = FALSE;
|
|
hCertTypeT = hCertType;
|
|
hr = CAGetCertTypeProperty(
|
|
hCertTypeT,
|
|
CERTTYPE_PROP_CN,
|
|
&apwszCertTypeCN);
|
|
_JumpIfErrorStr(hr, error, "CAGetCertTypeProperty", *ppwsz);
|
|
|
|
idmsg = 0;
|
|
if (SCTOP_REMOVE == Op)
|
|
{
|
|
if (CATemplateList.TemplateExistsOID(*ppwsz) ||
|
|
CATemplateList.TemplateExistsName(*ppwsz))
|
|
{
|
|
idmsg = IDS_REMOVING; // "Removing"
|
|
hr = myRemoveFromCATemplateList(
|
|
hCAInfo,
|
|
CATemplateList,
|
|
hCertTypeT);
|
|
_JumpIfError(hr, error, "myRemoveFromCATemplateList");
|
|
|
|
fChanged = TRUE;
|
|
}
|
|
else
|
|
{
|
|
idmsg = IDS_NOTPRESENT; // "Not present"
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!CATemplateList.TemplateExistsOID(*ppwsz) &&
|
|
!CATemplateList.TemplateExistsName(*ppwsz))
|
|
{
|
|
idmsg = IDS_ADDING; // "Adding"
|
|
hr = myAddToCATemplateList(
|
|
hCAInfo,
|
|
CATemplateList,
|
|
hCertTypeT,
|
|
TRUE);
|
|
_JumpIfError(hr, error, "myAddToCATemplateList");
|
|
|
|
fChanged = TRUE;
|
|
}
|
|
else
|
|
{
|
|
idmsg = IDS_ALREADYPRESENT; // "Already present"
|
|
}
|
|
}
|
|
if (0 != idmsg)
|
|
{
|
|
hr = myVerifyObjId(*ppwsz);
|
|
if (S_OK == hr &&
|
|
NULL != apwszCertTypeCN &&
|
|
NULL != apwszCertTypeCN[0])
|
|
{
|
|
wprintf(L"%ws: ", apwszCertTypeCN[0]);
|
|
}
|
|
wprintf(L"%ws: %ws\n", *ppwsz, myLoadResourceString(idmsg));
|
|
}
|
|
if (NULL != apwszCertTypeCN)
|
|
{
|
|
CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
|
|
apwszCertTypeCN = NULL;
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
CACloseCertType(hCertType);
|
|
hCertType = NULL;
|
|
}
|
|
}
|
|
if (fChanged || g_fForce)
|
|
{
|
|
hr = myUpdateCATemplateListToCA(hCAInfo, CATemplateList);
|
|
_PrintIfError2(hr, "myUpdateCATemplateListToCA", hr);
|
|
if (S_OK != hr && g_fForce)
|
|
{
|
|
// if failed to update through the CA for any reason, try writing
|
|
// directly to DS
|
|
|
|
hr = myUpdateCATemplateListToDS(hCAInfo);
|
|
_JumpIfError(hr, error, "myUpdateCATemplateListToDS");
|
|
}
|
|
_JumpIfError(hr, error, "myUpdateCATemplateListToCA");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszT)
|
|
{
|
|
LocalFree(pwszT);
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
if (NULL != apwszCertTypeCN)
|
|
{
|
|
CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
|
|
}
|
|
CACloseCertType(hCertType);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
dsEnumCASetTemplates(
|
|
IN HCAINFO hCAInfo,
|
|
IN OUT VOID *pvArgs)
|
|
{
|
|
HRESULT hr;
|
|
CASETTEMPLATESARGS *pArgs = (CASETTEMPLATESARGS *) pvArgs;
|
|
DWORD Op = SCTOP_SET;
|
|
WCHAR const *pwszList;
|
|
WCHAR **ppwszList = NULL;
|
|
|
|
pwszList = pArgs->pwszTemplateList;
|
|
if (myIsMinusSign(*pwszList))
|
|
{
|
|
pwszList++;
|
|
Op = SCTOP_REMOVE;
|
|
}
|
|
else if (L'+' == *pwszList)
|
|
{
|
|
pwszList++;
|
|
Op = SCTOP_ADD;
|
|
}
|
|
hr = cuParseStrings(pwszList, FALSE, NULL, NULL, &ppwszList, NULL);
|
|
_JumpIfError(hr, error, "cuParseStrings");
|
|
|
|
hr = dsAddCATemplates(hCAInfo, Op, ppwszList);
|
|
_JumpIfError(hr, error, "dsAddCATemplates");
|
|
|
|
error:
|
|
cuFreeStringArray(ppwszList);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbSetCATemplates(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszTemplateList,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
CASETTEMPLATESARGS Args;
|
|
|
|
Args.pwszTemplateList = pwszTemplateList;
|
|
|
|
hr = dsEnumCA(dsEnumCASetTemplates, &Args);
|
|
_JumpIfError(hr, error, "dsEnumCA");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
dsCAFindByCertType(
|
|
IN WCHAR const *pwszTemplate,
|
|
OPTIONAL WCHAR const *pwszDC,
|
|
IN DWORD dwFlags,
|
|
OUT HCAINFO *phCAInfo)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszCertType = pwszTemplate;
|
|
WCHAR *pwszAlloc = NULL;
|
|
|
|
while (TRUE)
|
|
{
|
|
hr = CAFindByCertType(
|
|
pwszCertType,
|
|
pwszDC, // 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_NON_TEMPLATE_CA | CA_FIND_INCLUDE_UNTRUSTED;
|
|
WCHAR **apwszMachine = NULL;
|
|
WCHAR **apwszCommonName = NULL;
|
|
|
|
if (!g_fUserRegistry)
|
|
{
|
|
dwFlags |= CA_FIND_LOCAL_SYSTEM;
|
|
}
|
|
if (NULL != g_pwszDC)
|
|
{
|
|
dwFlags |= CA_FLAG_SCOPE_DNS;
|
|
}
|
|
hr = dsCAFindByCertType(pwszTemplate, g_pwszDC, 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 == mylstrcmpiS(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 == LSTRCMPIS(pInfValues->pwszKey, CERTTYPE_PROP_CN))
|
|
{
|
|
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(
|
|
g_pwszDC,
|
|
RLBF_REQUIRE_SECURE_LDAP,
|
|
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;
|
|
static WCHAR const * const s_apwszKeys[] =
|
|
{ wszINFKEY_TEMPLATE, NULL };
|
|
|
|
hr = myInfOpenFile(pwszfnTemplateInf, &hInf, &ErrorLine);
|
|
_JumpIfError(hr, error, "myInfOpenFIle");
|
|
|
|
hr = myInfGetKeyList(
|
|
hInf,
|
|
wszINFSECTION_TEMPLATELIST,
|
|
wszINFKEY_TEMPLATE,
|
|
s_apwszKeys,
|
|
&fCritical,
|
|
&pwszzTemplateList);
|
|
_JumpIfErrorStr(hr, error, "myInfGetKeyList", wszINFKEY_TEMPLATE);
|
|
|
|
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)
|
|
{
|
|
WCHAR *pwszT = myInfGetError();
|
|
|
|
if (NULL != pwszT)
|
|
{
|
|
wprintf(L"%ws\n", pwszT);
|
|
}
|
|
myInfCloseFile(hInf);
|
|
}
|
|
myLdapClose(pld, NULL, strConfigDN);
|
|
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_MACHINE 0x00000010
|
|
#define DSP_OBJECT_USER 0x00000020
|
|
#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 },
|
|
{ DSP_OBJECT_USER, NULL },
|
|
{ DSP_OBJECT_MACHINE, NULL },
|
|
};
|
|
|
|
HRESULT GetSubjectAltNameEntry(
|
|
CERT_CONTEXT const *pccCert,
|
|
DWORD dwAltNameChoice,
|
|
LPCSTR pcszOID,
|
|
LPWSTR *ppwszValue)
|
|
{
|
|
HRESULT hr;
|
|
PCERT_INFO pCertInfo = pccCert->pCertInfo;
|
|
CERT_ALT_NAME_INFO *pInfo = NULL;
|
|
CERT_NAME_VALUE *pNameValue = NULL;
|
|
DWORD cb;
|
|
|
|
bool fFound = false;
|
|
|
|
*ppwszValue = NULL;
|
|
|
|
for (DWORD i = 0; !fFound && i < pCertInfo->cExtension; i++)
|
|
{
|
|
if (0 == strcmp(pCertInfo->rgExtension[i].pszObjId, szOID_SUBJECT_ALT_NAME2))
|
|
{
|
|
// Decode to plain text
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_ALTERNATE_NAME,
|
|
pCertInfo->rgExtension[i].Value.pbData,
|
|
pCertInfo->rgExtension[i].Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pInfo,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
for(DWORD j=0; !fFound && j<pInfo->cAltEntry; j++)
|
|
{
|
|
if(dwAltNameChoice== pInfo->rgAltEntry[j].dwAltNameChoice)
|
|
{
|
|
switch(dwAltNameChoice)
|
|
{
|
|
case CERT_ALT_NAME_OTHER_NAME:
|
|
if(0==_stricmp(pcszOID, pInfo->rgAltEntry[j].pOtherName->pszObjId))
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
pInfo->rgAltEntry[j].pOtherName->Value.pbData,
|
|
pInfo->rgAltEntry[j].pOtherName->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pNameValue,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myDecodeObject");
|
|
}
|
|
|
|
hr = myDupString((LPWSTR)pNameValue->Value.pbData, ppwszValue);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
fFound = true;
|
|
}
|
|
break;
|
|
case CERT_ALT_NAME_RFC822_NAME:
|
|
hr = myDupString(pInfo->rgAltEntry[j].pwszRfc822Name, ppwszValue);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
fFound = true;
|
|
break;
|
|
case CERT_ALT_NAME_DNS_NAME:
|
|
hr = myDupString(pInfo->rgAltEntry[j].pwszDNSName, ppwszValue);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
fFound = true;
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!fFound)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
error:
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
}
|
|
if(pNameValue)
|
|
{
|
|
LocalFree(pNameValue);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
LocateUserOrMachineInDS(
|
|
IN CERT_CONTEXT const *pccCert,
|
|
IN DWORD dwObjectType,
|
|
OUT LPWSTR *ppwszURL)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
HANDLE hDS = NULL;
|
|
PDOMAIN_CONTROLLER_INFO pDCI = NULL;
|
|
PDS_NAME_RESULT pName = NULL;
|
|
LPCWSTR pwszDC;
|
|
LPWSTR pwszSearchName = NULL;
|
|
LPCWSTR pcwszAttribute;
|
|
LPCWSTR pcwszObjectCategory =
|
|
(LPC_USEROBJECT==dwObjectType)?wszDSUSERCLASSNAME:wszDSMACHINECLASSNAME;
|
|
LDAP *pld = NULL;
|
|
LPCWSTR pcwszFormat = L"(&(objectCategory=%s)(%s=%s))";
|
|
LPWSTR pwszUserFilter = NULL;
|
|
|
|
CSASSERT(dwObjectType==LPC_USEROBJECT || dwObjectType==LPC_MACHINEOBJECT);
|
|
|
|
// DSCrackNames first
|
|
|
|
if(dwObjectType == LPC_USEROBJECT)
|
|
{
|
|
// look for UPN is subject alt name
|
|
hr = GetSubjectAltNameEntry(
|
|
pccCert,
|
|
CERT_ALT_NAME_OTHER_NAME,
|
|
szOID_NT_PRINCIPAL_NAME,
|
|
&pwszSearchName);
|
|
if(S_OK==hr)
|
|
{
|
|
hr = DsGetDcName(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DS_GC_SERVER_REQUIRED,
|
|
&pDCI);
|
|
_JumpIfError(hr, error, "DsGetDCName");
|
|
|
|
pwszDC = pDCI->DomainControllerName;
|
|
while (*pwszDC == L'\\')
|
|
{
|
|
pwszDC++;
|
|
}
|
|
|
|
hr = DsBind(pwszDC, NULL, &hDS);
|
|
_JumpIfError(hr, error, "DSBind");
|
|
|
|
hr = DsCrackNames(
|
|
hDS,
|
|
DS_NAME_NO_FLAGS,
|
|
DS_USER_PRINCIPAL_NAME,
|
|
DS_FQDN_1779_NAME,
|
|
1,
|
|
&pwszSearchName,
|
|
&pName);
|
|
|
|
if(S_OK==hr && pName->cItems>0 && pName->rItems[0].pName)
|
|
{
|
|
hr = myDupString(pName->rItems[0].pName, ppwszURL);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Not found yet? Try other fields
|
|
if(NULL == *ppwszURL)
|
|
{
|
|
if(dwObjectType == LPC_USEROBJECT)
|
|
{
|
|
// look for email is subject alt name
|
|
hr = GetSubjectAltNameEntry(
|
|
pccCert,
|
|
CERT_ALT_NAME_RFC822_NAME,
|
|
NULL,
|
|
&pwszSearchName);
|
|
_PrintIfError(hr, "GetSubjectAltNameEntry");
|
|
|
|
if(S_OK != hr)
|
|
{
|
|
hr = myGetRDNAttributeFromNameBlob(
|
|
&pccCert->pCertInfo->Subject,
|
|
szOID_RSA_emailAddr,
|
|
&pwszSearchName);
|
|
_PrintIfError(hr, "myGetRDNAttributeFromNameBlob");
|
|
}
|
|
|
|
if(S_OK==hr)
|
|
{
|
|
pcwszAttribute = wszDSMAILATTRIBUTE;
|
|
}
|
|
}
|
|
else // LPC_MACHINEOBJECT
|
|
{
|
|
// look for DNS name in subject alt name
|
|
hr = GetSubjectAltNameEntry(
|
|
pccCert,
|
|
CERT_ALT_NAME_DNS_NAME,
|
|
NULL,
|
|
&pwszSearchName);
|
|
_PrintIfError(hr, "GetSubjectAltNameEntry");
|
|
|
|
if(S_OK != hr)
|
|
{
|
|
hr = myGetCommonName(
|
|
&pccCert->pCertInfo->Subject,
|
|
FALSE,
|
|
&pwszSearchName);
|
|
_PrintIfError(hr, "myGetCommonName");
|
|
}
|
|
|
|
if(S_OK==hr)
|
|
{
|
|
pcwszAttribute = wszDSDNSHOSTNAMEATTRIBUTE;
|
|
}
|
|
}
|
|
|
|
// Found a suitable name? Search the global catalog for the matching object.
|
|
if(NULL != pwszSearchName)
|
|
{
|
|
hr = myLdapOpen(
|
|
NULL, // pwszDomainName
|
|
RLBF_REQUIRE_GC | RLBF_REQUIRE_SECURE_LDAP,
|
|
&pld,
|
|
NULL, // pstrDomainDN
|
|
NULL); // pstrConfigDN
|
|
_JumpIfError(hr, error, "myLdapOpen");
|
|
|
|
if(dwObjectType == LPC_USEROBJECT)
|
|
{
|
|
// build the search filter, e.g.
|
|
// (&(objectCategory=user)([email protected]))
|
|
|
|
pwszUserFilter = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*
|
|
(wcslen(pcwszFormat)+wcslen(pcwszObjectCategory)+
|
|
wcslen(pcwszAttribute)+wcslen(pwszSearchName)+1));
|
|
_JumpIfAllocFailed(pwszUserFilter, error);
|
|
|
|
wsprintf(pwszUserFilter, pcwszFormat,
|
|
pcwszObjectCategory, pcwszAttribute, pwszSearchName);
|
|
|
|
hr = myLdapFindObjectInForest(
|
|
pld,
|
|
pwszUserFilter,
|
|
ppwszURL);
|
|
_PrintIfErrorStr(hr, "myLdapFindObjectInForest", pwszUserFilter);
|
|
}
|
|
else
|
|
{
|
|
hr = myLdapFindComputerInForest(
|
|
pld,
|
|
pwszSearchName,
|
|
ppwszURL);
|
|
_PrintIfErrorStr(hr, "myLdapFindMachineInForest", pwszSearchName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(NULL == *ppwszURL)
|
|
{
|
|
hr = CRYPT_E_NOT_FOUND;
|
|
_JumpError(hr, error, "Could not find a matching DS object to publish to");
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hDS)
|
|
{
|
|
DsUnBind(&hDS);
|
|
}
|
|
if(pDCI)
|
|
{
|
|
NetApiBufferFree(pDCI);
|
|
}
|
|
if(pName)
|
|
{
|
|
DsFreeNameResult(pName);
|
|
}
|
|
if(pwszSearchName)
|
|
{
|
|
LocalFree(pwszSearchName);
|
|
}
|
|
myLdapClose(pld, NULL, NULL);
|
|
if(pwszUserFilter)
|
|
{
|
|
LocalFree(pwszUserFilter);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
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(
|
|
g_pwszDC,
|
|
RLBF_REQUIRE_SECURE_LDAP,
|
|
&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;
|
|
|
|
if (NULL != pwszTemplate)
|
|
{
|
|
hr = myFormatCertsrvStringArray(
|
|
FALSE, // fURL
|
|
pwszServerName, // pwszServerName_p1_2
|
|
pwszSanitizedCN,// pwszSanitizedName_p3_7
|
|
0, // iCert_p4
|
|
MAXDWORD, // iCertTarget_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");
|
|
}
|
|
else
|
|
{
|
|
// user and machine objects don't have predefined DS location, we
|
|
// need to search for it based on information from the cert
|
|
|
|
hr = LocateUserOrMachineInDS(pccPublish, dwObjectType, &pwszURL);
|
|
if (S_OK != hr)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_ERR_CANNOT_FIND_MATCHING_OBJ));
|
|
}
|
|
_JumpIfError(hr, error, "LocateObjectInDS");
|
|
}
|
|
|
|
wprintf(L"%ws?%ws\n\n", pwszURL, pwszAttribute);
|
|
if (g_fForce)
|
|
{
|
|
dwObjectType |= LPC_CREATECONTAINER | LPC_CREATEOBJECT;
|
|
}
|
|
|
|
hr = myLdapPublishCertToDS(
|
|
pld,
|
|
pccPublish,
|
|
pwszURL,
|
|
pwszAttribute,
|
|
dwObjectType,
|
|
FALSE, // fDelete
|
|
&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);
|
|
|
|
if (dspFlags & DSP_OBJECT_AIA)
|
|
{
|
|
hr = myLdapFilterCertificates(
|
|
pld,
|
|
pwszURL,
|
|
pwszAttribute,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_JumpIfErrorStr(hr, error, "myLdapFilterCertificates", pwszURL);
|
|
}
|
|
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(
|
|
g_pwszDC,
|
|
RLBF_REQUIRE_SECURE_LDAP,
|
|
&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;
|
|
CAutoLPWSTR pwszCertTypeNameV1;
|
|
|
|
*pfCrossCA = FALSE;
|
|
|
|
// CrossCA is a V2 template, so only fetch the template OID
|
|
|
|
hr = cuGetCertType(
|
|
pCertContext->pCertInfo,
|
|
&pwszCertTypeNameV1,// 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;
|
|
}
|
|
|
|
if(((LPWSTR)NULL)!=pwszCertTypeNameV1&&
|
|
0 == LSTRCMPIS(pwszCertTypeNameV1, wszCERTTYPE_CROSS_CA))
|
|
{
|
|
*pfCrossCA = TRUE;
|
|
}
|
|
else
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwszObjId,
|
|
NULL,
|
|
CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES | 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,
|
|
};
|
|
|
|
|
|
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
|
|
IsMachineCert(
|
|
IN CERT_CONTEXT const *pCertContext,
|
|
OUT BOOL *pfMachine)
|
|
{
|
|
HRESULT hr;
|
|
HCERTTYPE hCertType = NULL;
|
|
CERT_EXTENSION *pExt;
|
|
CERT_TEMPLATE_EXT *pTemplate = NULL;
|
|
CERT_NAME_VALUE *pbName = NULL;
|
|
LPWSTR pwszTemplate = NULL;
|
|
DWORD dwTemplateFlags;
|
|
DWORD cb;
|
|
bool fNameIsOID;
|
|
|
|
*pfMachine = FALSE;
|
|
pExt = CertFindExtension(
|
|
szOID_CERTIFICATE_TEMPLATE,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension);
|
|
|
|
if (NULL != pExt)
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pTemplate,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
if (!ConvertSzToWsz(&pwszTemplate, pTemplate->pszObjId, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToWsz");
|
|
}
|
|
fNameIsOID = true;
|
|
}
|
|
else
|
|
{
|
|
// try v1 template extension
|
|
|
|
pExt = CertFindExtension(
|
|
szOID_ENROLL_CERTTYPE_EXTENSION,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension);
|
|
if(pExt)
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbName,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
hr = myDupString((LPWSTR)pbName->Value.pbData, &pwszTemplate);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
fNameIsOID = false;
|
|
}
|
|
}
|
|
|
|
if(pwszTemplate)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwszTemplate,
|
|
NULL,
|
|
(fNameIsOID?CT_FIND_BY_OID:0) |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES,
|
|
&hCertType);
|
|
|
|
if(S_OK==hr)
|
|
{
|
|
hr = CAGetCertTypeFlagsEx(
|
|
hCertType,
|
|
CERTTYPE_GENERAL_FLAG,
|
|
&dwTemplateFlags);
|
|
}
|
|
|
|
if(S_OK==hr)
|
|
{
|
|
*pfMachine = (dwTemplateFlags & CT_FLAG_MACHINE_TYPE)?TRUE:FALSE;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hCertType)
|
|
{
|
|
CACloseCertType(hCertType);
|
|
}
|
|
LOCAL_FREE(pTemplate);
|
|
LOCAL_FREE(pbName);
|
|
LOCAL_FREE(pwszTemplate);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
dsPublishCertFromContext(
|
|
IN CERT_CONTEXT const *pCertContext,
|
|
OPTIONAL IN WCHAR const *pwszType)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fCrossCA;
|
|
BOOL fCA;
|
|
BOOL fKRA;
|
|
BOOL fRoot;
|
|
BOOL fMachine;
|
|
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");
|
|
|
|
hr = IsMachineCert(pCertContext, &fMachine);
|
|
_JumpIfError(hr, error, "IsMachineCert");
|
|
|
|
fRoot = CertCompareCertificateName(
|
|
X509_ASN_ENCODING,
|
|
&pCertContext->pCertInfo->Subject,
|
|
&pCertContext->pCertInfo->Issuer);
|
|
|
|
dwObjectType = LPC_CAOBJECT;
|
|
if (NULL == pwszType || myIsMinusSignString(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;
|
|
}
|
|
else
|
|
if(fMachine)
|
|
{
|
|
dspFlags =
|
|
DSP_OBJECT_MACHINE |
|
|
DSP_ATTRIBUTE_USERCERTIFICATE |
|
|
DSP_TYPE_EECERT;
|
|
dwObjectType = LPC_MACHINEOBJECT;
|
|
}
|
|
else
|
|
{
|
|
dspFlags =
|
|
DSP_OBJECT_USER |
|
|
DSP_ATTRIBUTE_USERCERTIFICATE |
|
|
DSP_TYPE_EECERT;
|
|
dwObjectType = LPC_USEROBJECT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 == LSTRCMPIS(pwszType, L"NTAuthCA"))
|
|
{
|
|
dspFlags = DSP_OBJECT_NTAUTHCERT |
|
|
DSP_ATTRIBUTE_CACERTIFICATE |
|
|
DSP_TYPE_ROOTCACERT |
|
|
DSP_TYPE_SUBCACERT;
|
|
pwszSanitizedCN = L"NTAuthCertificates";
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszType, L"RootCA"))
|
|
{
|
|
dspFlags = DSP_OBJECT_AIA |
|
|
DSP_OBJECT_ROOTTRUST |
|
|
DSP_ATTRIBUTE_CACERTIFICATE |
|
|
DSP_TYPE_ROOTCACERT;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszType, L"SubCA"))
|
|
{
|
|
dspFlags = DSP_OBJECT_AIA |
|
|
DSP_ATTRIBUTE_CACERTIFICATE |
|
|
DSP_TYPE_SUBCACERT;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszType, L"CrossCA"))
|
|
{
|
|
// 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 == LSTRCMPIS(pwszType, L"KRA"))
|
|
{
|
|
dspFlags = DSP_OBJECT_KRA |
|
|
DSP_ATTRIBUTE_USERCERTIFICATE |
|
|
DSP_TYPE_KRACERT |
|
|
DSP_TYPE_EECERT;
|
|
dwObjectType = LPC_KRAOBJECT;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszType, L"User"))
|
|
{
|
|
dspFlags = DSP_OBJECT_USER |
|
|
DSP_ATTRIBUTE_USERCERTIFICATE |
|
|
DSP_TYPE_EECERT;
|
|
dwObjectType = LPC_USEROBJECT;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszType, L"Machine"))
|
|
{
|
|
dspFlags = DSP_OBJECT_MACHINE |
|
|
DSP_ATTRIBUTE_USERCERTIFICATE |
|
|
DSP_TYPE_EECERT;
|
|
dwObjectType = LPC_MACHINEOBJECT;
|
|
}
|
|
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 = myGetCommonName(
|
|
fCA?
|
|
&pCertContext->pCertInfo->Subject :
|
|
&pCertContext->pCertInfo->Issuer,
|
|
TRUE,
|
|
&pwszCN);
|
|
_JumpIfError(hr, error, "myGetCommonName");
|
|
|
|
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)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_ERROR_EXTENSION_MISSING));
|
|
wprintf(wszNewLine);
|
|
hr = HRESULT_FROM_WIN32(ERROR_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 != LSTRCMPIS(awcLDAP, wszLDAPCOLON))
|
|
{
|
|
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 *pwszSanitizedCNAlloc2 = 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(
|
|
g_pwszDC,
|
|
RLBF_REQUIRE_SECURE_LDAP,
|
|
&pld,
|
|
&strDomainDN,
|
|
&strConfigDN);
|
|
_JumpIfError(hr, error, "myLdapOpen");
|
|
|
|
if (NULL == pwszSanitizedCN)
|
|
{
|
|
hr = myGetCommonName(&pCRLContext->pCrlInfo->Issuer, FALSE, &pwszCN);
|
|
_JumpIfError(hr, error, "myGetCommonName");
|
|
|
|
hr = mySanitizeName(pwszCN, &pwszSanitizedCNAlloc);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
pwszSanitizedCN = pwszSanitizedCNAlloc;
|
|
}
|
|
if (MAXDWORD == dsGetNumericSuffix(pwszSanitizedCN))
|
|
{
|
|
CERT_EXTENSION *pExt;
|
|
|
|
pExt = CertFindExtension(
|
|
szOID_CERTSRV_CA_VERSION,
|
|
pCRLContext->pCrlInfo->cExtension,
|
|
pCRLContext->pCrlInfo->rgExtension);
|
|
if (NULL != pExt)
|
|
{
|
|
DWORD NameId;
|
|
DWORD cb;
|
|
WCHAR const *pwsz;
|
|
|
|
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
|
|
MAXDWORD, // iCertTarget_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 != pwszSanitizedCNAlloc2)
|
|
{
|
|
LocalFree(pwszSanitizedCNAlloc2);
|
|
}
|
|
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 = myGetLong(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 = GetUserDefaultUILanguage();
|
|
if (0 == dwLanguageId)
|
|
{
|
|
dwLanguageId = GetSystemDefaultUILanguage();
|
|
}
|
|
if (g_fVerbose)
|
|
{
|
|
wprintf(
|
|
L"%ws: %x (%u)\n",
|
|
myLoadResourceString(IDS_SYSLANGID_COLON), // "System default Language Id:"
|
|
dwLanguageId,
|
|
dwLanguageId);
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszType)
|
|
{
|
|
hr = myGetLong(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(
|
|
g_pwszDC,
|
|
NULL != pwszDisplayName? RLBF_REQUIRE_SECURE_LDAP : 0,
|
|
&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 (0 == LSTRCMPIS(pwszDisplayName, L"delete"))
|
|
{
|
|
pwszDisplayName = NULL; // delete existing entry
|
|
}
|
|
if (fObjectExists)
|
|
{
|
|
if (fLangIdExists)
|
|
{
|
|
if (!g_fForce && NULL != pwszDisplayName)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
|
|
_JumpError(hr, error, "ldap_get_values");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NULL == pwszDisplayName)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "not found");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!g_fForce || NULL == pwszDisplayName)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "ldap_first/next_entry");
|
|
}
|
|
}
|
|
//wprintf(L"%u: %u,%ws\n", dwType, dwLanguageId, pwszDisplayName);
|
|
if (!fObjectExists)
|
|
{
|
|
CSASSERT(NULL != pwszDisplayName);
|
|
if (MAXDWORD == dwType)
|
|
{
|
|
dwType = CERT_OID_TYPE_TEMPLATE;
|
|
}
|
|
hr = myLdapCreateOIDObject(
|
|
pld,
|
|
pwszOIDDN,
|
|
dwType,
|
|
pwszObjId,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_JumpIfError(hr, error, "myLdapCreateOIDObject");
|
|
|
|
CSASSERT(NULL == pwszError);
|
|
}
|
|
hr = myLdapAddOrDeleteOIDDisplayNameToAttribute(
|
|
pld,
|
|
ppwszLdapVal,
|
|
dwLanguageId,
|
|
pwszDisplayName,
|
|
pwszOIDDN,
|
|
OID_PROP_LOCALIZED_NAME,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_JumpIfError(hr, error, "myLdapAddOrDeleteOIDDisplayNameToAttribute");
|
|
|
|
wprintf(wszNewLine);
|
|
if (LDAP_SUCCESS == dwDisposition)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(
|
|
NULL == pwszDisplayName?
|
|
IDS_FORMAT_DELETED_FROM_DS_STORE : // "%ws deleted from DS store."
|
|
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);
|
|
CSASSERT(NULL != pwszDisplayName);
|
|
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);
|
|
}
|
|
|
|
|
|
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;
|
|
LPCWSTR pcwszGlobal = L"Global\\";
|
|
CAutoLPWSTR pwszEvent;
|
|
|
|
pwszEvent = (LPWSTR) LocalAlloc(LMEM_FIXED,
|
|
sizeof(WCHAR)*(1+wcslen(pcwszGlobal)+
|
|
wcslen(MACHINE_AUTOENROLLMENT_TRIGGER_EVENT)));
|
|
_JumpIfAllocFailed(pwszEvent, error);
|
|
|
|
wcscpy(pwszEvent, pcwszGlobal);
|
|
wcscat(pwszEvent, MACHINE_AUTOENROLLMENT_TRIGGER_EVENT);
|
|
|
|
hEventAE = OpenEvent(
|
|
EVENT_MODIFY_STATE,
|
|
FALSE,
|
|
pwszEvent);
|
|
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" %ws\n", prgVal[i]);
|
|
}
|
|
|
|
if (0 == LSTRCMPIS(pwszAttrName, CA_PROP_DNSNAME))
|
|
{
|
|
prgDNS = prgVal;
|
|
}
|
|
else if (0 == LSTRCMPIS(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);
|
|
_PrintIfError(hr, "cuGetGroupMembership");
|
|
hr = S_OK;
|
|
|
|
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);
|
|
}
|