windows-nt/Source/XPSP1/NT/net/tapi/skywalker/rend/rndldap.cpp
2020-09-26 16:20:57 +08:00

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