Windows-Server-2003/ds/adsi/ldap/globals.cxx

1383 lines
36 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996
//
// File: globals.cxx
//
// Contents:
//
// History:
//----------------------------------------------------------------------------
#include "ldap.hxx"
#pragma hdrstop
TCHAR *szProviderName = TEXT("LDAP");
TCHAR *szLDAPNamespaceName = TEXT("LDAP");
TCHAR *szGCNamespaceName = TEXT("GC");
//
// List of interface properties for Generic Objects
//
INTF_PROP_DATA IntfPropsGeneric[] =
{
// 9999 implies BSTR value got using pIADs ptr.
{ TEXT("__Class"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__GUID"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__Path"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__Parent"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__Schema"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__URL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
// end of list from IADs::get_ methods.
{ TEXT("__Genus"), OPERATION_CODE_READABLE,
UMI_TYPE_I4, FALSE, {UMI_GENUS_INSTANCE}},
{ TEXT("__Name"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__KEY"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__RELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__RELPATH"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__FULLRELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__PADS_SCHEMA_CONTAINER_PATH"), OPERATION_CODE_READABLE,
9999, FALSE, {NULL}},
{ TEXT("__SECURITY_DESCRIPTOR"), OPERATION_CODE_READWRITE,
9999, FALSE, {NULL}},
{ NULL, 0, 0, FALSE, {0}} // end of data marker
};
//
// Same as generic save that genus is set to schema value.
//
INTF_PROP_DATA IntfPropsSchema[] =
{
// 9999 implies BSTR value got using pIADs ptr.
{ TEXT("__Class"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__Path"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__Parent"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__URL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
// end of list from IADs::get_ methods.
{ TEXT("__Genus"), OPERATION_CODE_READABLE,
UMI_TYPE_I4, FALSE, {UMI_GENUS_CLASS}},
{ TEXT("__Name"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__RELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__RELPATH"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__FULLRELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ TEXT("__SUPERCLASS"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
{ NULL, 0, 0, FALSE, {0}} // end of data marker
};
//
// Interface property data for connection objects.
//
INTF_PROP_DATA IntfPropsConnection[] =
{
{ TEXT("Class"), OPERATION_CODE_READABLE,
UMI_TYPE_LPWSTR, FALSE, {NULL} },
{ TEXT("__UserId"), OPERATION_CODE_READWRITE,
UMI_TYPE_LPWSTR, FALSE, {NULL}},
{ TEXT("__Password"), OPERATION_CODE_WRITEABLE,
UMI_TYPE_LPWSTR, FALSE, {NULL}},
{ TEXT("__SECURE_AUTHENTICATION"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {TRUE}},
{ TEXT("__NO_AUTHENTICATION"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_READONLY_SERVER"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_PROMPT_CREDENTIALS"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_SERVER_BIND"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_FAST_BIND"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_USE_SIGNING"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_USE_SEALING"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
// { TEXT("SecurityFlags"), OPERATION_CODE_READWRITE,
// UMI_TYPE_I4, FALSE, {1}},
{ NULL, 0, 0, FALSE, {0}} // end of data marker
};
//
// Interface property data for cursor objects.
//
INTF_PROP_DATA IntfPropsCursor[] =
{
{ TEXT("__Filter"), OPERATION_CODE_READWRITE,
UMI_TYPE_LPWSTR, TRUE, {NULL}},
{ NULL, 0, 0, FALSE, {0}} // end of data marker
};
//
// Interface properties for query object.
//
INTF_PROP_DATA IntfPropsQuery[]=
{
{ TEXT("__SEARCH_SCOPE"), OPERATION_CODE_READWRITE, UMI_TYPE_I4,
FALSE, {LDAP_SCOPE_SUBTREE} },
{ TEXT("__PADS_SEARCHPREF_ASYNCHRONOUS"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_SEARCHPREF_DEREF_ALIASES"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_SEARCHPREF_SIZE_LIMIT"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_TIME_LIMIT"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_ATTRIBTYPES_ONLY"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_SEARCHPREF_TIMEOUT"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_PAGESIZE"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_PAGED_TIME_LIMIT"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_CHASE_REFERRALS"), OPERATION_CODE_READWRITE,
UMI_TYPE_I4, FALSE, {ADS_CHASE_REFERRALS_EXTERNAL}},
//
// BugBug do we keep this similar to IDirectorySearch or do we not cache.
//
{ TEXT("__PADS_SEARCHPREF_CACHE_RESULTS"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {TRUE}},
{ TEXT("__PADS_SEARCHPREF_TOMBSTONE"), OPERATION_CODE_READWRITE,
UMI_TYPE_BOOL, FALSE, {FALSE}},
{ TEXT("__PADS_SEARCHPREF_FILTER"), OPERATION_CODE_READWRITE,
UMI_TYPE_LPWSTR, FALSE, {0}},
{ TEXT("__PADS_SEARCHPREF_ATTRIBUTES"), OPERATION_CODE_READWRITE,
UMI_TYPE_LPWSTR, TRUE, {0}},
{ NULL, 0, 0, FALSE, {0}} // end of data marker
};
BOOL g_fDllsLoaded = FALSE;
HANDLE g_hDllNtdsapi = NULL;
HANDLE g_hDllSecur32 = NULL;
CRITICAL_SECTION g_csLoadLibsCritSect;
// load library helper
HMODULE LoadLibraryHelper(
LPTSTR pszFileName
)
{
const DWORD iSize = GetSystemDirectory(NULL, 0);
TCHAR* buffer = NULL;
DWORD dwTemp = 0;
HMODULE handle = NULL;
if(iSize == 0)
{
goto error;
}
buffer = new TCHAR[iSize + _tcslen(__TEXT("\\")) + _tcslen(pszFileName)]; // iSize includes the NULL terminiator
if(!buffer)
{
goto error;
}
dwTemp = GetSystemDirectory(buffer, iSize);
if(dwTemp == 0)
{
goto error;
}
_tcscat(buffer, __TEXT("\\"));
_tcscat(buffer, pszFileName);
handle = LoadLibrary(buffer);
error:
if(buffer)
{
delete [] buffer;
buffer = NULL;
}
return handle;
}
//
// Loads all the dynamic libs we need.
//
void BindToDlls()
{
DWORD dwErr = 0;
if (g_fDllsLoaded) {
return;
}
ENTER_LOADLIBS_CRITSECT();
if (g_fDllsLoaded) {
LEAVE_LOADLIBS_CRITSECT();
return;
}
if (!(g_hDllNtdsapi = LoadLibraryHelper(L"NTDSAPI.DLL"))) {
dwErr = GetLastError();
}
if (g_hDllSecur32 = LoadLibraryHelper(L"SECUR32.DLL")) {
if (dwErr) {
//
// Set the last error for whatever it is worth.
// This does not really matter cause any dll we
// cannot load, we will not get functions on that
// dll. If secur32 load failed, then that call
// would have set a relevant last error.
//
SetLastError(dwErr);
}
}
g_fDllsLoaded = TRUE;
LEAVE_LOADLIBS_CRITSECT();
return;
}
//
// Loads the appropriate ntdsapi fn.
//
PVOID LoadNtDsApiFunction(CHAR *function)
{
if (!g_fDllsLoaded) {
BindToDlls();
}
if (g_hDllNtdsapi) {
return((PVOID*) GetProcAddress((HMODULE) g_hDllNtdsapi, function));
}
return NULL;
}
//
// Loads the appropriate secur32 fn.
//
PVOID LoadSecur32Function(CHAR *function)
{
if (!g_fDllsLoaded) {
BindToDlls();
}
if (g_hDllSecur32) {
return((PVOID*) GetProcAddress((HMODULE) g_hDllSecur32, function));
}
return NULL;
}
//
// DsUnquoteRdnValueWrapper
//
DWORD DsUnquoteRdnValueWrapper(
IN DWORD cQuotedRdnValueLength,
IN LPCWSTR psQuotedRdnValue,
IN OUT DWORD *pcUnquotedRdnValueLength,
OUT LPWSTR psUnquotedRdnValue
)
{
static PF_DsUnquoteRdnValueW pfDsUnquoteRdnVal = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsUnquoteRdnVal == NULL) {
pfDsUnquoteRdnVal =
(PF_DsUnquoteRdnValueW) LoadNtDsApiFunction(DSUNQUOTERDN_API);
f_LoadAttempted = TRUE;
}
if (pfDsUnquoteRdnVal != NULL) {
return ((*pfDsUnquoteRdnVal)(
cQuotedRdnValueLength,
psQuotedRdnValue,
pcUnquotedRdnValueLength,
psUnquotedRdnValue
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsMakePasswordCredentialsWrapper
//
DWORD DsMakePasswordCredentialsWrapper(
LPCWSTR User,
LPCWSTR Domain,
LPCWSTR Password,
RPC_AUTH_IDENTITY_HANDLE *pAuthIdentity
)
{
static PF_DsMakePasswordCredentialsW pfMakePwdCreds = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfMakePwdCreds == NULL) {
pfMakePwdCreds = (PF_DsMakePasswordCredentialsW)
LoadNtDsApiFunction(DSMAKEPASSWD_CRED_API);
f_LoadAttempted = TRUE;
}
if (pfMakePwdCreds != NULL) {
return ((*pfMakePwdCreds)(
User,
Domain,
Password,
pAuthIdentity
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsFreePasswordCredentialsWrapper
//
DWORD DsFreePasswordCredentialsWrapper(
RPC_AUTH_IDENTITY_HANDLE AuthIdentity
)
{
static PF_DsFreePasswordCredentials pfFreeCreds = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfFreeCreds == NULL) {
pfFreeCreds = (PF_DsFreePasswordCredentials)
LoadNtDsApiFunction(DSFREEPASSWD_CRED_API);
f_LoadAttempted = TRUE;
}
if (pfFreeCreds != NULL) {
return ((*pfFreeCreds)(
AuthIdentity
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsBindWrapper.
//
DWORD DsBindWrapper(
LPCWSTR DomainControllerName,
LPCWSTR DnsDomainName,
HANDLE *phDS
)
{
static PF_DsBindW pfDsBind = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsBind == NULL) {
pfDsBind = (PF_DsBindW) LoadNtDsApiFunction(DSBIND_API);
f_LoadAttempted = TRUE;
}
if (pfDsBind != NULL) {
return ((*pfDsBind)(
DomainControllerName,
DnsDomainName,
phDS
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsUnBindWrapper.
//
DWORD DsUnBindWrapper(
HANDLE *phDS
)
{
static PF_DsUnbindW pfDsUnbind = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsUnbind == NULL) {
pfDsUnbind = (PF_DsUnbindW) LoadNtDsApiFunction(DSUNBIND_API);
f_LoadAttempted = TRUE;
}
if (pfDsUnbind != NULL) {
return ((*pfDsUnbind)(
phDS
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsCrackNamesWrapper.
//
DWORD DsCrackNamesWrapper(
HANDLE hDS,
DS_NAME_FLAGS flags,
DS_NAME_FORMAT formatOffered,
DS_NAME_FORMAT formatDesired,
DWORD cNames,
const LPCWSTR *rpNames,
PDS_NAME_RESULTW *ppResult
)
{
static PF_DsCrackNamesW pfDsCrackNames = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsCrackNames == NULL) {
pfDsCrackNames = (PF_DsCrackNamesW)
LoadNtDsApiFunction(DSCRACK_NAMES_API);
f_LoadAttempted = TRUE;
}
if (pfDsCrackNames != NULL) {
return ((*pfDsCrackNames)(
hDS,
flags,
formatOffered,
formatDesired,
cNames,
rpNames,
ppResult
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsBindWithCredWrapper.
//
DWORD DsBindWithCredWrapper(
LPCWSTR DomainControllerName,
LPCWSTR DnsDomainName,
RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
HANDLE *phDS
)
{
static PF_DsBindWithCredW pfDsBindWithCred = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsBindWithCred == NULL) {
pfDsBindWithCred = (PF_DsBindWithCredW)
LoadNtDsApiFunction(DSBINDWITHCRED_API);
f_LoadAttempted = TRUE;
}
if (pfDsBindWithCred != NULL) {
return ((*pfDsBindWithCred)(
DomainControllerName,
DnsDomainName,
AuthIdentity,
phDS
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// DsFreeNameResultWrapper.
//
DWORD DsFreeNameResultWrapper(
DS_NAME_RESULTW *pResult
)
{
static PF_DsFreeNameResultW pfDsFreeNameResult = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfDsFreeNameResult == NULL) {
pfDsFreeNameResult = (PF_DsFreeNameResultW)
LoadNtDsApiFunction(DSFREENAME_RESULT_API);
f_LoadAttempted = TRUE;
}
if (pfDsFreeNameResult != NULL) {
return ((*pfDsFreeNameResult)(
pResult
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//
// QueryContextAttributesWrapper.
//
DWORD QueryContextAttributesWrapper(
PCtxtHandle phContext,
unsigned long ulAttribute,
void SEC_FAR * pBuffer
)
{
static PF_QueryContextAttributes pfQueryCtxtAttr = NULL;
static BOOL f_LoadAttempted = FALSE;
//
// Load the fn and set the variables accordingly.
//
if (!f_LoadAttempted && pfQueryCtxtAttr == NULL) {
pfQueryCtxtAttr = (PF_QueryContextAttributes)
LoadSecur32Function(QUERYCONTEXT_ATTR_API);
f_LoadAttempted = TRUE;
}
if (pfQueryCtxtAttr != NULL) {
return ((*pfQueryCtxtAttr)(
phContext,
ulAttribute,
pBuffer
)
);
}
else {
return (ERROR_GEN_FAILURE);
}
}
//+---------------------------------------------------------------------------
// Function: UrlToClassAndDn - global scope, helper function.
//
// Synopsis: This function takes strings of the following formats and
// returns the class name and dn part in the appropriate return
// values :
// 1) Fully qualified = user.cn=MyTestUser,
// 2) Full Name (umi) = .cn=MyTestUser,
// 3) ADSI style RDN = cn=MyTestUser.
//
// Arguments: pUrl - IUmiURL pointer.
// ppszDN - Contains returned DN (callee must free
// using FreeADsStr.
// ppszClass - Contains returned class name string. It
// is the callees responsiblity to free using
// FreeADsStrResult.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *ppszDN && *ppszClass.
//
//----------------------------------------------------------------------------
HRESULT
UrlToClassAndDn(
IN IUmiURL *pUrl,
OUT LPWSTR *ppszClass,
OUT LPWSTR *ppszDN
)
{
HRESULT hr;
WCHAR pszTxt[1024];
ULONG ulLen = 1023;
WCHAR *pszUrlTxt = pszTxt;
LPCWSTR pszUrlTxtCopy = NULL;
LPWSTR pszDN = NULL, pszClass = NULL;
DWORD dwClassCount = 0;
*ppszDN = *ppszClass = NULL;
ADsAssert(pUrl);
//
// Something on the url object telling us what is wrong will help.
//
//
// We need to get hold of the string from the url.
//
hr = pUrl->Get(0, &ulLen, pszUrlTxt);
// replace the correct error code below WBEM_E_BUFFER_TOO_SMALL
if (hr == 0x8004103c) {
//
// not enough space in our buffer, lets try again.
//
pszUrlTxt = (WCHAR*) AllocADsMem(ulLen * sizeof(WCHAR));
if (!pszUrlTxt) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = pUrl->Get(0, &ulLen, pszUrlTxt);
}
BAIL_ON_FAILURE(hr);
pszUrlTxtCopy = pszUrlTxt;
//
// Look for the . if there is one that is.
//
while (*pszUrlTxtCopy
&& (*pszUrlTxtCopy != L'.')
&& (*pszUrlTxtCopy != L'=')
) {
dwClassCount++;
pszUrlTxtCopy++;
}
if (!*pszUrlTxtCopy) {
//
// There was no = in the url has to be a bad RDN.
//
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
//
// Urls without a . or not valid.
//
if (*pszUrlTxtCopy != L'.') {
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
if (*pszUrlTxtCopy == L'=') {
//
// We do not have any class name
//
pszDN = AllocADsStr(pszUrlTxt);
if (!pszDN) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
else {
//
// If the count is zero then we have .cn=something
//
if (dwClassCount == 0) {
pszDN = AllocADsStr(++pszUrlTxtCopy);
if (!pszDN) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
}
else {
//
// A valid class name is present.
//
pszClass = (LPWSTR) AllocADsMem(sizeof(WCHAR) * (dwClassCount+1));
if (!pszClass) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
wcsncpy(pszClass, pszUrlTxt, dwClassCount);
//
// Advance beyond the . in the url and copy the rdn.
//
pszUrlTxtCopy++;
if (!*pszUrlTxtCopy) {
//
// Only class name, no RDN.
//
BAIL_ON_FAILURE(hr = E_INVALIDARG);
}
pszDN = AllocADsStr(pszUrlTxtCopy);
if (!pszDN) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
} // end of else that is dwClassCount != 0
} // end of else corresponding to class name or . present
//
// Alloc class name into new str so we can free using FreeADsStr.
//
if (pszClass) {
*ppszClass = AllocADsStr(pszClass);
if (!*ppszClass) {
BAIL_ON_FAILURE(hr);
}
FreeADsMem(pszClass);
}
*ppszDN = pszDN;
error:
if (pszUrlTxt && (pszUrlTxt != pszTxt)) {
FreeADsMem(pszUrlTxt);
}
//
// Free the DN and Class only if applicable.
//
if (FAILED(hr)) {
if (pszDN) {
FreeADsStr(pszDN);
}
if (pszClass) {
FreeADsMem(pszClass);
}
}
RRETURN(hr);
}
HRESULT
GetRDn(
IUmiURL *pURL,
DWORD dwComponent,
LPWSTR pszRDn,
DWORD dwRDnLen
)
{
HRESULT hr = S_OK;
IUmiURLKeyList * pKeyList = NULL;
DWORD dwLen = dwRDnLen;
DWORD dwKeyNameLen = 64;
WCHAR szKeyName[64];
LPWSTR pszTmpStr = NULL;
BOOL fSchema = FALSE;
pszTmpStr = (WCHAR*)AllocADsMem(dwRDnLen);
if (!pszTmpStr) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Get the component we need, num is passed in.
//
hr = pURL->GetComponent(
dwComponent,
&dwLen,
pszRDn,
&pKeyList
);
BAIL_ON_FAILURE(hr);
if (!pKeyList) {
BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
}
//
// Make sure that the key count is only one, anything
//else cannot be an LDAP path component.
//
hr = pKeyList->GetCount(&dwLen);
BAIL_ON_FAILURE(hr);
if (dwLen != 1) {
//
// Need to see if we have the pszRDN set, if so that is the
// RDN itself - for example Schema or RootDSE.
//
if (pszRDn) {
goto error;
}
BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
}
dwLen = dwRDnLen;
//
// Get the RDN from the key !.
//
hr = pKeyList->GetKey(
0,
0,
&dwKeyNameLen,
szKeyName,
&dwLen,
pszTmpStr
);
BAIL_ON_FAILURE(hr);
//
// We need to special case class.Name=User. This means
// we are looking for a class called user not an instance
// of class with RDN Name=User.
//
fSchema = !_wcsicmp(pszRDn, L"Class")
|| !_wcsicmp(pszRDn, L"Schema")
|| !_wcsicmp(pszRDn, L"Property")
|| !_wcsicmp(pszRDn, L"Syntax");
if (fSchema
&& szKeyName
&& !_wcsicmp(szKeyName, L"Name")
) {
//
// We have class.Name=User.
//
wsprintf(pszRDn, L"%s", pszTmpStr);
}
else {
//
// We have right values and this is the normal code path.
//
wsprintf(pszRDn, L"%s=",szKeyName);
wcscat(pszRDn, pszTmpStr);
}
error:
if (pKeyList) {
pKeyList->Release();
}
if (pszTmpStr) {
FreeADsMem(pszTmpStr);
}
RRETURN(hr);
}
HRESULT
GetDNFromURL(
IUmiURL *pURL,
LPWSTR *pszDnStr,
DWORD dwTotalLen
)
{
HRESULT hr = S_OK;
DWORD dwNumComponents = 0, dwCtr = 0;
LPWSTR pszLocalDn = NULL;
LPWSTR pszRDn = NULL;
*pszDnStr = NULL;
hr = pURL->GetComponentCount(&dwNumComponents);
BAIL_ON_FAILURE(hr);
if (dwNumComponents == 0) {
//
// DnStr is NULL in this case.
//
RRETURN(hr);
}
//
// This is for the retval.
//
pszLocalDn = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
if (!pszLocalDn) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// This is for the rdn's, this buffer should be more than enough
//
pszRDn = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
if (!pszRDn) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// We need to get each of the individuals dn's and keep adding
// them to the dn we return.
//
for (dwCtr = 0; dwCtr < dwNumComponents; dwCtr++) {
*pszRDn = NULL;
hr = GetRDn(pURL, (dwNumComponents-1) - dwCtr, pszRDn, dwTotalLen);
BAIL_ON_FAILURE(hr);
if (*pszRDn) {
wcscat(pszLocalDn, pszRDn);
if (dwCtr != (dwNumComponents - 1)) {
wcscat(pszLocalDn, L",");
}
}
else {
BAIL_ON_FAILURE(hr = E_FAIL);
}
}
//
// We must have the correct DN !
//
*pszDnStr = pszLocalDn;
error:
if (FAILED(hr)) {
if (pszLocalDn) {
FreeADsMem(pszLocalDn);
}
}
if (pszRDn) {
FreeADsMem(pszRDn);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: UrlToLDAPPath - global scope, helper function.
//
// Synopsis: This routine converts the URL to the
//
// Arguments: pURL - URL to be converted to path. Note
// that this can be native or Umi.
// pszLDAPPath - Path is allocated into this var.
// ppszDn -
// ppszClass - Contains returned class name string. It
// is the callees responsiblity to free using
// FreeADsStrResult.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *ppszDN && *ppszClass.
//
//----------------------------------------------------------------------------
HRESULT
UrlToLDAPPath(
IN IUmiURL *pURL,
OUT LPWSTR *ppszLDAPPath,
OPTIONAL OUT LPWSTR *ppszDn,
OPTIONAL OUT LPWSTR *ppszServer
)
{
HRESULT hr = S_OK;
DWORD dwURLType = 0;
DWORD dwLen = 1023;
DWORD dwTxtLen = 1023;
WCHAR pszTxt[1024];
LPWSTR pszDn = NULL;
LPWSTR pszLdapPath = NULL;
BOOL fAddSlash = FALSE;
ULONGLONG ululPathType = UMIPATH_INFO_INSTANCE_PATH;
//
// We need the type of the url, if it is an ldap native path.
// For now though this support is not available. We assume that
// this is a umi path for now.
//
//
// Get the total length needed for the path.
//
hr = pURL->Get(0, &dwLen, pszTxt);
// replace the correct error code below WBEM_E_BUFFER_TOO_SMALL
if ((FAILED(hr) && (hr != 0x8004103c))
|| (dwLen == 0)) {
//
// Failure was either length was zero or error was someting
// other than buffer too small.
//
BAIL_ON_FAILURE(hr);
}
dwLen++; // for the terminating \0.
pszLdapPath = (LPWSTR) AllocADsMem(dwLen * sizeof(WCHAR));
if (!pszLdapPath) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
hr = pURL->GetPathInfo(0, &ululPathType);
BAIL_ON_FAILURE(hr);
if (ululPathType == UMIPATH_INFO_NATIVE_STRING) {
//
// Just get the path in pszLdapPath and return.
//
hr = pURL->Get(0, &dwLen, pszLdapPath);
BAIL_ON_FAILURE(hr);
}
else {
//
// Make sure that the namespace is either LDAP or GC.
// We bail on failure cause we cannot possibly have a locator
// that is more than our buffer size !
//
hr = pURL->GetRootNamespace(&dwTxtLen, pszTxt);
BAIL_ON_FAILURE(hr);
if (!_wcsicmp(L"LDAP", pszTxt)) {
wsprintf(pszLdapPath, L"%s", L"LDAP:");
}
else if (!_wcsicmp(L"GC", pszTxt)) {
wsprintf(pszLdapPath, L"%s", L"GC:");
}
else {
BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
}
//
// We now need to add the server and the // if applicable.
//
dwTxtLen = 1023;
hr = pURL->GetLocator(&dwTxtLen, pszTxt);
if (hr == 0x8004103c) {
//
// Unexpected cause locator is too big !.
//
hr = E_FAIL;
}
BAIL_ON_FAILURE(hr);
if (!wcscmp(pszTxt, L".")) {
//
// This would mean we are going serverless.
//
wcscat(pszLdapPath, L"/");
}
else if (!*pszTxt) {
//
// Means that we have the LDAP namespace or no server.
//
fAddSlash = TRUE;
}
else {
//
// Add the // and the servername given.
//
wcscat(pszLdapPath, L"//");
wcscat(pszLdapPath, pszTxt);
}
//
// Now we need to get the DN and tag it along.
//
hr = GetDNFromURL(pURL, &pszDn, dwLen);
BAIL_ON_FAILURE(hr);
if (pszDn && *pszDn) {
if (fAddSlash) {
//
// Serverless path.
//
wcscat(pszLdapPath, L"/");
}
//
// Tag on the DN now, it will do the right thing for
// both server and serverless paths.
//
wcscat(pszLdapPath,L"/");
wcscat(pszLdapPath,pszDn);
}
} // this was not a native path.
*ppszLDAPPath = pszLdapPath;
error:
if (FAILED(hr)) {
if (pszLdapPath) {
FreeADsMem(pszLdapPath);
}
}
if (pszDn) {
FreeADsMem(pszDn);
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: ADsPathToUmiUrl - global scope, helper function.
//
// Synopsis: This routine converts the ADsPath to UMI URL txt.
//
// Arguments: ADsPath - Input string.
// ppszUrlTxt - Output converted url txt.
//
// Returns: HRESULT - S_OK or any failure ecode.
//
// Modifies: *ppszUrlTxt - to point to the correct
//
//----------------------------------------------------------------------------
HRESULT
ADsPathToUmiURL(
IN LPWSTR ADsPath,
OUT LPWSTR *ppszUrlTxt
)
{
HRESULT hr = S_OK;
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = &ObjectInfo;
DWORD dwNumComponents = 0, dwCtr;
LPWSTR pszUrl = NULL;
BOOL fReverseOrder = TRUE;
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
ADsAssert(ADsPath && ppszUrlTxt);
*ppszUrlTxt = NULL;
//
// We build our ObjectInfo struct and then build the url
// from the objectInfo struct.
//
pObjectInfo->ObjectType = TOKEN_LDAPOBJECT;
hr = ADsObject(ADsPath, pObjectInfo);
BAIL_ON_FAILURE(hr);
dwNumComponents = pObjectInfo->NumComponents;
//
// We can make a guess as to the size we need for the string.
//
pszUrl = (WCHAR *) AllocADsMem(
( sizeof(WCHAR) * wcslen(ADsPath) )
// for the actual name
+ (sizeof(WCHAR) * dwNumComponents)
// for all the .'s we need as in .DC=test
+ (sizeof(WCHAR) * 15)
);
//
// sizeof(WCHAR) * 15 has been added so that we can handle
// the umi:// (6) which is extra + if we have a GC path, then
// we would need to add LDAP/ (5) just in case a small buffer
// of 4 giving the 15
//
if (!pszUrl) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// Get the umi:// in the output, then add the server if applicable,
// then the LDAP/GC or LDAP alone as applicable.
//
wsprintf(pszUrl, L"%s", L"umi://");
if (pObjectInfo->dwServerPresent) {
if (pObjectInfo->TreeName) {
wcscat(pszUrl, pObjectInfo->TreeName);
}
}
wcscat(pszUrl, L"/"); // need if there is a server or not.
wcscat(pszUrl, L"LDAP"); // needed if LDAP or GC.
if (!_wcsicmp(pObjectInfo->ProviderName, szGCNamespaceName)) {
wcscat(pszUrl, L"/GC");
}
//
// This is to check if we were given an LDAP windows style path,
// with reverse order rather than LDAP dn style path.
//
if (pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST) {
//
// Already reversed so just use the order directly.
//
for (dwCtr = 0; dwCtr < dwNumComponents; dwCtr++) {
//
// When you have a path like LDAP://RootDSE, then the szComponent
// alone is set and not the value in these cases we need to
// build the path in a different manner.
//
if (pObjectInfo->ComponentArray[dwCtr].szValue) {
wcscat(pszUrl, L"/.");
wcscat(
pszUrl,
pObjectInfo->ComponentArray[dwCtr].szComponent
);
wcscat(pszUrl, L"=");
wcscat(pszUrl, pObjectInfo->ComponentArray[dwCtr].szValue);
}
else {
//
// We just have a component as in RootDSE or Schema so.
//
wcscat(pszUrl, L"/");
wcscat(
pszUrl,
pObjectInfo->ComponentArray[dwCtr].szComponent
);
}
}
}
else {
//
// Need to do this reverse order.
//
for (dwCtr = dwNumComponents; dwCtr > 0; dwCtr--) {
//
// When you have a path like LDAP://RootDSE, then the szComponent
// alone is set and not the value in these cases we need to
// build the path in a different manner.
//
if (pObjectInfo->ComponentArray[dwCtr-1].szValue) {
wcscat(pszUrl, L"/.");
wcscat(
pszUrl,
pObjectInfo->ComponentArray[dwCtr-1].szComponent
);
wcscat(pszUrl, L"=");
wcscat(pszUrl, pObjectInfo->ComponentArray[dwCtr-1].szValue);
}
else {
//
// We just have a component as in RootDSE or Schema so.
//
wcscat(pszUrl, L"/");
wcscat(
pszUrl,
pObjectInfo->ComponentArray[dwCtr-1].szComponent
);
}
}
}
*ppszUrlTxt = pszUrl;
error:
if (FAILED(hr)) {
if (pszUrl) {
FreeADsMem(pszUrl);
}
}
if (pObjectInfo) {
FreeObjectInfo(pObjectInfo);
}
RRETURN(hr);
}
BOOL
IsPreDefinedErrorCode(HRESULT hr)
{
switch (hr) {
case E_UNEXPECTED :
case E_NOTIMPL :
case E_OUTOFMEMORY :
case E_INVALIDARG :
case E_NOINTERFACE :
case E_HANDLE :
case E_ABORT :
case E_FAIL :
case E_ACCESSDENIED :
case E_PENDING :
case E_POINTER :
case UMI_E_CONNECTION_FAILURE :
case UMI_E_TIMED_OUT :
case UMI_E_TYPE_MISMATCH :
case UMI_E_NOT_FOUND :
case UMI_E_INVALID_FLAGS :
case UMI_E_UNSUPPORTED_FLAGS :
case UMI_E_SYNCHRONIZATION_REQUIRED :
case UMI_E_UNSUPPORTED_OPERATION :
case UMI_E_TRANSACTION_FAILURE :
RRETURN(TRUE);
break;
default:
RRETURN(FALSE);
break;
}
}
//+---------------------------------------------------------------------------
// Function: MapHrToUmiError - global scope, helper function.
//
// Synopsis: This routine converts the given hr to an equivalent umi err.
//
// Arguments: hr - hr to convert to umi error.
//
// Returns: HRESULT - umi error code corresponing to hr passed in.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT
MapHrToUmiError(HRESULT hr)
{
HRESULT retHr = hr;
if (IsPreDefinedErrorCode(hr)) {
RRETURN(hr);
}
switch (hr) {
case E_ADS_INVALID_DOMAIN_OBJECT:
case E_ADS_INVALID_USER_OBJECT:
case E_ADS_INVALID_COMPUTER_OBJECT:
case E_ADS_UNKNOWN_OBJECT:
retHr = UMI_E_NOT_FOUND;
break;
case E_ADS_PROPERTY_NOT_FOUND:
retHr = UMI_E_NOT_FOUND;
break;
case E_ADS_BAD_PARAMETER:
retHr = E_INVALIDARG;
break;
case E_ADS_CANT_CONVERT_DATATYPE:
retHr = UMI_E_TYPE_MISMATCH;
break;
case E_ADS_BAD_PATHNAME:
retHr = E_INVALIDARG;
break;
case HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) :
// LDAP_NO_SUCH_ATTRIBUTE
retHr = UMI_E_NOT_FOUND;
break;
case HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) :
// LDAP_NO_SUCH_OBJECT
retHr = UMI_E_NOT_FOUND;
break;
default:
retHr = E_FAIL;
break;
} // end of case
RRETURN(retHr);
}