1337 lines
35 KiB
C++
1337 lines
35 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;
|
||
|
|
||
|
//
|
||
|
// 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 = LoadLibrary(L"NTDSAPI.DLL"))) {
|
||
|
dwErr = GetLastError();
|
||
|
}
|
||
|
|
||
|
if (g_hDllSecur32 = LoadLibrary(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);
|
||
|
}
|
||
|
|