546 lines
13 KiB
C++
546 lines
13 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
rndldap.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains implementation of ldap helper functions.
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include "rndldap.h"
|
||
|
#include "ntldap.h"
|
||
|
|
||
|
|
||
|
HRESULT GetAttributeValue(
|
||
|
IN LDAP * pLdap,
|
||
|
IN LDAPMessage * pEntry,
|
||
|
IN const WCHAR * pName,
|
||
|
OUT BSTR * pValue
|
||
|
)
|
||
|
{
|
||
|
*pValue = NULL;
|
||
|
|
||
|
TCHAR **p = ldap_get_values(pLdap, pEntry, (WCHAR *)pName);
|
||
|
if (p != NULL)
|
||
|
{
|
||
|
if (p[0] != NULL)
|
||
|
{
|
||
|
*pValue = SysAllocString(p[0]);
|
||
|
}
|
||
|
ldap_value_free(p);
|
||
|
}
|
||
|
|
||
|
return (*pValue == NULL) ? E_FAIL : S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT GetAttributeValueBer(
|
||
|
IN LDAP * pLdap,
|
||
|
IN LDAPMessage * pEntry,
|
||
|
IN const WCHAR * pName,
|
||
|
OUT char ** pValue,
|
||
|
OUT DWORD * pdwSize
|
||
|
)
|
||
|
{
|
||
|
*pValue = NULL;
|
||
|
|
||
|
struct berval **p = ldap_get_values_len(pLdap, pEntry, (WCHAR *)pName);
|
||
|
if (p != NULL)
|
||
|
{
|
||
|
if (p[0] != NULL)
|
||
|
{
|
||
|
*pValue = new CHAR[p[0]->bv_len];
|
||
|
if (*pValue == NULL)
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
memcpy(*pValue, p[0]->bv_val, p[0]->bv_len);
|
||
|
*pdwSize = p[0]->bv_len;
|
||
|
}
|
||
|
ldap_value_free_len(p);
|
||
|
}
|
||
|
return (*pValue == NULL) ? E_FAIL : S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT GetNamingContext(LDAP *hLdap, TCHAR **ppNamingContext)
|
||
|
{
|
||
|
// send a search (base level, base dn = "", filter = "objectclass=*")
|
||
|
// ask only for the defaultNamingContext attribute
|
||
|
PTCHAR Attributes[] = {(WCHAR *)DEFAULT_NAMING_CONTEXT, NULL};
|
||
|
|
||
|
LDAPMessage *SearchResult;
|
||
|
|
||
|
ULONG res = DoLdapSearch(
|
||
|
hLdap, // ldap handle
|
||
|
L"", // empty base dn
|
||
|
LDAP_SCOPE_BASE, // base level search
|
||
|
(WCHAR *)ANY_OBJECT_CLASS, // instance of any object class
|
||
|
Attributes, // array of attribute names
|
||
|
FALSE, // also return the attribute values
|
||
|
&SearchResult // search results
|
||
|
);
|
||
|
|
||
|
BAIL_IF_LDAP_FAIL(res, "Search for oganization");
|
||
|
|
||
|
// associate the ldap handle with the search message holder, so that the
|
||
|
// search message may be released when the instance goes out of scope
|
||
|
CLdapMsgPtr MessageHolder(SearchResult);
|
||
|
|
||
|
TCHAR **NamingContext;
|
||
|
|
||
|
LDAPMessage *EntryMessage = ldap_first_entry(hLdap, SearchResult);
|
||
|
while ( NULL != EntryMessage )
|
||
|
{
|
||
|
// look for the value for the namingContexts attribute
|
||
|
NamingContext = ldap_get_values(
|
||
|
hLdap,
|
||
|
EntryMessage,
|
||
|
(WCHAR *)DEFAULT_NAMING_CONTEXT
|
||
|
);
|
||
|
|
||
|
// the first entry contains the naming context and its a single
|
||
|
// value(null terminated) if a value is found, create memory for
|
||
|
// the directory path, set the dir path length
|
||
|
if ( (NULL != NamingContext) &&
|
||
|
(NULL != NamingContext[0]) &&
|
||
|
(NULL == NamingContext[1]) )
|
||
|
{
|
||
|
// the naming context value is released when the ValueHolder
|
||
|
// instance goes out of scope
|
||
|
CLdapValuePtr ValueHolder(NamingContext);
|
||
|
|
||
|
*ppNamingContext = new TCHAR [lstrlen(NamingContext[0]) + 1];
|
||
|
|
||
|
BAIL_IF_NULL(*ppNamingContext, E_OUTOFMEMORY);
|
||
|
|
||
|
lstrcpy(*ppNamingContext, NamingContext[0]);
|
||
|
|
||
|
// return success
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Get next entry.
|
||
|
EntryMessage = ldap_next_entry(hLdap, EntryMessage);
|
||
|
}
|
||
|
|
||
|
// none found, return error
|
||
|
return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
DoLdapSearch (
|
||
|
LDAP *ld,
|
||
|
PWCHAR base,
|
||
|
ULONG scope,
|
||
|
PWCHAR filter,
|
||
|
PWCHAR attrs[],
|
||
|
ULONG attrsonly,
|
||
|
LDAPMessage **res,
|
||
|
BOOL bSACL /*=TRUE */
|
||
|
)
|
||
|
{
|
||
|
LDAP_TIMEVAL Timeout;
|
||
|
Timeout.tv_sec = REND_LDAP_TIMELIMIT;
|
||
|
Timeout.tv_usec = 0;
|
||
|
|
||
|
//
|
||
|
// Without SACLs
|
||
|
//
|
||
|
SECURITY_INFORMATION seInfo =
|
||
|
DACL_SECURITY_INFORMATION |
|
||
|
OWNER_SECURITY_INFORMATION |
|
||
|
GROUP_SECURITY_INFORMATION;
|
||
|
|
||
|
//
|
||
|
// Ber val
|
||
|
//
|
||
|
BYTE berValue[2*sizeof(ULONG)];
|
||
|
berValue[0] = 0x30;
|
||
|
berValue[1] = 0x03;
|
||
|
berValue[2] = 0x02;
|
||
|
berValue[3] = 0x01;
|
||
|
berValue[4] = (BYTE)(seInfo & 0xF);
|
||
|
|
||
|
//
|
||
|
// LDAP server control
|
||
|
//
|
||
|
LDAPControlW seInfoControl = {
|
||
|
LDAP_SERVER_SD_FLAGS_OID_W,
|
||
|
{5, (PCHAR)berValue},
|
||
|
TRUE
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// LDAP Server controls list
|
||
|
//
|
||
|
PLDAPControlW serverControls[2] = { &seInfoControl, NULL};
|
||
|
PLDAPControlW* pServerControls = NULL;
|
||
|
if( !bSACL )
|
||
|
{
|
||
|
pServerControls = serverControls;
|
||
|
}
|
||
|
|
||
|
ULONG ulRes = ldap_search_ext_sW(ld,
|
||
|
base,
|
||
|
scope,
|
||
|
filter,
|
||
|
attrs,
|
||
|
attrsonly,
|
||
|
pServerControls, // server controls
|
||
|
NULL, // client controls
|
||
|
&Timeout, // timeout value
|
||
|
0, // maximum size
|
||
|
res);
|
||
|
|
||
|
//
|
||
|
// The ldap_search* APIs are quirky in that they require you to free the
|
||
|
// result even if the call fails. ldap_msgfree() checks its argument, so
|
||
|
// this also doesn't break if the result *wasn't* left around. This is
|
||
|
// inconsistent with pretty much all other Windows system APIs; to keep
|
||
|
// from obfuscating the callers of DoLdapSearch, we free the result here
|
||
|
// in the failure case. That way, callers can treat DoLdapSearch like any
|
||
|
// other function that cleans up after itself on failure.
|
||
|
//
|
||
|
// Some callers use smart pointers that would free the message on destruction,
|
||
|
// and some do not. Therefore we set *res to NULL after freeing *res, to
|
||
|
// protect ourselves in either case. Any subsequent ldap_msgfree(NULL) will
|
||
|
// do nothing (and will not fault).
|
||
|
//
|
||
|
|
||
|
if ( ulRes != LDAP_SUCCESS )
|
||
|
{
|
||
|
ldap_msgfree( *res );
|
||
|
*res = NULL;
|
||
|
}
|
||
|
|
||
|
return ulRes;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Translates the result of an ldap_result call to an ldap error code.
|
||
|
//
|
||
|
|
||
|
ULONG LdapErrorFromLdapResult(ULONG res, LDAPMessage * pResultMessage)
|
||
|
{
|
||
|
ULONG ulCode;
|
||
|
|
||
|
if ( res == 0 )
|
||
|
{
|
||
|
ulCode = LDAP_TIMEOUT;
|
||
|
}
|
||
|
else if ( res == (ULONG) -1 )
|
||
|
{
|
||
|
ulCode = LDAP_LOCAL_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ulCode = LDAP_SUCCESS;
|
||
|
ulCode = pResultMessage->lm_returncode;
|
||
|
}
|
||
|
|
||
|
ldap_msgfree( pResultMessage );
|
||
|
|
||
|
return ulCode;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
DoLdapAdd (
|
||
|
LDAP *ld,
|
||
|
PWCHAR dn,
|
||
|
LDAPModW *attrs[]
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Ask to add an object.We get back an error/success code and a
|
||
|
// message number so that we can refer to this pending message.
|
||
|
//
|
||
|
|
||
|
ULONG ulMessageNumber;
|
||
|
|
||
|
ULONG res1 = ldap_add_extW(ld,
|
||
|
dn,
|
||
|
attrs,
|
||
|
NULL, // server controls
|
||
|
NULL, // client controls
|
||
|
&ulMessageNumber);
|
||
|
|
||
|
BAIL_IF_LDAP_FAIL(res1, "ldap_add_extW");
|
||
|
|
||
|
//
|
||
|
// Wait for the result, specifying a timeout. We get
|
||
|
// back an error/success code and a result message.
|
||
|
//
|
||
|
|
||
|
LDAP_TIMEVAL Timeout;
|
||
|
Timeout.tv_sec = REND_LDAP_TIMELIMIT;
|
||
|
Timeout.tv_usec = 0;
|
||
|
|
||
|
LDAPMessage * pResultMessage;
|
||
|
|
||
|
ULONG res2 = ldap_result(ld,
|
||
|
ulMessageNumber,
|
||
|
LDAP_MSG_ALL,
|
||
|
&Timeout,
|
||
|
&pResultMessage);
|
||
|
|
||
|
//
|
||
|
// Extract return code and free message.
|
||
|
//
|
||
|
|
||
|
return LdapErrorFromLdapResult(res2, pResultMessage);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
DoLdapModify (
|
||
|
BOOL fChase,
|
||
|
LDAP *ld,
|
||
|
PWCHAR dn,
|
||
|
LDAPModW *attrs[],
|
||
|
BOOL bSACL /*=TRUE */
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Chase referrals. These is only used if fChase is set, but we must not
|
||
|
// stick them in an "if" block or they will not have appropriate scope.
|
||
|
//
|
||
|
|
||
|
LDAPControlW control;
|
||
|
LDAPControlW * controls [] = {&control, NULL};
|
||
|
ULONG ulValue = LDAP_CHASE_EXTERNAL_REFERRALS | LDAP_CHASE_SUBORDINATE_REFERRALS;
|
||
|
|
||
|
if ( fChase )
|
||
|
{
|
||
|
control.ldctl_iscritical = 1;
|
||
|
control.ldctl_oid = LDAP_CONTROL_REFERRALS_W;
|
||
|
control.ldctl_value.bv_len = sizeof(ULONG);
|
||
|
control.ldctl_value.bv_val = (char *) &ulValue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Without SACLs
|
||
|
//
|
||
|
SECURITY_INFORMATION seInfo = DACL_SECURITY_INFORMATION ;
|
||
|
|
||
|
//
|
||
|
// Ber val
|
||
|
//
|
||
|
BYTE berValue[2*sizeof(ULONG)];
|
||
|
berValue[0] = 0x30;
|
||
|
berValue[1] = 0x03;
|
||
|
berValue[2] = 0x02;
|
||
|
berValue[3] = 0x01;
|
||
|
berValue[4] = (BYTE)(seInfo & 0xF);
|
||
|
|
||
|
//
|
||
|
// LDAP server control
|
||
|
//
|
||
|
LDAPControlW seInfoControl = {
|
||
|
LDAP_SERVER_SD_FLAGS_OID_W,
|
||
|
{5, (PCHAR)berValue},
|
||
|
TRUE
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// LDAP Server controls list
|
||
|
//
|
||
|
PLDAPControlW serverControls[2] = { &seInfoControl, NULL};
|
||
|
PLDAPControlW* pServerControls = NULL;
|
||
|
if( !bSACL )
|
||
|
{
|
||
|
pServerControls = serverControls;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Ask to modify an object.We get back an error/success code and a
|
||
|
// message number so that we can refer to this pending message.
|
||
|
//
|
||
|
|
||
|
ULONG ulMessageNumber;
|
||
|
|
||
|
ULONG res1 = ldap_modify_extW(ld,
|
||
|
dn,
|
||
|
attrs,
|
||
|
pServerControls, // server controls
|
||
|
fChase ? controls : NULL, // client controls
|
||
|
&ulMessageNumber);
|
||
|
|
||
|
BAIL_IF_LDAP_FAIL(res1, "ldap_modify_extW");
|
||
|
|
||
|
//
|
||
|
// Wait for the result, specifying a timeout. We get
|
||
|
// back an error/success code and a result message.
|
||
|
//
|
||
|
|
||
|
LDAP_TIMEVAL Timeout;
|
||
|
Timeout.tv_sec = REND_LDAP_TIMELIMIT;
|
||
|
Timeout.tv_usec = 0;
|
||
|
|
||
|
LDAPMessage * pResultMessage;
|
||
|
|
||
|
ULONG res2 = ldap_result(ld,
|
||
|
ulMessageNumber,
|
||
|
LDAP_MSG_ALL,
|
||
|
&Timeout,
|
||
|
&pResultMessage);
|
||
|
|
||
|
//
|
||
|
// Extract return code and free message.
|
||
|
//
|
||
|
|
||
|
return LdapErrorFromLdapResult(res2, pResultMessage);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
DoLdapDelete (
|
||
|
LDAP *ld,
|
||
|
PWCHAR dn
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Ask to delete an object.We get back an error/success code and a
|
||
|
// message number so that we can refer to this pending message.
|
||
|
//
|
||
|
|
||
|
ULONG ulMessageNumber;
|
||
|
|
||
|
ULONG res1 = ldap_delete_extW(ld,
|
||
|
dn,
|
||
|
NULL, // server controls
|
||
|
NULL, // client controls
|
||
|
&ulMessageNumber);
|
||
|
|
||
|
BAIL_IF_LDAP_FAIL(res1, "ldap_delete_extW");
|
||
|
|
||
|
//
|
||
|
// Wait for the result, specifying a timeout. We get
|
||
|
// back an error/success code and a result message.
|
||
|
//
|
||
|
|
||
|
LDAP_TIMEVAL Timeout;
|
||
|
Timeout.tv_sec = REND_LDAP_TIMELIMIT;
|
||
|
Timeout.tv_usec = 0;
|
||
|
|
||
|
LDAPMessage * pResultMessage;
|
||
|
|
||
|
ULONG res2 = ldap_result(ld,
|
||
|
ulMessageNumber,
|
||
|
LDAP_MSG_ALL,
|
||
|
&Timeout,
|
||
|
&pResultMessage);
|
||
|
|
||
|
//
|
||
|
// Extract return code and free message.
|
||
|
//
|
||
|
|
||
|
return LdapErrorFromLdapResult(res2, pResultMessage);
|
||
|
}
|
||
|
|
||
|
HRESULT SetTTL(
|
||
|
IN LDAP * pLdap,
|
||
|
IN const WCHAR * pDN,
|
||
|
IN DWORD dwTTL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Set the TTL of a dynamic object for either ILS or NDNC.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pLdap - The Ldap connection.
|
||
|
|
||
|
pDN - The DN of a object on the ILS server.
|
||
|
|
||
|
dwTTL - The time to live value.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
HRESULT.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TCHAR strTTL[32]; // The attribute value is a DWORD in string.
|
||
|
wsprintf(strTTL, _T("%d"), dwTTL);
|
||
|
|
||
|
TCHAR * ttl[] = {strTTL, NULL};
|
||
|
|
||
|
LDAPMod mod; // The modify sturctures used by LDAP
|
||
|
mod.mod_values = ttl;
|
||
|
mod.mod_op = LDAP_MOD_REPLACE;
|
||
|
mod.mod_type = (WCHAR *)ENTRYTTL;
|
||
|
|
||
|
LDAPMod* mods[] = {&mod, NULL}; // only one attribute is modified.
|
||
|
|
||
|
LOG((MSP_INFO, "setting TTL for %S", pDN));
|
||
|
|
||
|
BAIL_IF_LDAP_FAIL(DoLdapModify(FALSE, pLdap, (WCHAR *)pDN, mods), "set TTL");
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT UglyIPtoIP(
|
||
|
BSTR pUglyIP,
|
||
|
BSTR * pIP
|
||
|
)
|
||
|
// This function converts NM's IP address format to the right format.
|
||
|
{
|
||
|
#define IPADDRLEN 16
|
||
|
WCHAR buffer[IPADDRLEN + 1];
|
||
|
DWORD dwIP;
|
||
|
|
||
|
dwIP = _wtoi(pUglyIP);
|
||
|
if (dwIP == 0)
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
dwIP = ntohl(dwIP);
|
||
|
|
||
|
// format the four bytes in the dword into an ip address string
|
||
|
swprintf(buffer, L"%d.%d.%d.%d",
|
||
|
HIBYTE(HIWORD(dwIP)),
|
||
|
LOBYTE(HIWORD(dwIP)),
|
||
|
HIBYTE(LOWORD(dwIP)),
|
||
|
LOBYTE(LOWORD(dwIP))
|
||
|
);
|
||
|
|
||
|
*pIP = SysAllocString(buffer);
|
||
|
|
||
|
BAIL_IF_NULL(*pIP, E_OUTOFMEMORY);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT ParseUserName(
|
||
|
BSTR pName,
|
||
|
BSTR * ppAddress
|
||
|
)
|
||
|
{
|
||
|
WCHAR * pCloseBracket = wcschr(pName, CLOSE_BRACKET_CHARACTER);
|
||
|
|
||
|
if ( pCloseBracket == NULL )
|
||
|
{
|
||
|
// this is not the format generated by us.
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
*ppAddress = SysAllocString(pCloseBracket + 1);
|
||
|
|
||
|
BAIL_IF_NULL(*ppAddress, E_OUTOFMEMORY);
|
||
|
|
||
|
*pCloseBracket = NULL_CHARACTER;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// eof
|