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