//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: ldap.cpp // //--------------------------------------------------------------------------- #include #pragma hdrstop #undef LdapMapErrorToWin32 #include #define LdapMapErrorToWin32 Use_myHLdapError_Instead_Of_LdapMapErrorToWin32 #include #include "csldap.h" #include "certacl.h" #include "certtype.h" #include "cainfop.h" #include "csber.h" static CHAR s_sdBerValue[] = { BER_SEQUENCE, 3 * sizeof(BYTE), // three byte sequence BER_INTEGER, 1 * sizeof(BYTE), // of one-byte integer DACL_SECURITY_INFORMATION //OWNER_SECURITY_INFORMATION | //GROUP_SECURITY_INFORMATION }; static LDAPControl s_se_info_control = { LDAP_SERVER_SD_FLAGS_OID_W, { ARRAYSIZE(s_sdBerValue), s_sdBerValue }, TRUE }; LDAPControl *g_rgLdapControls[2] = { &s_se_info_control, NULL }; // Revocation templates WCHAR const g_wszHTTPRevocationURLTemplate[] = // Fetch CRL via http: L"http://" wszFCSAPARM_SERVERDNSNAME L"/CertEnroll/" wszFCSAPARM_SANITIZEDCANAME wszFCSAPARM_CRLFILENAMESUFFIX wszFCSAPARM_CRLDELTAFILENAMESUFFIX L".crl"; WCHAR const g_wszFILERevocationURLTemplate[] = // Fetch CRL via file: L"file://\\\\" wszFCSAPARM_SERVERDNSNAME L"\\CertEnroll\\" wszFCSAPARM_SANITIZEDCANAME wszFCSAPARM_CRLFILENAMESUFFIX wszFCSAPARM_CRLDELTAFILENAMESUFFIX L".crl"; WCHAR const g_wszASPRevocationURLTemplate[] = // ASP revocation check via https: L"https://" wszFCSAPARM_SERVERDNSNAME L"/CertEnroll/nsrev_" wszFCSAPARM_SANITIZEDCANAME L".asp"; #define wszCDPDNTEMPLATE \ L"CN=" \ wszFCSAPARM_SANITIZEDCANAMEHASH \ wszFCSAPARM_CRLFILENAMESUFFIX \ L"," \ L"CN=" \ wszFCSAPARM_SERVERSHORTNAME \ L"," \ L"CN=CDP," \ L"CN=Public Key Services," \ L"CN=Services," \ wszFCSAPARM_CONFIGDN WCHAR const g_wszzLDAPRevocationURLTemplate[] = // Fetch CRL via ldap: L"ldap:///" wszCDPDNTEMPLATE wszFCSAPARM_DSCRLATTRIBUTE L"\0"; // Publish CRL via ldap: WCHAR const g_wszCDPDNTemplate[] = wszCDPDNTEMPLATE; // AIA templates WCHAR const g_wszHTTPIssuerCertURLTemplate[] = // Fetch CA Cert via http: L"http://" wszFCSAPARM_SERVERDNSNAME L"/CertEnroll/" wszFCSAPARM_SERVERDNSNAME L"_" wszFCSAPARM_SANITIZEDCANAME wszFCSAPARM_CERTFILENAMESUFFIX L".crt" L"\0"; WCHAR const g_wszFILEIssuerCertURLTemplate[] = // Fetch CA Cert via http: L"file://\\\\" wszFCSAPARM_SERVERDNSNAME L"\\CertEnroll\\" wszFCSAPARM_SERVERDNSNAME L"_" wszFCSAPARM_SANITIZEDCANAME wszFCSAPARM_CERTFILENAMESUFFIX L".crt" L"\0"; #define wszAIADNTEMPLATE \ L"CN=" \ wszFCSAPARM_SANITIZEDCANAMEHASH \ L"," \ L"CN=AIA," \ L"CN=Public Key Services," \ L"CN=Services," \ wszFCSAPARM_CONFIGDN WCHAR const g_wszzLDAPIssuerCertURLTemplate[] = // Fetch CA Cert via ldap: L"ldap:///" wszAIADNTEMPLATE wszFCSAPARM_DSCACERTATTRIBUTE L"\0"; // Publish CA Cert via ldap: WCHAR const g_wszAIADNTemplate[] = wszAIADNTEMPLATE; #define wszNTAUTHDNTEMPLATE \ L"CN=NTAuthCertificates," \ L"CN=Public Key Services," \ L"CN=Services," \ wszFCSAPARM_CONFIGDN WCHAR const g_wszLDAPNTAuthURLTemplate[] = // Fetch NTAuth Certs via ldap: L"ldap:///" wszNTAUTHDNTEMPLATE wszFCSAPARM_DSCACERTATTRIBUTE; #define wszROOTTRUSTDNTEMPLATE \ L"CN=" \ wszFCSAPARM_SANITIZEDCANAMEHASH \ L"," \ L"CN=Certification Authorities," \ L"CN=Public Key Services," \ L"CN=Services," \ wszFCSAPARM_CONFIGDN WCHAR const g_wszLDAPRootTrustURLTemplate[] = // Fetch Root Certs via ldap: L"ldap:///" wszROOTTRUSTDNTEMPLATE wszFCSAPARM_DSCACERTATTRIBUTE; #define wszKRADNTEMPLATE \ L"CN=" \ wszFCSAPARM_SANITIZEDCANAMEHASH \ L"," \ L"CN=KRA," \ L"CN=Public Key Services," \ L"CN=Services," \ wszFCSAPARM_CONFIGDN WCHAR const g_wszzLDAPKRACertURLTemplate[] = // Fetch KRA Cert via ldap: L"ldap:///" wszKRADNTEMPLATE wszFCSAPARM_DSKRACERTATTRIBUTE L"\0"; // Publish KRA Certs via ldap: WCHAR const g_wszKRADNTemplate[] = wszKRADNTEMPLATE; //+-------------------------------------------------------------------------- // // Routine Description: // This routine simply queries the operational attributes for the // domaindn and configdn. // // The strings returned by this routine must be freed by the caller // using SysFreeString // // Parameters: // pld -- a valid handle to an ldap session // pstrDomainDN -- a pointer to a string to be allocated in this routine // pstrConfigDN -- a pointer to a string to be allocated in this routine // // Return Values: // HRESULT for operation error. // //--------------------------------------------------------------------------- HRESULT myGetAuthoritativeDomainDn( IN LDAP *pld, OPTIONAL OUT BSTR *pstrDomainDN, OPTIONAL OUT BSTR *pstrConfigDN) { HRESULT hr; LDAPMessage *pSearchResult = NULL; LDAPMessage *pEntry; WCHAR *pwszAttrName; BerElement *pber; WCHAR **rgpwszValues; WCHAR *apwszAttrArray[3]; WCHAR *pwszDefaultNamingContext = L"defaultNamingContext"; WCHAR *pwszConfigurationNamingContext = L"configurationNamingContext"; WCHAR *pwszObjectClassFilter = L"objectClass=*"; BSTR strDomainDN = NULL; BSTR strConfigDN = NULL; // Set the OUT parameters to NULL if (NULL != pstrConfigDN) { *pstrConfigDN = NULL; } if (NULL != pstrDomainDN) { *pstrDomainDN = NULL; } // Query for the ldap server oerational attributes to obtain the default // naming context. apwszAttrArray[0] = pwszDefaultNamingContext; apwszAttrArray[1] = pwszConfigurationNamingContext; apwszAttrArray[2] = NULL; // this is the sentinel hr = ldap_search_s( pld, NULL, LDAP_SCOPE_BASE, pwszObjectClassFilter, apwszAttrArray, FALSE, &pSearchResult); hr = myHLdapError(pld, hr, NULL); _JumpIfError(hr, error, "ldap_search_sW"); pEntry = ldap_first_entry(pld, pSearchResult); if (NULL == pEntry) { hr = myHLdapLastError(pld, NULL); _JumpError(hr, error, "ldap_first_entry"); } pwszAttrName = ldap_first_attribute(pld, pEntry, &pber); while (NULL != pwszAttrName) { BSTR *pstr = NULL; if (NULL != pstrDomainDN && 0 == lstrcmpi(pwszAttrName, pwszDefaultNamingContext)) { pstr = &strDomainDN; } else if (NULL != pstrConfigDN && 0 == lstrcmpi(pwszAttrName, pwszConfigurationNamingContext)) { pstr = &strConfigDN; } if (NULL != pstr && NULL == *pstr) { rgpwszValues = ldap_get_values(pld, pEntry, pwszAttrName); if (NULL != rgpwszValues) { if (NULL != rgpwszValues[0]) { *pstr = SysAllocString(rgpwszValues[0]); if (NULL == *pstr) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "SysAllocString"); } } ldap_value_free(rgpwszValues); } } ldap_memfree(pwszAttrName); pwszAttrName = ldap_next_attribute(pld, pEntry, pber); } if ((NULL != pstrDomainDN && NULL == strDomainDN) || (NULL != pstrConfigDN && NULL == strConfigDN)) { // We couldn't get default domain info - bail out hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO); _JumpError(hr, error, "missing domain info"); } if (NULL != pstrDomainDN) { *pstrDomainDN = strDomainDN; strDomainDN = NULL; } if (NULL != pstrConfigDN) { *pstrConfigDN = strConfigDN; strConfigDN = NULL; } hr = S_OK; error: if (NULL != pSearchResult) { ldap_msgfree(pSearchResult); } myLdapClose(NULL, strDomainDN, strConfigDN); return(hr); } HRESULT myDomainFromDn( IN WCHAR const *pwszDN, OPTIONAL OUT WCHAR **ppwszDomainDNS) { HRESULT hr; DWORD cwcOut; WCHAR *pwszOut; WCHAR **ppwszExplodedDN = NULL; WCHAR **ppwsz; WCHAR wszDC[4]; WCHAR *pwsz; *ppwszDomainDNS = NULL; ppwszExplodedDN = ldap_explode_dn(const_cast(pwszDN), 0); if (NULL == ppwszExplodedDN) { hr = myHLdapLastError(NULL, NULL); _JumpError(hr, error, "ldap_explode_dn"); } cwcOut = 0; for (ppwsz = ppwszExplodedDN; NULL != *ppwsz; ppwsz++) { pwsz = *ppwsz; wcsncpy(wszDC, pwsz, ARRAYSIZE(wszDC) - 1); wszDC[ARRAYSIZE(wszDC) - 1] = L'\0'; if (0 == lstrcmpi(wszDC, L"DC=")) { pwsz += ARRAYSIZE(wszDC) - 1; if (0 != cwcOut) { cwcOut++; } cwcOut += wcslen(pwsz); } } pwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwcOut + 1) * sizeof(WCHAR)); if (NULL == pwszOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } *ppwszDomainDNS = pwszOut; for (ppwsz = ppwszExplodedDN; NULL != *ppwsz; ppwsz++) { pwsz = *ppwsz; wcsncpy(wszDC, pwsz, ARRAYSIZE(wszDC) - 1); wszDC[ARRAYSIZE(wszDC) - 1] = L'\0'; if (0 == lstrcmpi(wszDC, L"DC=")) { pwsz += ARRAYSIZE(wszDC) - 1; if (pwszOut != *ppwszDomainDNS) { *pwszOut++ = L'.'; } wcscpy(pwszOut, pwsz); pwszOut += wcslen(pwsz); } } CSASSERT(wcslen(*ppwszDomainDNS) == cwcOut); hr = S_OK; error: if (NULL != ppwszExplodedDN) { ldap_value_free(ppwszExplodedDN); } return(hr); } HRESULT myLdapOpen( OUT LDAP **ppld, OPTIONAL OUT BSTR *pstrDomainDN, OPTIONAL OUT BSTR *pstrConfigDN) { HRESULT hr; LDAP *pld = NULL; *ppld = NULL; CSASSERT(NULL == pstrConfigDN || NULL == *pstrConfigDN); CSASSERT(NULL == pstrDomainDN || NULL == *pstrDomainDN); hr = myRobustLdapBind(&pld, FALSE); _JumpIfError(hr, error, "myRobustLdapBind"); // domain and config containers (%5, %6) hr = myGetAuthoritativeDomainDn(pld, pstrDomainDN, pstrConfigDN); if (S_OK != hr) { hr = myHError(hr); _JumpError(hr, error, "myGetAuthoritativeDomainDn"); } *ppld = pld; pld = NULL; error: if (NULL != pld) { ldap_unbind(pld); } return(hr); } VOID myLdapClose( OPTIONAL IN LDAP *pld, OPTIONAL IN BSTR strDomainDN, OPTIONAL IN BSTR strConfigDN) { if (NULL != strDomainDN) { SysFreeString(strDomainDN); } if (NULL != strConfigDN) { SysFreeString(strConfigDN); } if (NULL != pld) { ldap_unbind(pld); } } BOOL myLdapRebindRequired( IN ULONG ldaperrParm, OPTIONAL IN LDAP *pld) { BOOL fRebindRequired = FALSE; if (LDAP_SERVER_DOWN == ldaperrParm || LDAP_UNAVAILABLE == ldaperrParm || LDAP_TIMEOUT == ldaperrParm || NULL == pld) { fRebindRequired = TRUE; } else { ULONG ldaperr; VOID *pvReachable = NULL; // clear high bits for 64-bit machines ldaperr = ldap_get_option(pld, LDAP_OPT_HOST_REACHABLE, &pvReachable); if (LDAP_SUCCESS != ldaperr || LDAP_OPT_ON != pvReachable) { fRebindRequired = TRUE; } } return(fRebindRequired); } HRESULT myLdapGetDSHostName( IN LDAP *pld, OUT WCHAR **ppwszHostName) { HRESULT hr; ULONG ldaperr; ldaperr = ldap_get_option(pld, LDAP_OPT_HOST_NAME, ppwszHostName); if (LDAP_SUCCESS != ldaperr) { *ppwszHostName = NULL; } hr = myHLdapError(pld, ldaperr, NULL); return(hr); } HRESULT myLdapCreateContainer( IN LDAP *pld, IN WCHAR const *pwszDN, IN BOOL fSkipObject, // Does the DN contain a leaf object name IN DWORD cMaxLevel, // create this many nested containers as needed IN PSECURITY_DESCRIPTOR pContainerSD, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; WCHAR const *pwsz = pwszDN; LDAPMod objectClass; LDAPMod advancedView; LDAPMod securityDescriptor; WCHAR *papwszshowInAdvancedViewOnly[2] = { L"TRUE", NULL }; WCHAR *objectClassVals[3]; LDAPMod *mods[4]; struct berval *sdVals[2]; struct berval sdberval; if (NULL != ppwszError) { *ppwszError = NULL; } mods[0] = &objectClass; mods[1] = &advancedView; mods[2] = &securityDescriptor; mods[3] = NULL; objectClass.mod_op = LDAP_MOD_ADD; objectClass.mod_type = TEXT("objectclass"); objectClass.mod_values = objectClassVals; advancedView.mod_op = LDAP_MOD_ADD; advancedView.mod_type = TEXT("showInAdvancedViewOnly"); advancedView.mod_values = papwszshowInAdvancedViewOnly; objectClassVals[0] = TEXT("top"); objectClassVals[1] = TEXT("container"); objectClassVals[2] = NULL; securityDescriptor.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; securityDescriptor.mod_type = CERTTYPE_SECURITY_DESCRIPTOR_NAME; securityDescriptor.mod_bvalues = sdVals; sdVals[0] = &sdberval; sdVals[1] = NULL; if (IsValidSecurityDescriptor(pContainerSD)) { sdberval.bv_len = GetSecurityDescriptorLength(pContainerSD); sdberval.bv_val = (char *)pContainerSD; } else { sdberval.bv_len = 0; sdberval.bv_val = NULL; } // If the DN passed in was for the full object that goes in the container // (and not the container itself), skip past the CN for the leaf object. if (fSkipObject) { // Look for the CN of the container for this object. pwsz = wcsstr(&pwsz[3], L"CN="); if (NULL == pwsz) { // If there was no CN, then we are contained in an OU or DC, // and we don't need to do the create. hr = S_OK; goto error; } } if (0 != wcsncmp(pwsz, L"CN=", 3)) { // We're not pointing to a simple container, so don't create this DN. hr = S_OK; goto error; } pwszDN = pwsz; if (0 != cMaxLevel) { pwsz = wcsstr(&pwsz[3], L"CN="); if (NULL != pwsz) { // The remaining DN is a container, so try to create it. hr = myLdapCreateContainer( pld, pwsz, FALSE, cMaxLevel - 1, pContainerSD, ppwszError); _JumpIfError(hr, error, "myLdapCreateContainer"); CSASSERT(NULL == ppwszError || NULL == *ppwszError); } } DBGPRINT((DBG_SS_CERTLIBI, "Creating DS Container: '%ws'\n", pwszDN)); // Create the container hr = ldap_add_ext_s( pld, const_cast(pwszDN), mods, g_rgLdapControls, NULL); _PrintIfErrorStr2( hr, "ldap_add_ext_s(container)", pwszDN, LDAP_ALREADY_EXISTS); if ((HRESULT) LDAP_SUCCESS != hr && (HRESULT) LDAP_ALREADY_EXISTS != hr) { hr = myHLdapError(pld, hr, ppwszError); _JumpIfErrorStr(hr, error, "ldap_add_ext_s(container)", pwszDN); } hr = S_OK; error: return(hr); } HRESULT TrimURLDN( IN WCHAR const *pwszIn, OPTIONAL OUT WCHAR **ppwszSuffix, OUT WCHAR **ppwszDN) { HRESULT hr; WCHAR *pwsz; if (NULL != ppwszSuffix) { *ppwszSuffix = NULL; } *ppwszDN = NULL; pwsz = wcschr(pwszIn, L':'); if (NULL != pwsz) { pwszIn = &pwsz[1]; } while (L'/' == *pwszIn) { pwszIn++; } hr = myDupString(pwszIn, ppwszDN); _JumpIfError(hr, error, "myDupString"); pwsz = wcschr(*ppwszDN, L'?'); if (NULL != pwsz) { *pwsz++ = L'\0'; if (NULL != ppwszSuffix) { *ppwszSuffix = pwsz; } } CSASSERT(S_OK == hr); error: if (S_OK != hr && NULL != *ppwszDN) { LocalFree(*ppwszDN); *ppwszDN = NULL; } return(hr); } HRESULT CreateCertObject( IN LDAP *pld, IN WCHAR const *pwszDN, IN DWORD dwObjectType, // LPC_* OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; PSECURITY_DESCRIPTOR pSD = NULL; PSECURITY_DESCRIPTOR pContainerSD = NULL; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } // get default DS CA security descriptor hr = myGetSDFromTemplate(WSZ_DEFAULT_CA_DS_SECURITY, NULL, &pSD); _JumpIfError(hr, error, "myGetSDFromTemplate"); // get default DS AIA security descriptor hr = myGetSDFromTemplate(WSZ_DEFAULT_CA_DS_SECURITY, NULL, &pContainerSD); _JumpIfError(hr, error, "myGetSDFromTemplate"); if (LPC_CREATECONTAINER & dwObjectType) { hr = myLdapCreateContainer( pld, pwszDN, TRUE, 0, pContainerSD, ppwszError); if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr) { _JumpIfError(hr, error, "myLdapCreateContainer"); } } if (LPC_CREATEOBJECT & dwObjectType) { switch (LPC_OBJECTMASK & dwObjectType) { case LPC_CAOBJECT: hr = myLdapCreateCAObject( pld, pwszDN, NULL, 0, pSD, pdwDisposition, ppwszError); if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr) { _JumpIfErrorStr(hr, error, "myLdapCreateCAObject", pwszDN); } break; case LPC_KRAOBJECT: case LPC_USEROBJECT: case LPC_MACHINEOBJECT: hr = myLdapCreateUserObject( pld, pwszDN, NULL, 0, pSD, dwObjectType, pdwDisposition, ppwszError); if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hr) { _JumpIfErrorStr(hr, error, "myLdapCreateUserObject", pwszDN); } break; default: hr = E_INVALIDARG; _JumpError(hr, error, "dwObjectType"); } } hr = S_OK; error: if (NULL != pSD) { LocalFree(pSD); } if (NULL != pContainerSD) { LocalFree(pContainerSD); } return(hr); } HRESULT AddCertToAttribute( IN LDAP *pld, IN CERT_CONTEXT const *pccPublish, IN WCHAR const *pwszDN, IN WCHAR const *pwszAttribute, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; DWORD cres; DWORD cber; DWORD iber; DWORD i; LDAP_TIMEVAL timeval; LDAPMessage *pmsg = NULL; LDAPMessage *pres; WCHAR *apwszAttrs[2]; struct berval **ppberval = NULL; struct berval **prgpberVals = NULL; FILETIME ft; BOOL fDeleteExpiredCert = FALSE; BOOL fNewCertMissing = TRUE; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } apwszAttrs[0] = const_cast(pwszAttribute); apwszAttrs[1] = NULL; timeval.tv_sec = csecLDAPTIMEOUT; timeval.tv_usec = 0; hr = ldap_search_st( pld, // ld const_cast(pwszDN), // base LDAP_SCOPE_BASE, // scope NULL, // filter apwszAttrs, // attrs FALSE, // attrsonly &timeval, // timeout &pmsg); // res if (S_OK != hr) { *pdwDisposition = hr; hr = myHLdapError(pld, hr, NULL); _JumpErrorStr(hr, error, "ldap_search_st", pwszDN); } cres = ldap_count_entries(pld, pmsg); if (0 == cres) { // No entries were found. hr = NTE_NOT_FOUND; _JumpError(hr, error, "ldap_count_entries"); } pres = ldap_first_entry(pld, pmsg); if (NULL == pres) { hr = NTE_NOT_FOUND; _JumpError(hr, error, "ldap_first_entry"); } ppberval = ldap_get_values_len( pld, pres, const_cast(pwszAttribute)); cber = 0; if (NULL != ppberval) { while (NULL != ppberval[cber]) { cber++; } } prgpberVals = (struct berval **) LocalAlloc( LMEM_FIXED, (cber + 2) * sizeof(prgpberVals[0])); if (NULL == prgpberVals) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // Delete any certs that are at least one day old GetSystemTimeAsFileTime(&ft); myMakeExprDateTime(&ft, -1, ENUM_PERIOD_DAYS); iber = 0; if (NULL != ppberval) { for (i = 0; NULL != ppberval[i]; i++) { BOOL fCopyBER = TRUE; struct berval *pberval = ppberval[i]; if (pberval->bv_len == 1 && pberval->bv_val[0] == 0) { fCopyBER = FALSE; // remove zero byte placeholder value } else if (pccPublish->cbCertEncoded == pberval->bv_len && 0 == memcmp( pberval->bv_val, pccPublish->pbCertEncoded, pccPublish->cbCertEncoded)) { fCopyBER = FALSE; // remove duplicates to avoid ldap error fNewCertMissing = FALSE; } else { CERT_CONTEXT const *pcc; pcc = CertCreateCertificateContext( X509_ASN_ENCODING, (BYTE *) pberval->bv_val, pberval->bv_len); if (NULL == pcc) { hr = myHLastError(); _PrintError(hr, "CertCreateCertificateContext"); } else { if (0 > CompareFileTime(&pcc->pCertInfo->NotAfter, &ft)) { fCopyBER = FALSE; fDeleteExpiredCert = TRUE; DBGPRINT((DBG_SS_CERTLIB, "Deleting expired cert %u\n", i)); } CertFreeCertificateContext(pcc); } } if (fCopyBER) { prgpberVals[iber++] = pberval; } } } // set disposition assuming there's nothing to do: *pdwDisposition = LDAP_ATTRIBUTE_OR_VALUE_EXISTS; if (fNewCertMissing || fDeleteExpiredCert) { struct berval certberval; LDAPMod *mods[2]; LDAPMod certmod; mods[0] = &certmod; mods[1] = NULL; certmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; certmod.mod_type = const_cast(pwszAttribute); certmod.mod_bvalues = prgpberVals; prgpberVals[iber++] = &certberval; prgpberVals[iber] = NULL; certberval.bv_val = (char *) pccPublish->pbCertEncoded; certberval.bv_len = pccPublish->cbCertEncoded; hr = ldap_modify_ext_s( pld, const_cast(pwszDN), mods, NULL, NULL); *pdwDisposition = hr; if (hr != S_OK) { hr = myHLdapError(pld, hr, ppwszError); _JumpError(hr, error, "ldap_modify_ext_s"); } } hr = S_OK; error: if (NULL != prgpberVals) { LocalFree(prgpberVals); } if (NULL != ppberval) { ldap_value_free_len(ppberval); } if (NULL != pmsg) { ldap_msgfree(pmsg); } return(hr); } HRESULT AddCRLToAttribute( IN LDAP *pld, IN CRL_CONTEXT const *pCRLPublish, IN WCHAR const *pwszDN, IN WCHAR const *pwszAttribute, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; DWORD cres; LDAP_TIMEVAL timeval; LDAPMessage *pmsg = NULL; LDAPMessage *pres; WCHAR *apwszAttrs[2]; struct berval **ppberval = NULL; LDAPMod crlmod; LDAPMod *mods[2]; struct berval *crlberVals[2]; struct berval crlberval; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } apwszAttrs[0] = const_cast(pwszAttribute); apwszAttrs[1] = NULL; timeval.tv_sec = csecLDAPTIMEOUT; timeval.tv_usec = 0; hr = ldap_search_st( pld, // ld const_cast(pwszDN), // base LDAP_SCOPE_BASE, // scope NULL, // filter apwszAttrs, // attrs FALSE, // attrsonly &timeval, // timeout &pmsg); // res if (S_OK != hr) { *pdwDisposition = hr; hr = myHLdapError(pld, hr, NULL); _JumpErrorStr(hr, error, "ldap_search_st", pwszDN); } cres = ldap_count_entries(pld, pmsg); if (0 == cres) { // No entries were found. hr = NTE_NOT_FOUND; _JumpError(hr, error, "ldap_count_entries"); } pres = ldap_first_entry(pld, pmsg); if (NULL == pres) { hr = NTE_NOT_FOUND; _JumpError(hr, error, "ldap_first_entry"); } ppberval = ldap_get_values_len( pld, pres, const_cast(pwszAttribute)); if (NULL != ppberval && NULL != ppberval[0] && pCRLPublish->cbCrlEncoded == ppberval[0]->bv_len && 0 == memcmp( ppberval[0]->bv_val, pCRLPublish->pbCrlEncoded, pCRLPublish->cbCrlEncoded)) { // set disposition assuming there's nothing to do: *pdwDisposition = LDAP_ATTRIBUTE_OR_VALUE_EXISTS; } else { mods[0] = &crlmod; mods[1] = NULL; crlmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; crlmod.mod_type = const_cast(pwszAttribute); crlmod.mod_bvalues = crlberVals; crlberVals[0] = &crlberval; crlberVals[1] = NULL; crlberval.bv_val = (char *) pCRLPublish->pbCrlEncoded; crlberval.bv_len = pCRLPublish->cbCrlEncoded; hr = ldap_modify_ext_s( pld, const_cast(pwszDN), mods, NULL, NULL); *pdwDisposition = hr; if (hr != S_OK) { hr = myHLdapError(pld, hr, ppwszError); _JumpError(hr, error, "ldap_modify_ext_s"); } } hr = S_OK; error: if (NULL != ppberval) { ldap_value_free_len(ppberval); } if (NULL != pmsg) { ldap_msgfree(pmsg); } return(hr); } HRESULT myLdapPublishCertToDS( IN LDAP *pld, IN CERT_CONTEXT const *pccPublish, IN WCHAR const *pwszURL, IN WCHAR const *pwszAttribute, IN DWORD dwObjectType, // LPC_* OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; WCHAR *pwszDN = NULL; WCHAR *pwszSuffix; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } hr = TrimURLDN(pwszURL, &pwszSuffix, &pwszDN); _JumpIfError(hr, error, "TrimURLDN"); if (0 == lstrcmpi(wszDSUSERCERTATTRIBUTE, pwszAttribute) || 0 == lstrcmpi(wszDSKRACERTATTRIBUTE, pwszAttribute)) { if (LPC_CAOBJECT == (LPC_OBJECTMASK & dwObjectType)) { hr = E_INVALIDARG; } } else if (0 == lstrcmpi(wszDSCACERTATTRIBUTE, pwszAttribute) || 0 == lstrcmpi(wszDSCROSSCERTPAIRATTRIBUTE, pwszAttribute)) { if (LPC_CAOBJECT != (LPC_OBJECTMASK & dwObjectType)) { hr = E_INVALIDARG; } } else { hr = E_INVALIDARG; } _JumpIfErrorStr(hr, error, "Bad Cert Attribute", pwszAttribute); *pdwDisposition = LDAP_SUCCESS; if ((LPC_CREATECONTAINER | LPC_CREATEOBJECT) & dwObjectType) { hr = CreateCertObject( pld, pwszDN, dwObjectType, pdwDisposition, ppwszError); _JumpIfError(hr, error, "CreateCertObject"); CSASSERT(NULL == ppwszError || NULL == *ppwszError); } hr = AddCertToAttribute( pld, pccPublish, pwszDN, pwszAttribute, pdwDisposition, ppwszError); _JumpIfError(hr, error, "AddCertToAttribute"); CSASSERT(NULL == ppwszError || NULL == *ppwszError); error: if (NULL != pwszDN) { LocalFree(pwszDN); } return(hr); } HRESULT myLdapPublishCRLToDS( IN LDAP *pld, IN CRL_CONTEXT const *pCRLPublish, IN WCHAR const *pwszURL, IN WCHAR const *pwszAttribute, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; WCHAR *pwszDN = NULL; WCHAR *pwszSuffix; PSECURITY_DESCRIPTOR pSD = NULL; PSECURITY_DESCRIPTOR pContainerSD = NULL; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } hr = TrimURLDN(pwszURL, &pwszSuffix, &pwszDN); _JumpIfError(hr, error, "TrimURLDN"); if (0 == lstrcmpi(wszDSBASECRLATTRIBUTE, pwszAttribute)) { } else if (0 == lstrcmpi(wszDSDELTACRLATTRIBUTE, pwszAttribute)) { } else { hr = E_INVALIDARG; _JumpErrorStr(hr, error, "Bad CRL Attribute", pwszAttribute); } // get default DS CDP security descriptor hr = myGetSDFromTemplate(WSZ_DEFAULT_CDP_DS_SECURITY, NULL, &pSD); if (S_OK != hr) { _PrintError(hr, "myGetSDFromTemplate"); pSD = NULL; } // get default DS AIA security descriptor hr = myGetSDFromTemplate(WSZ_DEFAULT_CA_DS_SECURITY, NULL, &pContainerSD); _JumpIfError(hr, error, "myGetSDFromTemplate"); hr = myLdapCreateContainer(pld, pwszDN, TRUE, 1, pContainerSD, ppwszError); _JumpIfError(hr, error, "myLdapCreateContainer"); hr = myLdapCreateCDPObject( pld, pwszDN, NULL != pSD? pSD : pContainerSD, pdwDisposition, ppwszError); _JumpIfErrorStr(hr, error, "myLdapCreateCDPObject", pwszDN); hr = AddCRLToAttribute( pld, pCRLPublish, pwszDN, pwszAttribute, pdwDisposition, ppwszError); _JumpIfError(hr, error, "AddCRLToAttribute"); error: if (NULL != pSD) { LocalFree(pSD); } if (NULL != pContainerSD) { LocalFree(pContainerSD); } if (NULL != pwszDN) { LocalFree(pwszDN); } return(hr); } HRESULT CreateOrUpdateDSObject( IN LDAP *pld, IN WCHAR const *pwszDN, IN LDAPMod **prgmodsCreate, OPTIONAL IN LDAPMod **prgmodsUpdate, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; ULONG ldaperr; if (NULL != ppwszError) { *ppwszError = NULL; } ldaperr = ldap_add_ext_s( pld, const_cast(pwszDN), prgmodsCreate, g_rgLdapControls, NULL); *pdwDisposition = ldaperr; _PrintIfErrorStr2(ldaperr, "ldap_add_ext_s", pwszDN, LDAP_ALREADY_EXISTS); if (ldaperr == LDAP_ALREADY_EXISTS) { if (NULL == prgmodsUpdate) { ldaperr = LDAP_SUCCESS; } else { ldaperr = ldap_modify_ext_s( pld, const_cast(pwszDN), prgmodsUpdate, NULL, NULL); *pdwDisposition = ldaperr; _PrintIfErrorStr2( ldaperr, "ldap_modify_ext_s", pwszDN, LDAP_ATTRIBUTE_OR_VALUE_EXISTS); if (LDAP_ATTRIBUTE_OR_VALUE_EXISTS == ldaperr) { ldaperr = LDAP_SUCCESS; } } } if (ldaperr != LDAP_SUCCESS) { hr = myHLdapError(pld, ldaperr, ppwszError); _JumpError(hr, error, "Add/Update DS"); } hr = S_OK; error: return(hr); } HRESULT myLdapCreateCAObject( IN LDAP *pld, IN WCHAR const *pwszDN, OPTIONAL IN BYTE const *pbCert, IN DWORD cbCert, IN PSECURITY_DESCRIPTOR pSD, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; BYTE ZeroByte = 0; LDAPMod objectClass; LDAPMod securityDescriptor; LDAPMod crlmod; LDAPMod arlmod; LDAPMod certmod; struct berval sdberval; struct berval crlberval; struct berval arlberval; struct berval certberval; WCHAR *objectClassVals[3]; struct berval *sdVals[2]; struct berval *crlVals[2]; struct berval *arlVals[2]; struct berval *certVals[2]; LDAPMod *mods[6]; if (NULL != ppwszError) { *ppwszError = NULL; } mods[0] = &objectClass; mods[1] = &securityDescriptor; mods[2] = &crlmod; mods[3] = &arlmod; mods[4] = &certmod; // must be last! mods[5] = NULL; objectClass.mod_op = LDAP_MOD_ADD; objectClass.mod_type = wszDSOBJECTCLASSATTRIBUTE; objectClass.mod_values = objectClassVals; objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSCACLASSNAME; objectClassVals[2] = NULL; securityDescriptor.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; securityDescriptor.mod_type = CERTTYPE_SECURITY_DESCRIPTOR_NAME; securityDescriptor.mod_bvalues = sdVals; sdVals[0] = &sdberval; sdVals[1] = NULL; sdberval.bv_len = 0; sdberval.bv_val = NULL; if (IsValidSecurityDescriptor(pSD)) { sdberval.bv_len = GetSecurityDescriptorLength(pSD); sdberval.bv_val = (char *) pSD; } crlmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; crlmod.mod_type = wszDSBASECRLATTRIBUTE; crlmod.mod_bvalues = crlVals; crlVals[0] = &crlberval; crlVals[1] = NULL; crlberval.bv_len = sizeof(ZeroByte); crlberval.bv_val = (char *) &ZeroByte; arlmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; arlmod.mod_type = wszDSAUTHORITYCRLATTRIBUTE; arlmod.mod_bvalues = arlVals; arlVals[0] = &arlberval; arlVals[1] = NULL; arlberval.bv_len = sizeof(ZeroByte); arlberval.bv_val = (char *) &ZeroByte; certmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; certmod.mod_type = wszDSCACERTATTRIBUTE; certmod.mod_bvalues = certVals; certVals[0] = &certberval; certVals[1] = NULL; certberval.bv_len = sizeof(ZeroByte); certberval.bv_val = (char *) &ZeroByte; if (NULL != pbCert) { certberval.bv_len = cbCert; certberval.bv_val = (char *) pbCert; } DBGPRINT((DBG_SS_CERTLIBI, "Creating DS CA Object: '%ws'\n", pwszDN)); CSASSERT(&certmod == mods[ARRAYSIZE(mods) - 2]); hr = CreateOrUpdateDSObject( pld, pwszDN, mods, NULL != pbCert? &mods[ARRAYSIZE(mods) - 2] : NULL, pdwDisposition, ppwszError); _JumpIfError(hr, error, "CreateOrUpdateDSObject(CA object)"); error: return(hr); } HRESULT myLdapCreateUserObject( IN LDAP *pld, IN WCHAR const *pwszDN, OPTIONAL IN BYTE const *pbCert, IN DWORD cbCert, IN PSECURITY_DESCRIPTOR pSD, IN DWORD dwObjectType, // LPC_* (but LPC_CREATE* is ignored) OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; ULONG ldaperr; BYTE ZeroByte = 0; LDAPMod objectClass; LDAPMod securityDescriptor; LDAPMod certmod; struct berval sdberval; struct berval certberval; WCHAR *objectClassVals[6]; struct berval *sdVals[2]; struct berval *certVals[2]; LDAPMod *mods[4]; if (NULL != ppwszError) { *ppwszError = NULL; } mods[0] = &objectClass; mods[1] = &securityDescriptor; mods[2] = &certmod; // must be last! mods[3] = NULL; securityDescriptor.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; securityDescriptor.mod_type = CERTTYPE_SECURITY_DESCRIPTOR_NAME; securityDescriptor.mod_bvalues = sdVals; sdVals[0] = &sdberval; sdVals[1] = NULL; sdberval.bv_len = 0; sdberval.bv_val = NULL; if (IsValidSecurityDescriptor(pSD)) { sdberval.bv_len = GetSecurityDescriptorLength(pSD); sdberval.bv_val = (char *) pSD; } objectClass.mod_op = LDAP_MOD_ADD; objectClass.mod_type = wszDSOBJECTCLASSATTRIBUTE; objectClass.mod_values = objectClassVals; DBGCODE(WCHAR const *pwszObjectType); switch (LPC_OBJECTMASK & dwObjectType) { case LPC_KRAOBJECT: objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSKRACLASSNAME; objectClassVals[2] = NULL; DBGCODE(pwszObjectType = L"KRA"); break; case LPC_USEROBJECT: objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSPERSONCLASSNAME; objectClassVals[2] = wszDSORGPERSONCLASSNAME; objectClassVals[3] = wszDSUSERCLASSNAME; objectClassVals[4] = NULL; DBGCODE(pwszObjectType = L"User"); break; case LPC_MACHINEOBJECT: objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSPERSONCLASSNAME; objectClassVals[2] = wszDSORGPERSONCLASSNAME; objectClassVals[3] = wszDSUSERCLASSNAME; objectClassVals[4] = wszDSMACHINECLASSNAME; objectClassVals[5] = NULL; DBGCODE(pwszObjectType = L"Machine"); break; default: hr = E_INVALIDARG; _JumpError(hr, error, "dwObjectType"); } certmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; certmod.mod_type = wszDSUSERCERTATTRIBUTE; certmod.mod_bvalues = certVals; certVals[0] = &certberval; certVals[1] = NULL; certberval.bv_len = sizeof(ZeroByte); certberval.bv_val = (char *) &ZeroByte; if (NULL != pbCert) { certberval.bv_len = cbCert; certberval.bv_val = (char *) pbCert; } DBGPRINT(( DBG_SS_CERTLIBI, "Creating DS %ws Object: '%ws'\n", pwszObjectType, pwszDN)); CSASSERT(&certmod == mods[ARRAYSIZE(mods) - 2]); hr = CreateOrUpdateDSObject( pld, pwszDN, mods, NULL != pbCert? &mods[ARRAYSIZE(mods) - 2] : NULL, pdwDisposition, ppwszError); _JumpIfError(hr, error, "CreateOrUpdateDSObject(KRA object)"); error: return(hr); } HRESULT myLdapCreateCDPObject( IN LDAP *pld, IN WCHAR const *pwszDN, IN PSECURITY_DESCRIPTOR pSD, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; BYTE ZeroByte = 0; LDAPMod objectClass; LDAPMod securityDescriptor; LDAPMod crlmod; LDAPMod drlmod; struct berval sdberval; struct berval crlberval; struct berval drlberval; WCHAR *objectClassVals[3]; struct berval *sdVals[2]; struct berval *crlVals[2]; struct berval *drlVals[2]; LDAPMod *mods[5]; if (NULL != ppwszError) { *ppwszError = NULL; } mods[0] = &objectClass; mods[1] = &securityDescriptor; mods[2] = &crlmod; mods[3] = &drlmod; mods[4] = NULL; objectClass.mod_op = LDAP_MOD_ADD; objectClass.mod_type = wszDSOBJECTCLASSATTRIBUTE; objectClass.mod_values = objectClassVals; objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSCDPCLASSNAME; objectClassVals[2] = NULL; securityDescriptor.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD; securityDescriptor.mod_type = CERTTYPE_SECURITY_DESCRIPTOR_NAME; securityDescriptor.mod_bvalues = sdVals; sdVals[0] = &sdberval; sdVals[1] = NULL; sdberval.bv_len = 0; sdberval.bv_val = NULL; if (IsValidSecurityDescriptor(pSD)) { sdberval.bv_len = GetSecurityDescriptorLength(pSD); sdberval.bv_val = (char *) pSD; } crlmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; crlmod.mod_type = wszDSBASECRLATTRIBUTE; crlmod.mod_bvalues = crlVals; crlVals[0] = &crlberval; crlVals[1] = NULL; crlberval.bv_val = (char *) &ZeroByte; crlberval.bv_len = sizeof(ZeroByte); drlmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE; drlmod.mod_type = wszDSDELTACRLATTRIBUTE; drlmod.mod_bvalues = drlVals; drlVals[0] = &drlberval; drlVals[1] = NULL; drlberval.bv_val = (char *) &ZeroByte; drlberval.bv_len = sizeof(ZeroByte); DBGPRINT((DBG_SS_CERTLIBI, "Creating DS CDP Object: '%ws'\n", pwszDN)); hr = CreateOrUpdateDSObject( pld, pwszDN, mods, NULL, pdwDisposition, ppwszError); _JumpIfError(hr, error, "CreateOrUpdateDSObject(CDP object)"); error: return(hr); } HRESULT myLdapCreateOIDObject( IN LDAP *pld, IN WCHAR const *pwszDN, IN DWORD dwType, IN WCHAR const *pwszObjId, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; WCHAR awcType[22]; LDAPMod objectClass; LDAPMod typemod; LDAPMod oidmod; WCHAR *objectClassVals[3]; WCHAR *typeVals[2]; WCHAR *oidVals[2]; LDAPMod *mods[4]; if (NULL != ppwszError) { *ppwszError = NULL; } mods[0] = &objectClass; mods[1] = &typemod; mods[2] = &oidmod; mods[3] = NULL; CSASSERT(4 == ARRAYSIZE(mods)); objectClass.mod_op = LDAP_MOD_ADD; objectClass.mod_type = wszDSOBJECTCLASSATTRIBUTE; objectClass.mod_values = objectClassVals; objectClassVals[0] = wszDSTOPCLASSNAME; objectClassVals[1] = wszDSOIDCLASSNAME; objectClassVals[2] = NULL; CSASSERT(3 == ARRAYSIZE(objectClassVals)); typemod.mod_op = LDAP_MOD_ADD; typemod.mod_type = OID_PROP_TYPE; typemod.mod_values = typeVals; wsprintf(awcType, L"%u", dwType); typeVals[0] = awcType; typeVals[1] = NULL; CSASSERT(2 == ARRAYSIZE(typeVals)); oidmod.mod_op = LDAP_MOD_ADD; oidmod.mod_type = OID_PROP_OID; oidmod.mod_values = oidVals; oidVals[0] = const_cast(pwszObjId); oidVals[1] = NULL; CSASSERT(2 == ARRAYSIZE(oidVals)); DBGPRINT((DBG_SS_CERTLIBI, "Creating DS OID Object: '%ws'\n", pwszDN)); hr = CreateOrUpdateDSObject( pld, pwszDN, mods, NULL, pdwDisposition, ppwszError); _JumpIfError(hr, error, "CreateOrUpdateDSObject(OID object)"); error: return(hr); } HRESULT myLdapOIDIsMatchingLangId( IN WCHAR const *pwszDisplayName, IN DWORD dwLanguageId, OUT BOOL *pfLangIdExists) { DWORD DisplayLangId = _wtoi(pwszDisplayName); *pfLangIdExists = FALSE; if (iswdigit(*pwszDisplayName) && NULL != wcschr(pwszDisplayName, L',') && DisplayLangId == dwLanguageId) { *pfLangIdExists = TRUE; } return(S_OK); } HRESULT myLdapAddOIDDisplayNameToAttribute( IN LDAP *pld, OPTIONAL IN WCHAR **ppwszOld, IN DWORD dwLanguageId, IN WCHAR const *pwszDisplayName, IN WCHAR const *pwszDN, IN WCHAR const *pwszAttribute, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr; DWORD cname; DWORD iname; DWORD i; WCHAR **ppwszNew = NULL; WCHAR *pwszNew = NULL; BOOL fDeleteOldName = FALSE; BOOL fNewNameMissing = TRUE; *pdwDisposition = LDAP_OTHER; if (NULL != ppwszError) { *ppwszError = NULL; } pwszNew = (WCHAR *) LocalAlloc( LMEM_FIXED, (12 + 1 + wcslen(pwszDisplayName) + 1) * sizeof(WCHAR)); if (NULL == pwszNew) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wsprintf(pwszNew, L"%u,%ws", dwLanguageId, pwszDisplayName); cname = 0; if (NULL != ppwszOld) { while (NULL != ppwszOld[cname]) { cname++; } } ppwszNew = (WCHAR **) LocalAlloc( LMEM_FIXED, (cname + 2) * sizeof(ppwszNew[0])); if (NULL == ppwszNew) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } // Delete any display names with matching dwLanguageId iname = 0; if (NULL != ppwszOld) { for (i = 0; NULL != ppwszOld[i]; i++) { BOOL fCopy = TRUE; WCHAR *pwsz = ppwszOld[i]; // case-sensitive compare: if (0 == lstrcmp(pwszNew, ppwszOld[i])) { fCopy = FALSE; // remove duplicates to avoid ldap error fNewNameMissing = FALSE; } else { BOOL fLangIdExists; hr = myLdapOIDIsMatchingLangId( pwsz, dwLanguageId, &fLangIdExists); _PrintIfError(hr, "myLdapOIDIsMatchingLangId"); if (S_OK != hr || fLangIdExists) { fCopy = FALSE; fDeleteOldName = TRUE; DBGPRINT((DBG_SS_CERTLIB, "Deleting %ws\n", pwsz)); } } if (fCopy) { ppwszNew[iname++] = pwsz; } } } CSASSERT(iname <= cname); // set disposition assuming there's nothing to do: *pdwDisposition = LDAP_ATTRIBUTE_OR_VALUE_EXISTS; if (fNewNameMissing || fDeleteOldName) { LDAPMod *mods[2]; LDAPMod namemod; mods[0] = &namemod; mods[1] = NULL; namemod.mod_op = LDAP_MOD_REPLACE; namemod.mod_type = const_cast(pwszAttribute); namemod.mod_values = ppwszNew; ppwszNew[iname++] = pwszNew; ppwszNew[iname] = NULL; hr = ldap_modify_ext_s( pld, const_cast(pwszDN), mods, NULL, NULL); *pdwDisposition = hr; if (hr != S_OK) { hr = myHLdapError(pld, hr, ppwszError); _JumpError(hr, error, "ldap_modify_ext_s"); } } hr = S_OK; error: if (NULL != pwszNew) { LocalFree(pwszNew); } if (NULL != ppwszNew) { LocalFree(ppwszNew); } return(hr); } HRESULT myHLdapError3( OPTIONAL IN LDAP *pld, IN ULONG ldaperrParm, IN ULONG ldaperrParmQuiet, IN ULONG ldaperrParmQuiet2, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr = S_OK; if (NULL != ppwszError) { *ppwszError = NULL; } if (LDAP_SUCCESS != ldaperrParm) { BOOL fXlat = TRUE; ULONG ldaperr; WCHAR *pwszError = NULL; if (NULL != pld) { ldaperr = ldap_get_option(pld, LDAP_OPT_SERVER_ERROR, &pwszError); if (LDAP_SUCCESS != ldaperr) { _PrintError(ldaperr, "ldap_get_option(server error)"); pwszError = NULL; } ldaperr = ldap_get_option(pld, LDAP_OPT_SERVER_EXT_ERROR, &hr); if (LDAP_SUCCESS != ldaperr) { _PrintError2( ldaperr, "ldap_get_option(server extended error)", ldaperr); } else { fXlat = FALSE; } } if (fXlat) { #undef LdapMapErrorToWin32 hr = LdapMapErrorToWin32(ldaperrParm); #define LdapMapErrorToWin32 Use_myHLdapError_Instead_Of_LdapMapErrorToWin32 } hr = myHError(hr); _PrintErrorStr3( ldaperrParm, "ldaperr", pwszError, ldaperrParmQuiet, ldaperrParmQuiet2); if (NULL != ppwszError && NULL != pwszError) { WCHAR awc[32]; DWORD cwc; wsprintf(awc, L"ldap: 0x%x: ", ldaperrParm); cwc = wcslen(awc) + wcslen(pwszError); *ppwszError = (WCHAR *) LocalAlloc( LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == *ppwszError) { _PrintError(E_OUTOFMEMORY, "LocalAlloc"); } else { wcscpy(*ppwszError, awc); wcscat(*ppwszError, pwszError); } } if(NULL != pwszError) ldap_memfree(pwszError); } return(hr); } HRESULT myHLdapError2( OPTIONAL IN LDAP *pld, IN ULONG ldaperrParm, IN ULONG ldaperrParmQuiet, OPTIONAL OUT WCHAR **ppwszError) { return(myHLdapError3( pld, ldaperrParm, ldaperrParmQuiet, LDAP_SUCCESS, ppwszError)); } HRESULT myHLdapError( OPTIONAL IN LDAP *pld, IN ULONG ldaperrParm, OPTIONAL OUT WCHAR **ppwszError) { return(myHLdapError3( pld, ldaperrParm, LDAP_SUCCESS, LDAP_SUCCESS, ppwszError)); } HRESULT myHLdapLastError( OPTIONAL IN LDAP *pld, OPTIONAL OUT WCHAR **ppwszError) { return(myHLdapError3( pld, LdapGetLastError(), LDAP_SUCCESS, LDAP_SUCCESS, ppwszError)); } HRESULT myLDAPSetStringAttribute( IN LDAP *pld, IN WCHAR const *pwszDN, IN WCHAR const *pwszAttribute, IN WCHAR const *pwszValue, OUT DWORD *pdwDisposition, OPTIONAL OUT WCHAR **ppwszError) { HRESULT hr = S_OK; LDAPMod *mods[2]; LDAPMod certmod; const WCHAR *ppwszVals[2]; CAutoLPWSTR pwszDNOnly; WCHAR *pwszSuffix; // no free hr = TrimURLDN(pwszDN, &pwszSuffix, &pwszDNOnly); _JumpIfErrorStr(hr, error, "TrimURLDN", pwszDN); mods[0] = &certmod; mods[1] = NULL; ppwszVals[0] = pwszValue; ppwszVals[1] = NULL; certmod.mod_op = LDAP_MOD_REPLACE; certmod.mod_type = const_cast(pwszAttribute); certmod.mod_values = const_cast(ppwszVals); hr = ldap_modify_ext_s( pld, pwszDNOnly, mods, NULL, NULL); *pdwDisposition = hr; if (hr != S_OK) { hr = myHLdapError(pld, hr, ppwszError); _JumpError(hr, error, "ldap_modify_ext_s"); } hr = S_OK; error: return hr; }