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
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;
|
|
}
|