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.
814 lines
16 KiB
814 lines
16 KiB
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation, 1996
|
|
//
|
|
// Description:
|
|
//
|
|
// Microsoft Internet LDAP Client RFC 1823 API
|
|
//
|
|
//
|
|
// History
|
|
// davidsan 06/17/96 Created
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
// note: this is ugly code. all i'm doing is mapping things to my API in as painless a way
|
|
// as i can.
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// INCLUDES
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
#include "ldappch.h"
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// PROTOTYPES
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// GLOBALS
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// FUNCTIONS
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
int
|
|
LdapResFromHr(HRESULT hr)
|
|
{
|
|
switch (hr)
|
|
{
|
|
default:
|
|
return LDAP_LOCAL_ERROR;
|
|
|
|
case NOERROR:
|
|
return LDAP_SUCCESS;
|
|
|
|
case LDAP_E_OPERATIONS:
|
|
return LDAP_OPERATIONS_ERROR;
|
|
|
|
case LDAP_E_PROTOCOL:
|
|
return LDAP_PROTOCOL_ERROR;
|
|
|
|
case LDAP_S_TIMEEXCEEDED:
|
|
return LDAP_TIMELIMIT_EXCEEDED;
|
|
|
|
case LDAP_S_SIZEEXCEEDED:
|
|
return LDAP_SIZELIMIT_EXCEEDED;
|
|
|
|
case S_FALSE:
|
|
return LDAP_COMPARE_FALSE;
|
|
|
|
case LDAP_E_AUTHMETHOD:
|
|
return LDAP_AUTH_METHOD_NOT_SUPPORTED;
|
|
|
|
case LDAP_E_STRONGAUTHREQUIRED:
|
|
return LDAP_STRONG_AUTH_REQUIRED;
|
|
|
|
case LDAP_E_NOSUCHATTRIBUTE:
|
|
return LDAP_NO_SUCH_ATTRIBUTE;
|
|
|
|
case LDAP_E_UNDEFINEDTYPE:
|
|
return LDAP_UNDEFINED_TYPE;
|
|
|
|
case LDAP_E_MATCHING:
|
|
return LDAP_INAPPROPRIATE_MATCHING;
|
|
|
|
case LDAP_E_CONSTRAINT:
|
|
return LDAP_CONSTRAINT_VIOLATION;
|
|
|
|
case LDAP_E_ATTRIBORVALEXISTS:
|
|
return LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
|
|
|
|
case LDAP_E_SYNTAX:
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
case LDAP_E_NOSUCHOBJECT:
|
|
return LDAP_NO_SUCH_OBJECT;
|
|
|
|
case LDAP_E_ALIAS:
|
|
return LDAP_ALIAS_PROBLEM;
|
|
|
|
case LDAP_E_DNSYNTAX:
|
|
return LDAP_INVALID_DN_SYNTAX;
|
|
|
|
case LDAP_E_ISLEAF:
|
|
return LDAP_IS_LEAF;
|
|
|
|
case LDAP_E_ALIASDEREF:
|
|
return LDAP_ALIAS_DEREF_PROBLEM;
|
|
|
|
case LDAP_E_AUTH:
|
|
return LDAP_INAPPROPRIATE_AUTH;
|
|
|
|
case LDAP_E_CREDENTIALS:
|
|
return LDAP_INVALID_CREDENTIALS;
|
|
|
|
case LDAP_E_RIGHTS:
|
|
return LDAP_INSUFFICIENT_RIGHTS;
|
|
|
|
case LDAP_E_BUSY:
|
|
return LDAP_BUSY;
|
|
|
|
case LDAP_E_UNAVAILABLE:
|
|
return LDAP_UNAVAILABLE;
|
|
|
|
case LDAP_E_UNWILLING:
|
|
return LDAP_UNWILLING_TO_PERFORM;
|
|
|
|
case LDAP_E_LOOP:
|
|
return LDAP_LOOP_DETECT;
|
|
|
|
case LDAP_E_NAMING:
|
|
return LDAP_NAMING_VIOLATION;
|
|
|
|
case LDAP_E_OBJECTCLASS:
|
|
return LDAP_OBJECT_CLASS_VIOLATION;
|
|
|
|
case LDAP_E_NOTALLOWEDONNONLEAF:
|
|
return LDAP_NOT_ALLOWED_ON_NONLEAF;
|
|
|
|
case LDAP_E_NOTALLOWEDONRDN:
|
|
return LDAP_NOT_ALLOWED_ON_RDN;
|
|
|
|
case LDAP_E_ALREADYEXISTS:
|
|
return LDAP_ALREADY_EXISTS;
|
|
|
|
case LDAP_E_NOOBJECTCLASSMODS:
|
|
return LDAP_NO_OBJECT_CLASS_MODS;
|
|
|
|
case LDAP_E_RESULTSTOOLARGE:
|
|
return LDAP_RESULTS_TOO_LARGE;
|
|
|
|
case LDAP_E_OTHER:
|
|
return LDAP_OTHER;
|
|
|
|
case LDAP_E_SERVERDOWN:
|
|
return LDAP_SERVER_DOWN;
|
|
|
|
case LDAP_E_LOCAL:
|
|
return LDAP_LOCAL_ERROR;
|
|
|
|
case LDAP_E_ENCODING:
|
|
return LDAP_ENCODING_ERROR;
|
|
|
|
case LDAP_E_DECODING:
|
|
return LDAP_DECODING_ERROR;
|
|
|
|
case LDAP_E_TIMEOUT:
|
|
return LDAP_TIMEOUT;
|
|
|
|
case LDAP_E_AUTHUNKNOWN:
|
|
return LDAP_AUTH_UNKNOWN;
|
|
|
|
case LDAP_E_FILTER:
|
|
return LDAP_FILTER_ERROR;
|
|
|
|
case LDAP_E_USERCANCELLED:
|
|
return LDAP_USER_CANCELLED;
|
|
|
|
case E_INVALIDARG:
|
|
return LDAP_PARAM_ERROR;
|
|
|
|
case E_OUTOFMEMORY:
|
|
return LDAP_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
TimeoutFromTimeval(struct timeval *ptv)
|
|
{
|
|
if (!ptv->tv_usec && !ptv->tv_sec)
|
|
return INFINITE;
|
|
return (ptv->tv_usec / 1000) + (ptv->tv_sec * 1000);
|
|
}
|
|
|
|
char *
|
|
SzMatchingParen(char *sz)
|
|
{
|
|
int cLev = 0;
|
|
|
|
if (sz[0] != '(')
|
|
return NULL;
|
|
|
|
while (*sz)
|
|
{
|
|
if (*sz == '(')
|
|
cLev++;
|
|
else if (*sz == ')')
|
|
{
|
|
cLev--;
|
|
if (!cLev)
|
|
return sz;
|
|
}
|
|
sz++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *
|
|
SzFT(char *sz, DWORD *ptype)
|
|
{
|
|
while (*sz)
|
|
{
|
|
if (*sz == '=')
|
|
{
|
|
if (*(sz-1) == '~')
|
|
{
|
|
*ptype = LDAP_FILTER_APPROX;
|
|
*(sz-1) = 0;
|
|
return sz;
|
|
}
|
|
else if (*(sz - 1) == '<')
|
|
{
|
|
*ptype = LDAP_FILTER_LE;
|
|
*(sz-1) = 0;
|
|
return sz;
|
|
}
|
|
else if (*(sz - 1) == '<')
|
|
{
|
|
*ptype = LDAP_FILTER_GE;
|
|
*(sz-1) = 0;
|
|
return sz;
|
|
}
|
|
if (*(sz + 1) == '*')
|
|
{
|
|
*ptype = LDAP_FILTER_PRESENT;
|
|
*sz = 0;
|
|
return sz+1;
|
|
}
|
|
*ptype = 0;
|
|
return sz;
|
|
}
|
|
sz++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *
|
|
SzStar(char *sz)
|
|
{
|
|
while (*sz)
|
|
{
|
|
if (*sz == '*')
|
|
return sz;
|
|
sz++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
Unquote(char *sz)
|
|
{
|
|
char *pchSrc = sz, *pchDest = sz;
|
|
BOOL fQuoted = FALSE;
|
|
|
|
while (*pchSrc)
|
|
{
|
|
if (fQuoted)
|
|
{
|
|
goto LCopy;
|
|
}
|
|
else
|
|
{
|
|
if (*pchSrc == '\\')
|
|
fQuoted = TRUE;
|
|
else
|
|
{
|
|
LCopy:
|
|
*pchDest++ = *pchSrc;
|
|
fQuoted = FALSE;
|
|
}
|
|
}
|
|
pchSrc++;
|
|
}
|
|
}
|
|
|
|
void
|
|
FreePfilter(PFILTER pfilter)
|
|
{
|
|
PFILTER pfilterNext;
|
|
|
|
while (pfilter)
|
|
{
|
|
if (pfilter->type == LDAP_FILTER_AND ||
|
|
pfilter->type == LDAP_FILTER_OR ||
|
|
pfilter->type == LDAP_FILTER_NOT)
|
|
FreePfilter(pfilter->pfilterSub);
|
|
pfilterNext = pfilter->pfilterNext;
|
|
|
|
delete pfilter;
|
|
|
|
pfilter = pfilterNext;
|
|
}
|
|
}
|
|
|
|
PFILTER
|
|
PfilterFromString(char *sz)
|
|
{
|
|
PFILTER pfilter = NULL;
|
|
char *szMatchingParen;
|
|
char *szSubMatchingParen;
|
|
PFILTER pfilterSub = NULL;
|
|
PFILTER pfilterPrev = NULL;
|
|
char *szFT;
|
|
char *szStar;
|
|
char *szOldStar;
|
|
|
|
if (sz[0] != '(')
|
|
return NULL;
|
|
szMatchingParen = SzMatchingParen(sz);
|
|
if (!szMatchingParen)
|
|
return NULL;
|
|
|
|
pfilter = new FILTER;
|
|
if (!pfilter)
|
|
return NULL;
|
|
FillMemory(pfilter, sizeof(FILTER), 0);
|
|
|
|
switch (sz[1])
|
|
{
|
|
case '&':
|
|
case '|':
|
|
if (sz[1] == '&')
|
|
pfilter->type = LDAP_FILTER_AND;
|
|
else
|
|
pfilter->type = LDAP_FILTER_OR;
|
|
|
|
sz++;
|
|
sz++;
|
|
|
|
// sz now points to what should be first paren of first subfilter
|
|
while (sz < szMatchingParen)
|
|
{
|
|
szSubMatchingParen = SzMatchingParen(sz);
|
|
if (!szSubMatchingParen || szSubMatchingParen >= szMatchingParen)
|
|
goto LFail;
|
|
pfilterSub = PfilterFromString(sz);
|
|
if (!pfilter->pfilterSub)
|
|
pfilter->pfilterSub = pfilterSub;
|
|
if (pfilterPrev)
|
|
pfilterPrev->pfilterNext = pfilterSub;
|
|
pfilterPrev = pfilterSub;
|
|
sz = szSubMatchingParen + 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case '!':
|
|
pfilter->type = LDAP_FILTER_NOT;
|
|
sz++;
|
|
sz++;
|
|
szSubMatchingParen = SzMatchingParen(sz);
|
|
if (!szSubMatchingParen || szSubMatchingParen >= szMatchingParen)
|
|
goto LFail;
|
|
pfilterSub = PfilterFromString(sz);
|
|
pfilter->pfilterSub = pfilterSub;
|
|
break;
|
|
|
|
default:
|
|
// it's not an and/or/not, so it must be an attribute-related filter.
|
|
sz++;
|
|
szFT = SzFT(sz, &pfilter->type);
|
|
if (!szFT)
|
|
goto LFail;
|
|
*szFT++ = 0;
|
|
*szMatchingParen = 0;
|
|
Unquote(sz);
|
|
|
|
// so now sz points to the attribute and szFT points to the value.
|
|
if (pfilter->type == LDAP_FILTER_PRESENT)
|
|
{
|
|
pfilter->szAttrib = sz;
|
|
}
|
|
else
|
|
{
|
|
pfilter->ava.szAttrib = sz;
|
|
pfilter->ava.szValue = szFT;
|
|
}
|
|
|
|
if (!pfilter->type)
|
|
{
|
|
// if a type wasn't filled in, it means it's either eq or substring;
|
|
// we need to grind through the string and look for *s. note that we
|
|
// use a less general format of substring commands than the LDAP
|
|
// api and spec.
|
|
szStar = SzStar(szFT);
|
|
if (!szStar)
|
|
{
|
|
pfilter->type = LDAP_FILTER_EQUALITY;
|
|
}
|
|
else
|
|
{
|
|
pfilter->type = LDAP_FILTER_SUBSTRINGS;
|
|
pfilter->sub.szAttrib = sz;
|
|
pfilter->sub.szInitial = szFT;
|
|
Unquote(szFT);
|
|
*szStar++ = 0;
|
|
szOldStar = szStar;
|
|
szStar = SzStar(szOldStar);
|
|
if (szStar)
|
|
{
|
|
*szStar++ = 0;
|
|
pfilter->sub.szAny = szOldStar;
|
|
Unquote(szOldStar);
|
|
szOldStar = szStar;
|
|
szStar = SzStar(szOldStar);
|
|
if (szStar)
|
|
{
|
|
*szStar++ = 0;
|
|
pfilter->sub.szFinal = szOldStar;
|
|
Unquote(szOldStar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return pfilter;
|
|
|
|
LFail:
|
|
if (pfilter)
|
|
{
|
|
FreePfilter(pfilter);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
CAttrib(char **rgsz)
|
|
{
|
|
int c = 0;
|
|
while (*rgsz)
|
|
{
|
|
c++;
|
|
rgsz++;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
int
|
|
Cval(PATTR pattr)
|
|
{
|
|
PVAL pval = pattr->pvalFirst;
|
|
|
|
int c = 0;
|
|
while (pval)
|
|
{
|
|
c++;
|
|
pval = pval->pvalNext;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
extern "C" DLLEXPORT LDAP * __cdecl
|
|
ldap_open(char *hostname, int portno)
|
|
{
|
|
PLCLI plcli = NULL;
|
|
LDAP *pldap = NULL;
|
|
|
|
pldap = new LDAP;
|
|
if (!pldap)
|
|
return NULL;
|
|
|
|
FillMemory(pldap, sizeof(LDAP), 0);
|
|
|
|
if (FAILED(HrCreateLdapClient(LDAP_VER_CURRENT, INTERFACE_VER_CURRENT, &plcli)))
|
|
{
|
|
delete pldap;
|
|
return NULL;
|
|
}
|
|
|
|
if (FAILED(plcli->HrConnect(hostname, portno)))
|
|
{
|
|
delete pldap;
|
|
plcli->Release();
|
|
return NULL;
|
|
}
|
|
|
|
pldap->plcli = plcli;
|
|
|
|
return pldap;
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_bind_s(LDAP *ld, char *dn, char *cred, int method)
|
|
{
|
|
HRESULT hr;
|
|
XID xid;
|
|
|
|
if (!ld->plcli)
|
|
return LDAP_PARAM_ERROR;
|
|
|
|
if (method != LDAP_AUTH_SIMPLE)
|
|
return LDAP_AUTH_METHOD_NOT_SUPPORTED;
|
|
|
|
if (!cred)
|
|
cred = "";
|
|
|
|
if (!dn)
|
|
dn = "";
|
|
|
|
hr = ld->plcli->HrBindSimple(dn, cred, &xid);
|
|
if (FAILED(hr))
|
|
return LdapResFromHr(hr);
|
|
|
|
hr = ld->plcli->HrGetBindResponse(xid, INFINITE);
|
|
return LdapResFromHr(hr);
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_unbind(LDAP *ld)
|
|
{
|
|
if (!ld->plcli)
|
|
return LDAP_PARAM_ERROR;
|
|
|
|
ld->plcli->HrUnbind();
|
|
ld->plcli->HrDisconnect();
|
|
ld->plcli->Release();
|
|
|
|
// just in case someone tries to use the ld after this...
|
|
ld->plcli = NULL;
|
|
|
|
delete ld;
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_search_s(LDAP *ld, char *base, int scope, char *filter, char *attrs[], int attrsonly, LDAPMessage **res)
|
|
{
|
|
struct timeval time;
|
|
|
|
timerclear(&time);
|
|
return ldap_search_st(ld, base, scope, filter, attrs, attrsonly, &time, res);
|
|
}
|
|
|
|
char *attrsNull[] = {NULL};
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_search_st(LDAP *ld, char *base, int scope, char *filter, char *attrs[], int attrsonly, struct timeval *timeout, LDAPMessage **res)
|
|
{
|
|
HRESULT hr;
|
|
POBJ pobj;
|
|
XID xid;
|
|
SP sp;
|
|
char szFilter[1024];
|
|
|
|
*res = NULL;
|
|
|
|
if (!attrs)
|
|
attrs = attrsNull;
|
|
|
|
// make local copy so we can munge this in place
|
|
if (lstrlen(filter) > 1023)
|
|
return LDAP_PARAM_ERROR;
|
|
StrCpyN(szFilter, filter, ARRAYSIZE(szFilter));
|
|
|
|
if (!ld->plcli)
|
|
return LDAP_PARAM_ERROR;
|
|
|
|
sp.szDNBase = base;
|
|
sp.scope = scope;
|
|
sp.deref = ld->ld_deref;
|
|
sp.cRecordsMax = ld->ld_sizelimit;
|
|
sp.cSecondsMax = ld->ld_timelimit;
|
|
sp.fAttrsOnly = attrsonly;
|
|
sp.pfilter = PfilterFromString(szFilter);
|
|
if (!sp.pfilter)
|
|
return LDAP_PARAM_ERROR;
|
|
sp.cAttrib = CAttrib(attrs);
|
|
sp.rgszAttrib = attrs;
|
|
|
|
hr = ld->plcli->HrSearch(&sp, &xid);
|
|
FreePfilter(sp.pfilter);
|
|
if (FAILED(hr))
|
|
return LdapResFromHr(hr);
|
|
|
|
hr = ld->plcli->HrGetSearchResponse(xid, TimeoutFromTimeval(timeout), &pobj);
|
|
if (FAILED(hr))
|
|
return LdapResFromHr(hr);
|
|
|
|
*res = pobj;
|
|
return LdapResFromHr(hr);
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_msgfree(LDAPMessage *res)
|
|
{
|
|
POBJ pobj = res;
|
|
|
|
return LdapResFromHr(HrFreePobjList(pobj));
|
|
}
|
|
|
|
extern "C" DLLEXPORT LDAPMessage * __cdecl
|
|
ldap_first_entry(LDAP *ld, LDAPMessage *res)
|
|
{
|
|
ld->ld_errno = 0;
|
|
return res;
|
|
}
|
|
|
|
extern "C" DLLEXPORT LDAPMessage * __cdecl
|
|
ldap_next_entry(LDAP *ld, LDAPMessage *entry)
|
|
{
|
|
ld->ld_errno = 0;
|
|
return (LDAPMessage *)((POBJ)entry->pobjNext);
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_count_entries(LDAP *ld, LDAPMessage *res)
|
|
{
|
|
POBJ pobj = (POBJ)res;
|
|
int i = 0;
|
|
|
|
ld->ld_errno = 0;
|
|
while (pobj)
|
|
{
|
|
i++;
|
|
pobj = pobj->pobjNext;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
extern "C" DLLEXPORT char * __cdecl
|
|
ldap_first_attribute(LDAP *ld, LDAPMessage *entry, void **ptr)
|
|
{
|
|
POBJ pobj = (POBJ)entry;
|
|
|
|
*ptr = (void *)(pobj->pattrFirst);
|
|
ld->ld_errno = 0;
|
|
return pobj->pattrFirst->szAttrib;
|
|
}
|
|
|
|
// NOTE! minor change from rfc1823 API: the **ptr field below is just *ptr
|
|
// in rfc1823,but thats not a good idea, so i'm using **ptr here
|
|
// instead.
|
|
extern "C" DLLEXPORT char * __cdecl
|
|
ldap_next_attribute(LDAP *ld, LDAPMessage *entry, void **ptr)
|
|
{
|
|
ld->ld_errno = 0;
|
|
if (!(*ptr))
|
|
return NULL;
|
|
|
|
PATTR pattr = ((PATTR)*ptr)->pattrNext;
|
|
*ptr = (void *)pattr;
|
|
if (pattr)
|
|
return pattr->szAttrib;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
PATTR
|
|
PattrForAttr(POBJ pobj, char *szAttr)
|
|
{
|
|
PATTR pattr = pobj->pattrFirst;
|
|
|
|
while (pattr)
|
|
{
|
|
if (!lstrcmpi(pattr->szAttrib, szAttr))
|
|
return pattr;
|
|
pattr = pattr->pattrNext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
extern "C" DLLEXPORT char ** __cdecl
|
|
ldap_get_values(LDAP *ld, LDAPMessage *entry, char *attr)
|
|
{
|
|
POBJ pobj = (POBJ)entry;
|
|
PATTR pattr;
|
|
int cval;
|
|
char **rgsz;
|
|
int isz = 0;
|
|
PVAL pval;
|
|
|
|
ld->ld_errno = 0;
|
|
pattr = PattrForAttr(pobj, attr);
|
|
if (!pattr)
|
|
return NULL;
|
|
|
|
cval = Cval(pattr);
|
|
rgsz = new char *[cval + 1];
|
|
if (!rgsz)
|
|
return NULL;
|
|
pval = pattr->pvalFirst;
|
|
while (pval)
|
|
{
|
|
rgsz[isz++] = pval->szVal;
|
|
pval = pval->pvalNext;
|
|
}
|
|
rgsz[isz] = NULL;
|
|
|
|
return rgsz;
|
|
}
|
|
|
|
extern "C" DLLEXPORT struct berval ** __cdecl
|
|
ldap_get_values_len(LDAP *ld, LDAPMessage *entry, char *attr)
|
|
{
|
|
POBJ pobj = (POBJ)entry;
|
|
PATTR pattr;
|
|
int cval;
|
|
BERVAL **rgpberval;
|
|
int iberval = 0;
|
|
PVAL pval;
|
|
|
|
ld->ld_errno = 0;
|
|
pattr = PattrForAttr(pobj, attr);
|
|
if (!pattr)
|
|
return NULL;
|
|
|
|
cval = Cval(pattr);
|
|
rgpberval = new BERVAL *[cval + 1];
|
|
if (!rgpberval)
|
|
return NULL;
|
|
|
|
pval = pattr->pvalFirst;
|
|
while (pval)
|
|
{
|
|
rgpberval[iberval] = new BERVAL;
|
|
if (!rgpberval[iberval])
|
|
{
|
|
while (--iberval >= 0)
|
|
delete rgpberval[iberval];
|
|
|
|
delete [] rgpberval;
|
|
return NULL;
|
|
}
|
|
|
|
rgpberval[iberval]->bv_len = lstrlen(pval->szVal) + 1;
|
|
rgpberval[iberval]->bv_val = pval->szVal;
|
|
|
|
iberval++;
|
|
pval = pval->pvalNext;
|
|
}
|
|
rgpberval[iberval] = NULL;
|
|
|
|
return rgpberval;
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_count_values(char **vals)
|
|
{
|
|
// mmm, reuse of poorly-named code
|
|
return CAttrib(vals);
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_count_values_len(struct berval **vals)
|
|
{
|
|
// mmm, reuse of poorly-named code
|
|
return CAttrib((char **)vals);
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_value_free(char **vals)
|
|
{
|
|
delete [] vals;
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
extern "C" DLLEXPORT int __cdecl
|
|
ldap_value_free_len(struct berval **rgpberval)
|
|
{
|
|
BERVAL **ppberval = rgpberval;
|
|
|
|
while (*ppberval)
|
|
{
|
|
delete *ppberval;
|
|
ppberval++;
|
|
}
|
|
delete [] rgpberval;
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
extern "C" DLLEXPORT char * __cdecl
|
|
ldap_get_dn(LDAP *ld, LDAPMessage *entry)
|
|
{
|
|
POBJ pobj = (POBJ)entry;
|
|
char *szDN;
|
|
|
|
ld->ld_errno = 0;
|
|
szDN = new char[lstrlen(pobj->szDN) + 1];
|
|
if (!szDN)
|
|
{
|
|
ld->ld_errno = LDAP_NO_MEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
StrCpyN(szDN, pobj->szDN, lstrlen(pobj->szDN) + 1);
|
|
return szDN;
|
|
}
|
|
|
|
extern "C" DLLEXPORT void __cdecl
|
|
ldap_free_dn(char *dn)
|
|
{
|
|
delete [] dn;
|
|
}
|