Leaked source code of windows server 2003
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

//--------------------------------------------------------------------------------------------
//
// 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;
}