Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1860 lines
49 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: oidmgr.cpp
//
// Contents: DS OID management functions.
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include <winldap.h>
#include <ntldap.h>
#include <cainfop.h>
#include <oidmgr.h>
#include <certca.h>
#include "csldap.h"
#define __dwFILE__ __dwFILE_CERTCLIB_OIDMGR_CPP__
//the global critical section
CRITICAL_SECTION g_csOidURL;
extern BOOL g_fOidURL;
ULARGE_INTEGER g_ftOidTime;
BOOL g_fFailedTime=FALSE;
//the # of seconds in which we will not re-find a DC
#define CA_OID_MGR_FAIL_PERIOD 5
#define FILETIME_TICKS_PER_SECOND 10000000
//the cache of the enterprise root oid
LPWSTR g_pwszEnterpriseRootOID=NULL;
static WCHAR * s_wszOIDContainerSearch = L"(&(CN=OID)(objectCategory=" wszDSOIDCLASSNAME L"))";
static WCHAR * s_wszOIDContainerDN = L"CN=OID,CN=Public Key Services,CN=Services,";
WCHAR *g_awszOIDContainerAttrs[] = {OID_CONTAINER_PROP_OID,
OID_CONTAINER_PROP_GUID,
NULL};
//---------------------------------------------------------------------------
//
// myTimeOutRobustBind
//
// We will not attempt a LDAP bind if we have failed in the past pre-defined
// seconds.
//
//---------------------------------------------------------------------------
HRESULT
myTimeOutRobustLdapBind(OUT LDAP **ppldap)
{
HRESULT hr=E_FAIL;
FILETIME ftTime;
//the critical section has to be initalized
if (!g_fOidURL)
return(HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED));
EnterCriticalSection(&g_csOidURL);
//check if the previous failure has happened with 10 seconds
if(TRUE == g_fFailedTime)
{
//get the current time
GetSystemTimeAsFileTime(&ftTime);
g_ftOidTime.QuadPart += FILETIME_TICKS_PER_SECOND * CA_OID_MGR_FAIL_PERIOD;
if(0 > CompareFileTime(&ftTime, (LPFILETIME)&g_ftOidTime))
{
g_ftOidTime.QuadPart -= FILETIME_TICKS_PER_SECOND * CA_OID_MGR_FAIL_PERIOD;
hr=HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
_JumpError2(hr , error, "myDoesDSExist", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
}
else
{
//clear up the error recording
g_fFailedTime=FALSE;
}
}
//retrieve the ldap handle and the config string
hr = myDoesDSExist(TRUE);
_JumpIfError2(hr, error, "myDoesDSExist", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
hr = myRobustLdapBindEx(
0, // dwFlags1
RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
LDAP_VERSION2, // uVersion
NULL, // pwszDomainName
ppldap,
NULL); // ppwszForestDNSName
_JumpIfError(hr, error, "myRobustLdapBindEx");
error:
//remember the time if we failed due to lack of domain
if((S_OK != hr) && (FALSE==g_fFailedTime))
{
GetSystemTimeAsFileTime((LPFILETIME)&(g_ftOidTime));
g_fFailedTime=TRUE;
}
LeaveCriticalSection(&g_csOidURL);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDIsValidRootOID
//
//
// Pre .Net RC1, the enterprise root OID is derived from the GUID of CN=OID
// container in the format of DWORD.DWORD.DWORD.DWORD. The new Son of RFC2459
// defines a mandatory maximum length to the element of an OID of 2^28.
//
// The new format will be xxx.xxx.xxx.xxx.xxx.xxx, each element is a 3 byte
// date from the GUID (16 bytes). The last element is one byte only.
//
//---------------------------------------------------------------------------
BOOL CAOIDIsValidRootOID(LPWSTR pwszOID)
{
BOOL fValid=FALSE;
LPWSTR pwsz=NULL;
DWORD dwCount=0;
if(NULL == pwszOID)
goto error;
pwsz=pwszOID;
while(L'\0' != (*pwsz))
{
if(L'.' == (*pwsz))
{
dwCount++;
}
pwsz++;
}
if(14 != dwCount)
goto error;
fValid=TRUE;
error:
return fValid;
}
//---------------------------------------------------------------------------
//
// CAOIDAllocAndCopy
//
//---------------------------------------------------------------------------
HRESULT CAOIDAllocAndCopy(LPWSTR pwszSrc,
LPWSTR *ppwszDest)
{
if((NULL==ppwszDest) || (NULL==pwszSrc))
return E_INVALIDARG;
*ppwszDest=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (wcslen(pwszSrc) + 1));
if(NULL==(*ppwszDest))
return E_OUTOFMEMORY;
wcscpy(*ppwszDest, pwszSrc);
return S_OK;
}
//---------------------------------------------------------------------------
//
// CAOIDGetRandom
//
// We build a random x1.x2 string. X is a 32 bit unsigned integer. x1 > 1
// and x2 > 500.
//---------------------------------------------------------------------------
HRESULT CAOIDGetRandom(LPWSTR *ppwszRandom)
{
HRESULT hr=E_FAIL;
DWORD dwRandom1=0;
DWORD dwRandom2=0;
DWORD cbData=sizeof(DWORD);
WCHAR wszRandom1[DWORD_STRING_LENGTH];
WCHAR wszRandom2[DWORD_STRING_LENGTH];
HCRYPTPROV hProv=NULL;
//there is a bug in cryptAcquireContextW that if container is NULL, provider
//can not be ansi.
if(!CryptAcquireContextA(
&hProv,
NULL,
MS_DEF_PROV_A,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
hr= myHLastError();
_JumpError(hr, error, "CryptAcquireContextA");
}
//accoring to RFC2459 which bounds the OID size,
//elements in an arc must be between 0->2^28.
if(cbData > 3)
cbData=3;
if(!CryptGenRandom(hProv, cbData, (BYTE *)&dwRandom1))
{
hr= myHLastError();
_JumpError(hr, error, "CryptGenRandom");
}
if(!CryptGenRandom(hProv, cbData, (BYTE *)&dwRandom2))
{
hr= myHLastError();
_JumpError(hr, error, "CryptGenRandom");
}
if(dwRandom1 <= OID_RESERVE_DEFAULT_ONE)
dwRandom1 +=OID_RESERVE_DEFAULT_ONE;
if(dwRandom2 <= OID_RESERVR_DEFAULT_TWO)
dwRandom2 += OID_RESERVR_DEFAULT_TWO;
wszRandom1[0]=L'\0';
wsprintf(wszRandom1, L"%lu", dwRandom1);
wszRandom2[0]=L'\0';
wsprintf(wszRandom2, L"%lu", dwRandom2);
*ppwszRandom=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
(wcslen(wszRandom1) + wcslen(wszOID_DOT) + wcslen(wszRandom2) + 1));
if(NULL==(*ppwszRandom))
{
hr= E_OUTOFMEMORY;
_JumpError(hr, error, "CryptGenRandom");
}
wcscpy(*ppwszRandom, wszRandom1);
wcscat(*ppwszRandom, wszOID_DOT);
wcscat(*ppwszRandom, wszRandom2);
hr=S_OK;
error:
if(hProv)
CryptReleaseContext(hProv, 0);
return hr;
}
//----------------------------------------------------------------------------------
//
// CAOIDMapGUIDToOID
//
// GUID (16 byte) string is in the form of 3_Byte.3_Byte.3_Byte.3_Byte.3_Byte.1_Byte
// 12 characters are sufficient to present a 2^32 value.
//----------------------------------------------------------------------------------
HRESULT CAOIDMapGUIDToOID(LDAP_BERVAL *pGuidVal, LPWSTR *ppwszGUID)
{
HRESULT hr=E_INVALIDARG;
DWORD iIndex=0;
WCHAR wszString[DWORD_STRING_LENGTH];
DWORD dwData=0;
BYTE *pbData=NULL;
*ppwszGUID=NULL;
//a GUID should be 16 byte
if(16 != (pGuidVal->bv_len))
_JumpError(hr, error, "ArgumentCheck");
*ppwszGUID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * GUID_STRING_LENGTH);
if(NULL==(*ppwszGUID))
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
pbData=(BYTE *)(pGuidVal->bv_val);
for(iIndex=0; iIndex < 6; iIndex++)
{
wszString[0]=L'\0';
dwData=0;
//the 5th index (6th element) is only one byte 15th index (16th) bypte
if(iIndex == 5)
{
dwData=(DWORD)(pbData[iIndex * 3]);
}
else
{
dwData=(((DWORD)(pbData[iIndex * 3])) << 16) +
(((DWORD)(pbData[iIndex * 3 + 1])) << 8) +
((DWORD)(pbData[iIndex * 3 + 2]));
}
wsprintf(wszString, L"%lu", dwData);
if(0==iIndex)
{
wcscpy(*ppwszGUID, wszString);
}
else
{
wcscat(*ppwszGUID, wszOID_DOT);
wcscat(*ppwszGUID, wszString);
}
}
hr = S_OK;
error:
return hr;
}
//--------------------------------------------------------------------------
//
// FormatMessageUnicode
//
//--------------------------------------------------------------------------
HRESULT FormatMessageUnicode(LPWSTR *ppwszFormat,LPWSTR pwszString,...)
{
va_list argList;
DWORD cbMsg=0;
// format message into requested buffer
va_start(argList, pwszString);
cbMsg = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
pwszString,
0, // dwMessageId
0, // dwLanguageId
(LPWSTR) (ppwszFormat),
0, // minimum size to allocate
&argList);
va_end(argList);
if(0 != cbMsg)
return S_OK;
return E_INVALIDARG;
}
//---------------------------------------------------------------------------
//
// DoesOIDExist
//
//
//---------------------------------------------------------------------------
BOOL DoesOIDExist(LDAP *pld,
LPWSTR bstrConfig,
LPCWSTR pwszOID)
{
BOOL fExit=FALSE;
struct l_timeval timeout;
ULONG ldaperr=0;
DWORD dwCount=0;
LPWSTR awszAttr[2];
CERTSTR bstrDN = NULL;
LDAPMessage *SearchResult = NULL;
LPWSTR pwszFilter = NULL;
if(NULL==pwszOID)
goto error;
bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN));
if(NULL == bstrDN)
goto error;
wcscpy(bstrDN, s_wszOIDContainerDN);
wcscat(bstrDN, bstrConfig);
timeout.tv_sec = csecLDAPTIMEOUT;
timeout.tv_usec = 0;
awszAttr[0]=OID_PROP_OID;
awszAttr[1]=NULL;
if(S_OK != FormatMessageUnicode(&pwszFilter, L"(%1!s!=%2!s!)",
OID_PROP_OID, pwszOID))
goto error;
__try
{
ldaperr = ldap_search_stW(
pld,
(LPWSTR)bstrDN,
LDAP_SCOPE_ONELEVEL,
pwszFilter,
awszAttr,
0,
&timeout,
&SearchResult);
if(LDAP_SUCCESS != ldaperr)
goto error;
dwCount = ldap_count_entries(pld, SearchResult);
if(0 != dwCount)
fExit=TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if(pwszFilter)
LocalFree((HLOCAL)pwszFilter);
if(SearchResult)
ldap_msgfree(SearchResult);
if(bstrDN)
CertFreeString(bstrDN);
return fExit;
}
//---------------------------------------------------------------------------
//
// CAOIDUpdateDS
//
//
//---------------------------------------------------------------------------
HRESULT CAOIDUpdateDS(LDAP *pld,
LPWSTR pwszConfig,
ENT_OID_INFO *pOidInfo)
{
HRESULT hr=E_INVALIDARG;
BOOL fNew=FALSE;
ULONG ldaperr=0;
LDAPMod modObjectClass,
modCN,
modType,
modOID,
modDisplayName,
modCPS;
LDAPMod *mods[OID_ATTR_COUNT + 1];
DWORD cMod=0;
WCHAR wszType[DWORD_STRING_LENGTH];
LPWSTR awszObjectClass[3],
awszCN[2],
awszType[2],
awszOID[2],
awszDisplayName[2],
awszCPS[2];
CHAR sdBerValue[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION};
LDAPControl se_info_control =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, sdBerValue
},
TRUE
};
LDAPControl permissive_modify_control =
{
LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
{
0, NULL
},
FALSE
};
PLDAPControl server_controls[3] =
{
&se_info_control,
&permissive_modify_control,
NULL
};
CHAR sdBerValueDaclOnly[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION};
LDAPControl se_info_control_dacl_only =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, sdBerValueDaclOnly
},
TRUE
};
PLDAPControl server_controls_dacl_only[3] =
{
&se_info_control_dacl_only,
&permissive_modify_control,
NULL
};
CERTSTR bstrDN = NULL;
LPWSTR pwszCN = NULL;
if(NULL== (pOidInfo->pwszOID))
_JumpError(hr , error, "ArgumentCheck");
//if we are changing the OID value, we are creating a new oid
fNew = OID_ATTR_OID & (pOidInfo->dwAttr);
//set up the base DN
if(S_OK != (hr = myOIDHashOIDToString(pOidInfo->pwszOID, &pwszCN)))
_JumpError(hr , error, "myOIDHashOIDToString");
bstrDN = CertAllocStringLen(NULL, wcslen(pwszConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
if(bstrDN == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CertAllocStringLen");
}
wcscpy(bstrDN, L"CN=");
wcscat(bstrDN, pwszCN);
wcscat(bstrDN, L",");
wcscat(bstrDN, s_wszOIDContainerDN);
wcscat(bstrDN, pwszConfig);
//set up all the mods
modObjectClass.mod_op = LDAP_MOD_REPLACE;
modObjectClass.mod_type = L"objectclass";
modObjectClass.mod_values = awszObjectClass;
awszObjectClass[0] = wszDSTOPCLASSNAME;
awszObjectClass[1] = wszDSOIDCLASSNAME;
awszObjectClass[2] = NULL;
mods[cMod++] = &modObjectClass;
modCN.mod_op = LDAP_MOD_REPLACE;
modCN.mod_type = L"cn";
modCN.mod_values = awszCN;
awszCN[0] = pwszCN;
awszCN[1] = NULL;
mods[cMod++] = &modCN;
modOID.mod_op = LDAP_MOD_REPLACE;
modOID.mod_type = OID_PROP_OID;
modOID.mod_values = awszOID;
awszOID[0] = pOidInfo->pwszOID;
awszOID[1] = NULL;
mods[cMod++] = &modOID;
if(OID_ATTR_DISPLAY_NAME & (pOidInfo->dwAttr))
{
modDisplayName.mod_op = LDAP_MOD_REPLACE;
modDisplayName.mod_type = OID_PROP_DISPLAY_NAME;
if(pOidInfo->pwszDisplayName)
{
modDisplayName.mod_values = awszDisplayName;
awszDisplayName[0] = pOidInfo->pwszDisplayName;
awszDisplayName[1] = NULL;
}
else
modDisplayName.mod_values = NULL;
if(!fNew)
mods[cMod++] = &modDisplayName;
}
if(OID_ATTR_CPS & (pOidInfo->dwAttr))
{
modCPS.mod_op = LDAP_MOD_REPLACE;
modCPS.mod_type = OID_PROP_CPS;
if(pOidInfo->pwszCPS)
{
modCPS.mod_values = awszCPS;
awszCPS[0] = pOidInfo->pwszCPS;
awszCPS[1] = NULL;
}
else
modCPS.mod_values = NULL;
if(!fNew)
mods[cMod++] = &modCPS;
}
if(OID_ATTR_TYPE & (pOidInfo->dwAttr))
{
modType.mod_op = LDAP_MOD_REPLACE;
modType.mod_type = OID_PROP_TYPE;
modType.mod_values = awszType;
awszType[0] = wszType;
awszType[1] = NULL;
wsprintf(wszType, L"%d", pOidInfo->dwType);
mods[cMod++] = &modType;
}
mods[cMod++]=NULL;
//update the DS
__try
{
if(fNew)
{
ldaperr = ldap_add_ext_sW(pld, bstrDN, mods, server_controls, NULL);
_PrintIfError(ldaperr, "ldap_add_s");
}
else
{
ldaperr = ldap_modify_ext_sW(
pld,
bstrDN,
&mods[2],
server_controls_dacl_only,
NULL); // skip past objectClass and cn
if(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == ldaperr)
ldaperr = LDAP_SUCCESS;
_PrintIfError(ldaperr, "ldap_modify_ext_sW");
}
if ((LDAP_SUCCESS != ldaperr) && (LDAP_ALREADY_EXISTS != ldaperr))
{
hr = myHLdapError(pld, ldaperr, NULL);
_JumpError(ldaperr, error, fNew? "ldap_add_s" : "ldap_modify_sW");
}
hr=S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if(pwszCN)
LocalFree(pwszCN);
if(bstrDN)
CertFreeString(bstrDN);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDRetrieveEnterpriseRootWithConfig
//
// Get the enterpriseRoot from the displayName attribute of the container.
// If the attribute is missing, add the one with GUID of the container.
//
// Free memory via LocalFree().
//---------------------------------------------------------------------------
HRESULT
CAOIDRetrieveEnterpriseRootWithConfig(
LDAP *pld,
LPWSTR pwszConfig,
DWORD, // dwFlag
LPWSTR *ppwszOID)
{
HRESULT hr=E_INVALIDARG;
struct l_timeval timeout;
ULONG ldaperr=0;
DWORD dwCount=0;
LDAPMessage *Entry=NULL;
LDAPMod *mods[2];
LDAPMod modOIDName;
LPWSTR valOIDName[2];
CHAR sdBerValueDaclOnly[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION};
LDAPControl se_info_control_dacl_only =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, sdBerValueDaclOnly
},
TRUE
};
LDAPControl permissive_modify_control =
{
LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
{
0, NULL
},
FALSE
};
PLDAPControl server_controls_dacl_only[3] =
{
&se_info_control_dacl_only,
&permissive_modify_control,
NULL
};
CERTSTR bstrOIDContainer = NULL;
LDAPMessage *SearchResult = NULL;
WCHAR **wszLdapVal = NULL;
LDAP_BERVAL **pGuidVal = NULL;
LPWSTR pwszGUID = NULL;
__try
{
if(NULL==ppwszOID)
_JumpError(hr , error, "ArgumentCheck");
*ppwszOID=NULL;
//retrive the displayName attribute of the container if available
bstrOIDContainer = CertAllocStringLen(NULL, wcslen(pwszConfig) + wcslen(s_wszOIDContainerDN));
if(NULL == bstrOIDContainer)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CertAllocStringLen");
}
wcscpy(bstrOIDContainer, s_wszOIDContainerDN);
wcscat(bstrOIDContainer, pwszConfig);
timeout.tv_sec = csecLDAPTIMEOUT;
timeout.tv_usec = 0;
ldaperr = ldap_search_stW(
pld,
(LPWSTR)bstrOIDContainer,
LDAP_SCOPE_BASE,
s_wszOIDContainerSearch,
g_awszOIDContainerAttrs,
0,
&timeout,
&SearchResult);
if(LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError(pld, ldaperr, NULL);
_JumpError(hr, error, "ldap_search_stW");
}
dwCount = ldap_count_entries(pld, SearchResult);
//we should only find one container
if((1 != dwCount) || (NULL == (Entry = ldap_first_entry(pld, SearchResult))))
{
// No entries were found.
hr = myHLdapError(pld, LDAP_NO_SUCH_OBJECT, NULL);
_JumpError(hr, error, "ldap_search_stW");
}
wszLdapVal = ldap_get_values(pld, Entry, OID_CONTAINER_PROP_OID);
//make sure the displayName is a valud enterprise OID
if(wszLdapVal && wszLdapVal[0])
{
if(CAOIDIsValidRootOID(wszLdapVal[0]))
{
hr=CAOIDAllocAndCopy(wszLdapVal[0], ppwszOID);
//cache the enterprise root
if((S_OK == hr) && (g_fOidURL))
{
EnterCriticalSection(&g_csOidURL);
CAOIDAllocAndCopy(*ppwszOID, &g_pwszEnterpriseRootOID);
LeaveCriticalSection(&g_csOidURL);
}
goto error;
}
}
//no displayName is present or valid, we have to derive the displayName
//from the GUID of the container
pGuidVal = ldap_get_values_len(pld, Entry, OID_CONTAINER_PROP_GUID);
if((NULL==pGuidVal) || (NULL==pGuidVal[0]))
{
hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
_JumpError(hr, error, "getGUIDFromDS");
}
if(S_OK != (hr=CAOIDMapGUIDToOID(pGuidVal[0], &pwszGUID)))
_JumpError(hr, error, "CAOIDMapGUIDToOID");
//contantenate the strings
*ppwszOID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
(wcslen(wszOID_ENTERPRISE_ROOT) + wcslen(wszOID_DOT) + wcslen(pwszGUID) + 1));
if(NULL==(*ppwszOID))
{
hr=E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(*ppwszOID, wszOID_ENTERPRISE_ROOT);
wcscat(*ppwszOID, wszOID_DOT);
wcscat(*ppwszOID, pwszGUID);
//cache the newly created displayName to the DS
//no need to check for error since this is just a performance enhancement
valOIDName[0]=*ppwszOID;
valOIDName[1]=NULL;
modOIDName.mod_op = LDAP_MOD_REPLACE;
modOIDName.mod_type = OID_CONTAINER_PROP_OID;
modOIDName.mod_values = valOIDName;
mods[0]=&modOIDName;
mods[1]=NULL;
ldap_modify_ext_sW(
pld,
bstrOIDContainer,
mods,
server_controls_dacl_only,
NULL);
//cache the oid root in memory
if (g_fOidURL)
{
EnterCriticalSection(&g_csOidURL);
CAOIDAllocAndCopy(*ppwszOID, &g_pwszEnterpriseRootOID);
LeaveCriticalSection(&g_csOidURL);
}
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
error:
if(pwszGUID)
LocalFree(pwszGUID);
if(pGuidVal)
ldap_value_free_len(pGuidVal);
if(wszLdapVal)
ldap_value_free(wszLdapVal);
if(SearchResult)
ldap_msgfree(SearchResult);
if (bstrOIDContainer)
CertFreeString(bstrOIDContainer);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDRetrieveEnterpriseRoot
//
// Get the enterpriseRoot from the displayName attribute of the container.
// If the attribute is missing, add the one with GUID of the container.
//
// Free memory via LocalFree().
//---------------------------------------------------------------------------
HRESULT CAOIDRetrieveEnterpriseRoot(DWORD dwFlag, LPWSTR *ppwszOID)
{
HRESULT hr=E_INVALIDARG;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
if(NULL==ppwszOID)
_JumpError(hr , error, "ArgumentCheck");
*ppwszOID=NULL;
//retrieve the memory cache if available
if (g_fOidURL)
{
EnterCriticalSection(&g_csOidURL);
if(g_pwszEnterpriseRootOID)
{
hr=CAOIDAllocAndCopy(g_pwszEnterpriseRootOID, ppwszOID);
LeaveCriticalSection(&g_csOidURL);
goto error;
}
LeaveCriticalSection(&g_csOidURL);
}
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
hr = CAOIDRetrieveEnterpriseRootWithConfig(pld, bstrConfig,
dwFlag, ppwszOID);
error:
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDBuildOIDWithRoot
//
//
// Free memory via LocalFree().
//---------------------------------------------------------------------------
HRESULT
CAOIDBuildOIDWithRoot(
DWORD, // dwFlag
LPCWSTR pwszRoot,
LPCWSTR pwszEndOID,
LPWSTR *ppwszOID)
{
HRESULT hr=E_INVALIDARG;
if(NULL==pwszRoot)
_JumpError(hr , error, "ArgumentCheck");
*ppwszOID=NULL;
*ppwszOID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
(wcslen(pwszRoot) + wcslen(wszOID_DOT) + wcslen(pwszEndOID) + 1));
if(NULL==(*ppwszOID))
{
hr = E_OUTOFMEMORY;
_JumpError(hr , error, "LocalAlloc");
}
wcscpy(*ppwszOID, pwszRoot);
wcscat(*ppwszOID, wszOID_DOT);
wcscat(*ppwszOID, pwszEndOID);
hr= S_OK;
error:
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDBuildOID
//
//
// Free memory via LocalFree().
//---------------------------------------------------------------------------
HRESULT CAOIDBuildOID(DWORD dwFlag, LPCWSTR pwszEndOID, LPWSTR *ppwszOID)
{
HRESULT hr=E_INVALIDARG;
LPWSTR pwszRoot=NULL;
if((NULL==ppwszOID) || (NULL==pwszEndOID))
_JumpError(hr , error, "ArgumentCheck");
*ppwszOID=NULL;
if(S_OK != (hr=CAOIDRetrieveEnterpriseRoot(0, &pwszRoot)))
_JumpError(hr , error, "RetrieveEnterpriseRoot");
hr= CAOIDBuildOIDWithRoot(dwFlag, pwszRoot, pwszEndOID, ppwszOID);
error:
if(pwszRoot)
LocalFree(pwszRoot);
return hr;
}
//------------------------------------------------------------------------
// Convert the byte to its Hex presentation.
//
//
//------------------------------------------------------------------------
ULONG ByteToHex(BYTE byte, LPWSTR wszZero, LPWSTR wszA)
{
ULONG uValue=0;
if(((ULONG)byte)<=9)
{
uValue=((ULONG)byte)+ULONG(*wszZero);
}
else
{
uValue=(ULONG)byte-10+ULONG(*wszA);
}
return uValue;
}
//--------------------------------------------------------------------------
//
// ConvertByteToWstr
//
// If fSpace is TRUE, we add a space every 2 bytes.
//--------------------------------------------------------------------------
HRESULT ConvertByteToWstr(BYTE *pbData,
DWORD cbData,
LPWSTR *ppwsz)
{
HRESULT hr=E_INVALIDARG;
DWORD dwBufferSize=0;
DWORD dwBufferIndex=0;
DWORD dwEncodedIndex=0;
LPWSTR pwszZero=L"0";
LPWSTR pwszA=L"A";
if(!pbData || !ppwsz)
_JumpError(hr , error, "ArgumentCheck");
//calculate the memory needed, in bytes
//we need 2 wchars per byte, along with the NULL terminator
dwBufferSize=sizeof(WCHAR)*(cbData*2+1);
*ppwsz=(LPWSTR)LocalAlloc(LPTR, dwBufferSize);
if(NULL==(*ppwsz))
{
hr=E_OUTOFMEMORY;
_JumpError(hr , error, "LocalAlloc");
}
dwBufferIndex=0;
//format the wchar buffer one byte at a time
for(dwEncodedIndex=0; dwEncodedIndex<cbData; dwEncodedIndex++)
{
//format the higher 4 bits
(*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
(pbData[dwEncodedIndex]&UPPER_BITS)>>4,
pwszZero, pwszA);
dwBufferIndex++;
//format the lower 4 bits
(*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
pbData[dwEncodedIndex]&LOWER_BITS,
pwszZero, pwszA);
dwBufferIndex++;
}
//add the NULL terminator to the string
(*ppwsz)[dwBufferIndex]=L'\0';
hr=S_OK;
error:
return hr;
}
//---------------------------------------------------------------------------
// myOIDHashOIDToString
//
// Map the OID to a hash string in the format of oid.hash.
//---------------------------------------------------------------------------
HRESULT
myOIDHashOIDToString(
IN WCHAR const *pwszOID,
OUT WCHAR **ppwsz)
{
HRESULT hr=E_INVALIDARG;
BYTE pbHash[CERT_OID_MD5_HASH_SIZE];
DWORD cbData=CERT_OID_MD5_HASH_SIZE;
LPCWSTR pwszChar=NULL;
DWORD dwIDLength=CERT_OID_IDENTITY_LENGTH;
LPWSTR pwszHash=NULL;
if((NULL==pwszOID) || (NULL==ppwsz))
_JumpError(hr , error, "ArgumentCheck");
*ppwsz=NULL;
hr = myVerifyObjId(pwszOID);
_JumpIfErrorStr2(hr, error, "myVerifyObjId", pwszOID, E_INVALIDARG);
if(!CryptHashCertificate(
NULL,
CALG_MD5,
0,
(BYTE * )pwszOID,
sizeof(WCHAR) * wcslen(pwszOID),
pbHash,
&cbData))
{
hr= myHLastError();
_JumpError(hr , error, "CryptHashCertificate");
}
//convert the hash to a string
if(S_OK != (hr=ConvertByteToWstr(pbHash, CERT_OID_MD5_HASH_SIZE, &pwszHash)))
_JumpError(hr , error, "ConvertByteToWstr");
//find the last component of the oid. Take the first 16 characters
pwszChar=wcsrchr(pwszOID, L'.');
if(NULL==pwszChar)
pwszChar=pwszOID;
else
pwszChar++;
if(dwIDLength > wcslen(pwszChar))
dwIDLength=wcslen(pwszChar);
//the result string is oid.hash
*ppwsz=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
(dwIDLength + wcslen(pwszHash) + wcslen(wszOID_DOT) +1));
if(NULL==*ppwsz)
{
hr= E_OUTOFMEMORY;
_JumpError(hr , error, "LocalAlloc");
}
wcsncpy(*ppwsz, pwszChar, dwIDLength);
(*ppwsz)[dwIDLength]=L'\0';
wcscat(*ppwsz, wszOID_DOT);
wcscat(*ppwsz, pwszHash);
hr=S_OK;
error:
if(pwszHash)
LocalFree(pwszHash);
return hr;
}
//---------------------------------------------------------------------------
// I_CAOIDCreateNew
// Create a new OID based on the enterprise base
//
// Returns S_OK if successful.
//---------------------------------------------------------------------------
HRESULT
I_CAOIDCreateNew(
DWORD dwType,
DWORD, // dwFlag
LPWSTR *ppwszOID)
{
HRESULT hr=E_INVALIDARG;
ENT_OID_INFO oidInfo;
DWORD iIndex=0;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
LPWSTR pwszRoot = NULL;
LPWSTR pwszNewOID = NULL;
LPWSTR pwszRandom = NULL;
if(NULL==ppwszOID)
_JumpError(hr , error, "ArgumentCheck");
*ppwszOID=NULL;
//retrieve the root oid if available
if (g_fOidURL)
{
EnterCriticalSection(&g_csOidURL);
if(g_pwszEnterpriseRootOID)
{
if(S_OK != (hr=CAOIDAllocAndCopy(g_pwszEnterpriseRootOID, &pwszRoot)))
{
LeaveCriticalSection(&g_csOidURL);
goto error;
}
}
LeaveCriticalSection(&g_csOidURL);
}
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
if(NULL==pwszRoot)
{
if(S_OK != (hr = CAOIDRetrieveEnterpriseRootWithConfig(pld, bstrConfig, 0, &pwszRoot)))
_JumpError(hr , error, "CAOIDRetrieveEnterpriseRootWithConfig");
}
//we try to generate a random x1.x2 oid. x > 1 and x2 > 500
for(iIndex=0; iIndex < OID_RANDOM_CREATION_TRIAL; iIndex++)
{
if(S_OK != (hr = CAOIDGetRandom(&pwszRandom)))
_JumpError(hr , error, "CAOIDGetRandom");
if(S_OK != (hr = CAOIDBuildOIDWithRoot(0, pwszRoot, pwszRandom, &pwszNewOID)))
_JumpError(hr , error, "CAOIDBuildOIDWithRoot");
if(!DoesOIDExist(pld, bstrConfig, pwszNewOID))
break;
LocalFree(pwszRandom);
pwszRandom=NULL;
LocalFree(pwszNewOID);
pwszNewOID=NULL;
}
if(iIndex == OID_RANDOM_CREATION_TRIAL)
{
hr=E_FAIL;
_JumpError(hr , error, "CAOIDGetRandom");
}
//update the oid information on the DS
memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
oidInfo.dwAttr=OID_ATTR_ALL;
oidInfo.dwType=dwType;
oidInfo.pwszOID=pwszNewOID;
if(S_OK != (hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo)))
_JumpError(hr , error, "CAOIDUpdateDS");
*ppwszOID=pwszNewOID;
pwszNewOID=NULL;
hr=S_OK;
error:
if(pwszRandom)
LocalFree(pwszRandom);
if(pwszNewOID)
LocalFree(pwszNewOID);
if(pwszRoot)
LocalFree(pwszRoot);
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDCreateNew
//
//---------------------------------------------------------------------------
HRESULT
CAOIDCreateNew(
IN DWORD dwType,
IN DWORD dwFlag,
OUT LPWSTR *ppwszOID)
{
return I_CAOIDCreateNew(dwType, dwFlag, ppwszOID);
}
//---------------------------------------------------------------------------
// I_CAOIDSetProperty
// Set a property on an oid.
//
//
// Returns S_OK if successful.
//---------------------------------------------------------------------------
HRESULT
I_CAOIDSetProperty(
IN LPCWSTR pwszOID,
IN DWORD dwProperty,
IN LPVOID pPropValue)
{
HRESULT hr=E_INVALIDARG;
ENT_OID_INFO oidInfo;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
if(NULL==pwszOID)
_JumpError(hr , error, "ArgumentCheck");
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
//make sure the OID exist on the DS
if(!DoesOIDExist(pld, bstrConfig, pwszOID))
{
hr=NTE_NOT_FOUND;
_JumpErrorStr(hr, error, "DoesOIDExist", pwszOID);
}
//update the oid information on the DS
memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
oidInfo.pwszOID=(LPWSTR)pwszOID;
switch(dwProperty)
{
case CERT_OID_PROPERTY_DISPLAY_NAME:
oidInfo.dwAttr = OID_ATTR_DISPLAY_NAME;
oidInfo.pwszDisplayName=(LPWSTR)pPropValue;
break;
case CERT_OID_PROPERTY_CPS:
oidInfo.dwAttr = OID_ATTR_CPS;
oidInfo.pwszCPS=(LPWSTR)pPropValue;
break;
default:
hr=E_INVALIDARG;
_JumpError(hr , error, "ArgumentCheck");
}
hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo);
error:
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDSetProperty
//
//---------------------------------------------------------------------------
HRESULT
CAOIDSetProperty(
IN LPCWSTR pwszOID,
IN DWORD dwProperty,
IN LPVOID pPropValue)
{
return I_CAOIDSetProperty(pwszOID, dwProperty, pPropValue);
}
//---------------------------------------------------------------------------
// I_CAOIDAdd
//
// Returns S_OK if successful.
// Returns CRYPT_E_EXISTS if the OID alreay exits in the DS repository
//---------------------------------------------------------------------------
HRESULT
I_CAOIDAdd(
IN DWORD dwType,
IN DWORD, // dwFlag
IN LPCWSTR pwszOID)
{
HRESULT hr=E_INVALIDARG;
ENT_OID_INFO oidInfo;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
if(NULL==pwszOID)
_JumpError(hr , error, "ArgumentCheck");
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
//make sure the OID does not exist on the DS
if(DoesOIDExist(pld, bstrConfig, pwszOID))
{
hr=CRYPT_E_EXISTS;
_JumpErrorStr(hr, error, "OID Exists", pwszOID);
}
//update the oid information on the DS
memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
oidInfo.dwAttr=OID_ATTR_ALL;
oidInfo.dwType=dwType;
oidInfo.pwszOID=(LPWSTR)pwszOID;
hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo);
error:
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
// CAOIDAdd
//
// Returns S_OK if successful.
// Returns CRYPT_E_EXISTS if the OID alreay exits in the DS repository
//---------------------------------------------------------------------------
HRESULT
CAOIDAdd(
IN DWORD dwType,
IN DWORD dwFlag,
IN LPCWSTR pwszOID)
{
return I_CAOIDAdd(dwType, dwFlag, pwszOID);
}
//---------------------------------------------------------------------------
//
// I_CAOIDDelete
//
//---------------------------------------------------------------------------
HRESULT
I_CAOIDDelete(
IN LPCWSTR pwszOID)
{
HRESULT hr=E_INVALIDARG;
ULONG ldaperr=0;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
CERTSTR bstrDN = NULL;
LPWSTR pwszCN = NULL;
if(NULL==pwszOID)
_JumpError(hr , error, "ArgumentCheck");
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
//set up the base DN
if(S_OK != (hr = myOIDHashOIDToString((LPWSTR)pwszOID, &pwszCN)))
_JumpError(hr , error, "myOIDHashOIDToString");
bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
if(bstrDN == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CertAllocStringLen");
}
wcscpy(bstrDN, L"CN=");
wcscat(bstrDN, pwszCN);
wcscat(bstrDN, L",");
wcscat(bstrDN, s_wszOIDContainerDN);
wcscat(bstrDN, bstrConfig);
ldaperr = ldap_delete_s(pld, bstrDN);
if(LDAP_NO_SUCH_OBJECT == ldaperr)
ldaperr = LDAP_SUCCESS;
hr = myHLdapError(pld, ldaperr, NULL);
error:
if(pwszCN)
LocalFree(pwszCN);
if(bstrDN)
CertFreeString(bstrDN);
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDDelete
//
//---------------------------------------------------------------------------
HRESULT
CAOIDDelete(
IN LPCWSTR pwszOID)
{
return I_CAOIDDelete(pwszOID);
}
//---------------------------------------------------------------------------
//
// I_CAOIDGetProperty
//
//---------------------------------------------------------------------------
HRESULT
I_CAOIDGetProperty(
IN LPCWSTR pwszOID,
IN DWORD dwProperty,
OUT LPVOID pPropValue)
{
HRESULT hr=E_INVALIDARG;
ULONG ldaperr=0;
DWORD dwCount=0;
struct l_timeval timeout;
LPWSTR awszAttr[4];
LDAPMessage *Entry=NULL;
WCHAR **wszLdapVal = NULL;
LPWSTR pwszFilter = NULL;
LDAPMessage *SearchResult = NULL;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
CERTSTR bstrDN = NULL;
LPWSTR pwszCN = NULL;
if((NULL==pwszOID) || (NULL==pPropValue))
_JumpError(hr , error, "ArgumentCheck");
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
//set up the base DN
if(S_OK != (hr = myOIDHashOIDToString((LPWSTR)pwszOID, &pwszCN)))
_JumpError(hr , error, "myOIDHashOIDToString");
bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
if(bstrDN == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "CertAllocStringLen");
}
wcscpy(bstrDN, L"CN=");
wcscat(bstrDN, pwszCN);
wcscat(bstrDN, L",");
wcscat(bstrDN, s_wszOIDContainerDN);
wcscat(bstrDN, bstrConfig);
//search for the OID, asking for all its attributes
timeout.tv_sec = csecLDAPTIMEOUT;
timeout.tv_usec = 0;
awszAttr[0]=OID_PROP_TYPE;
awszAttr[1]=OID_PROP_DISPLAY_NAME;
awszAttr[2]=OID_PROP_CPS;
awszAttr[3]=NULL;
if(S_OK != (hr=FormatMessageUnicode(&pwszFilter, L"(%1!s!=%2!s!)",
OID_PROP_OID, pwszOID)))
_JumpError(hr , error, "FormatMessageUnicode");
ldaperr = ldap_search_stW(
pld,
(LPWSTR)bstrDN,
LDAP_SCOPE_BASE,
pwszFilter,
awszAttr,
0,
&timeout,
&SearchResult);
if(LDAP_SUCCESS != ldaperr)
{
hr = myHLdapError2(pld, ldaperr, LDAP_NO_SUCH_OBJECT, NULL);
_JumpErrorStr2(
hr,
error,
"ldap_search_stW",
pwszFilter,
HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
}
dwCount = ldap_count_entries(pld, SearchResult);
//we should only find one container
if((1 != dwCount) || (NULL == (Entry = ldap_first_entry(pld, SearchResult))))
{
// No entries were found.
hr = myHLdapError(pld, LDAP_NO_SUCH_OBJECT, NULL);
_JumpError(hr, error, "ldap_search_stW");
}
switch(dwProperty)
{
case CERT_OID_PROPERTY_DISPLAY_NAME:
wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_DISPLAY_NAME);
if(wszLdapVal && wszLdapVal[0])
{
hr=CAOIDAllocAndCopy(wszLdapVal[0], (LPWSTR *)pPropValue);
}
else
hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
break;
case CERT_OID_PROPERTY_CPS:
wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_CPS);
if(wszLdapVal && wszLdapVal[0])
{
hr=CAOIDAllocAndCopy(wszLdapVal[0], (LPWSTR *)pPropValue);
}
else
hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
break;
case CERT_OID_PROPERTY_TYPE:
wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_TYPE);
if(wszLdapVal && wszLdapVal[0])
{
*((DWORD *)pPropValue)=_wtol(wszLdapVal[0]);
hr=S_OK;
}
else
hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
break;
default:
hr=E_INVALIDARG;
}
if(hr != S_OK)
_JumpError(hr , error, "GetAttibuteValue");
error:
if(wszLdapVal)
ldap_value_free(wszLdapVal);
if(pwszFilter)
LocalFree((HLOCAL)pwszFilter);
if(SearchResult)
ldap_msgfree(SearchResult);
if(pwszCN)
LocalFree(pwszCN);
if(bstrDN)
CertFreeString(bstrDN);
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDGetProperty
//
//---------------------------------------------------------------------------
HRESULT
CAOIDGetProperty(
IN LPCWSTR pwszOID,
IN DWORD dwProperty,
OUT LPVOID pPropValue)
{
return I_CAOIDGetProperty(pwszOID, dwProperty, pPropValue);
}
//---------------------------------------------------------------------------
//
// I_CAOIDFreeProperty
//
//---------------------------------------------------------------------------
HRESULT
I_CAOIDFreeProperty(
IN LPVOID pPropValue)
{
if(pPropValue)
LocalFree(pPropValue);
return S_OK;
}
//---------------------------------------------------------------------------
//
// CAOIDFreeProperty
//
//---------------------------------------------------------------------------
HRESULT
CAOIDFreeProperty(
IN LPVOID pPropValue)
{
return I_CAOIDFreeProperty(pPropValue);
}
//---------------------------------------------------------------------------
//
// CAOIDGetLdapURL
//
// Get the LDAP URL for the DS OID repository in the format of
// LDAP:///DN of the Repository/all attributes?one?filter.
//---------------------------------------------------------------------------
HRESULT
CAOIDGetLdapURL(
IN DWORD dwType,
IN DWORD, // dwFlag
OUT LPWSTR *ppwszURL)
{
HRESULT hr=E_INVALIDARG;
LPWSTR wszFilterFormat=L"ldap:///%1!s!%2!s!?%3!s!,%4!s!,%5!s!,%6!s!,%7!s!?one?%8!s!=%9!d!";
LPWSTR pwsz=NULL;
LPWSTR pwszURL=NULL;
LDAP *pld = NULL;
CERTSTR bstrConfig = NULL;
if(NULL==ppwszURL)
_JumpError(hr , error, "ArgumentCheck");
//retrieve the ldap handle and the config string
if(S_OK != (hr = myTimeOutRobustLdapBind(&pld)))
_JumpError(hr , error, "myTimeRobustLdapBind");
hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
if(S_OK != hr)
{
_JumpError(hr , error, "CAGetAuthoritativeDomainDn");
}
if(S_OK != (hr=FormatMessageUnicode(
&pwszURL,
wszFilterFormat,
s_wszOIDContainerDN,
bstrConfig,
OID_PROP_TYPE,
OID_PROP_OID,
OID_PROP_DISPLAY_NAME,
OID_PROP_CPS,
OID_PROP_LOCALIZED_NAME,
OID_PROP_TYPE,
dwType
)))
_JumpError(hr , error, "FormatMessageUnicode");
//we eliminate the filter if dwType is CERT_OID_TYPE_ALL
if(CERT_OID_TYPE_ALL == dwType)
{
pwsz=wcsrchr(pwszURL, L'?');
if(NULL==pwsz)
{
//something serious is wrong
hr=E_UNEXPECTED;
_JumpError(hr , error, "FormatMessageUnicode");
}
*pwsz=L'\0';
}
*ppwszURL=pwszURL;
pwszURL=NULL;
hr=S_OK;
error:
if(pwszURL)
LocalFree((HLOCAL)pwszURL);
if(bstrConfig)
CertFreeString(bstrConfig);
if (pld)
ldap_unbind(pld);
return hr;
}
//---------------------------------------------------------------------------
//
// CAOIDFreeLdapURL
//
//---------------------------------------------------------------------------
HRESULT
CAOIDFreeLdapURL(
IN LPCWSTR pwszURL)
{
if(pwszURL)
LocalFree((HLOCAL)pwszURL);
return S_OK;
}