2060 lines
45 KiB
C++
2060 lines
45 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: ldap.cpp
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#undef LdapMapErrorToWin32
|
|
#include <winldap.h>
|
|
#define LdapMapErrorToWin32 Use_myHLdapError_Instead_Of_LdapMapErrorToWin32
|
|
|
|
#include <ntldap.h>
|
|
|
|
#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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(pwszAttribute);
|
|
apwszAttrs[1] = NULL;
|
|
|
|
timeval.tv_sec = csecLDAPTIMEOUT;
|
|
timeval.tv_usec = 0;
|
|
|
|
hr = ldap_search_st(
|
|
pld, // ld
|
|
const_cast<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(pwszAttribute);
|
|
apwszAttrs[1] = NULL;
|
|
|
|
timeval.tv_sec = csecLDAPTIMEOUT;
|
|
timeval.tv_usec = 0;
|
|
|
|
hr = ldap_search_st(
|
|
pld, // ld
|
|
const_cast<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(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<WCHAR *>(pwszAttribute);
|
|
namemod.mod_values = ppwszNew;
|
|
|
|
ppwszNew[iname++] = pwszNew;
|
|
ppwszNew[iname] = NULL;
|
|
|
|
hr = ldap_modify_ext_s(
|
|
pld,
|
|
const_cast<WCHAR *>(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<WCHAR *>(pwszAttribute);
|
|
certmod.mod_values = const_cast<PWCHAR *>(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;
|
|
} |