//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1995 - 1999 // // File: ds.cpp // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include #include #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(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(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(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(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(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 && jcAltEntry; 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)(mail=bogdant@microsoft.com)) 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(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); }