ldap.c revision 90792
190792Sgshapiro/* 290792Sgshapiro * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro */ 990792Sgshapiro 1090792Sgshapiro#include <sm/gen.h> 1190792SgshapiroSM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $") 1290792Sgshapiro 1390792Sgshapiro#if LDAPMAP 1490792Sgshapiro# include <sys/types.h> 1590792Sgshapiro# include <errno.h> 1690792Sgshapiro# include <setjmp.h> 1790792Sgshapiro# include <stdlib.h> 1890792Sgshapiro# include <unistd.h> 1990792Sgshapiro 2090792Sgshapiro# include <sm/bitops.h> 2190792Sgshapiro# include <sm/clock.h> 2290792Sgshapiro# include <sm/conf.h> 2390792Sgshapiro# include <sm/debug.h> 2490792Sgshapiro# include <sm/errstring.h> 2590792Sgshapiro# include <sm/ldap.h> 2690792Sgshapiro# include <sm/string.h> 2790792Sgshapiro# include <sm/sysexits.h> 2890792Sgshapiro 2990792SgshapiroSM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", 3090792Sgshapiro "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); 3190792Sgshapiro 3290792Sgshapirostatic void ldaptimeout __P((int)); 3390792Sgshapiro 3490792Sgshapiro/* 3590792Sgshapiro** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT 3690792Sgshapiro** 3790792Sgshapiro** Parameters: 3890792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT to clear 3990792Sgshapiro** 4090792Sgshapiro** Returns: 4190792Sgshapiro** None. 4290792Sgshapiro** 4390792Sgshapiro*/ 4490792Sgshapiro 4590792Sgshapirovoid 4690792Sgshapirosm_ldap_clear(lmap) 4790792Sgshapiro SM_LDAP_STRUCT *lmap; 4890792Sgshapiro{ 4990792Sgshapiro if (lmap == NULL) 5090792Sgshapiro return; 5190792Sgshapiro 5290792Sgshapiro lmap->ldap_host = NULL; 5390792Sgshapiro lmap->ldap_port = LDAP_PORT; 5490792Sgshapiro lmap->ldap_deref = LDAP_DEREF_NEVER; 5590792Sgshapiro lmap->ldap_timelimit = LDAP_NO_LIMIT; 5690792Sgshapiro lmap->ldap_sizelimit = LDAP_NO_LIMIT; 5790792Sgshapiro# ifdef LDAP_REFERRALS 5890792Sgshapiro lmap->ldap_options = LDAP_OPT_REFERRALS; 5990792Sgshapiro# else /* LDAP_REFERRALS */ 6090792Sgshapiro lmap->ldap_options = 0; 6190792Sgshapiro# endif /* LDAP_REFERRALS */ 6290792Sgshapiro lmap->ldap_attrsep = '\0'; 6390792Sgshapiro lmap->ldap_binddn = NULL; 6490792Sgshapiro lmap->ldap_secret = NULL; 6590792Sgshapiro lmap->ldap_method = LDAP_AUTH_SIMPLE; 6690792Sgshapiro lmap->ldap_base = NULL; 6790792Sgshapiro lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 6890792Sgshapiro lmap->ldap_attrsonly = LDAPMAP_FALSE; 6990792Sgshapiro lmap->ldap_timeout.tv_sec = 0; 7090792Sgshapiro lmap->ldap_timeout.tv_usec = 0; 7190792Sgshapiro lmap->ldap_ld = NULL; 7290792Sgshapiro lmap->ldap_filter = NULL; 7390792Sgshapiro lmap->ldap_attr[0] = NULL; 7490792Sgshapiro#if _FFR_LDAP_RECURSION 7590792Sgshapiro lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL; 7690792Sgshapiro lmap->ldap_attr_final[0] = NULL; 7790792Sgshapiro#endif /* _FFR_LDAP_RECURSION */ 7890792Sgshapiro lmap->ldap_res = NULL; 7990792Sgshapiro lmap->ldap_next = NULL; 8090792Sgshapiro lmap->ldap_pid = 0; 8190792Sgshapiro} 8290792Sgshapiro 8390792Sgshapiro/* 8490792Sgshapiro** SM_LDAP_START -- actually connect to an LDAP server 8590792Sgshapiro** 8690792Sgshapiro** Parameters: 8790792Sgshapiro** name -- name of map for debug output. 8890792Sgshapiro** lmap -- the LDAP map being opened. 8990792Sgshapiro** 9090792Sgshapiro** Returns: 9190792Sgshapiro** true if connection is successful, false otherwise. 9290792Sgshapiro** 9390792Sgshapiro** Side Effects: 9490792Sgshapiro** Populates lmap->ldap_ld. 9590792Sgshapiro*/ 9690792Sgshapiro 9790792Sgshapirostatic jmp_buf LDAPTimeout; 9890792Sgshapiro 9990792Sgshapiro#define SM_LDAP_SETTIMEOUT(to) \ 10090792Sgshapirodo \ 10190792Sgshapiro{ \ 10290792Sgshapiro if (to != 0) \ 10390792Sgshapiro { \ 10490792Sgshapiro if (setjmp(LDAPTimeout) != 0) \ 10590792Sgshapiro { \ 10690792Sgshapiro errno = ETIMEDOUT; \ 10790792Sgshapiro return false; \ 10890792Sgshapiro } \ 10990792Sgshapiro ev = sm_setevent(to, ldaptimeout, 0); \ 11090792Sgshapiro } \ 11190792Sgshapiro} while (0) 11290792Sgshapiro 11390792Sgshapiro#define SM_LDAP_CLEARTIMEOUT() \ 11490792Sgshapirodo \ 11590792Sgshapiro{ \ 11690792Sgshapiro if (ev != NULL) \ 11790792Sgshapiro sm_clrevent(ev); \ 11890792Sgshapiro} while (0) 11990792Sgshapiro 12090792Sgshapirobool 12190792Sgshapirosm_ldap_start(name, lmap) 12290792Sgshapiro char *name; 12390792Sgshapiro SM_LDAP_STRUCT *lmap; 12490792Sgshapiro{ 12590792Sgshapiro int bind_result; 12690792Sgshapiro int save_errno; 12790792Sgshapiro SM_EVENT *ev = NULL; 12890792Sgshapiro LDAP *ld; 12990792Sgshapiro 13090792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 2)) 13190792Sgshapiro sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 13290792Sgshapiro 13390792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 9)) 13490792Sgshapiro sm_dprintf("ldapmap_start(%s, %d)\n", 13590792Sgshapiro lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host, 13690792Sgshapiro lmap->ldap_port); 13790792Sgshapiro 13890792Sgshapiro# if USE_LDAP_INIT 13990792Sgshapiro ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 14090792Sgshapiro save_errno = errno; 14190792Sgshapiro# else /* USE_LDAP_INIT */ 14290792Sgshapiro /* 14390792Sgshapiro ** If using ldap_open(), the actual connection to the server 14490792Sgshapiro ** happens now so we need the timeout here. For ldap_init(), 14590792Sgshapiro ** the connection happens at bind time. 14690792Sgshapiro */ 14790792Sgshapiro 14890792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 14990792Sgshapiro ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 15090792Sgshapiro save_errno = errno; 15190792Sgshapiro 15290792Sgshapiro /* clear the event if it has not sprung */ 15390792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 15490792Sgshapiro# endif /* USE_LDAP_INIT */ 15590792Sgshapiro 15690792Sgshapiro errno = save_errno; 15790792Sgshapiro if (ld == NULL) 15890792Sgshapiro return false; 15990792Sgshapiro 16090792Sgshapiro sm_ldap_setopts(ld, lmap); 16190792Sgshapiro 16290792Sgshapiro# if USE_LDAP_INIT 16390792Sgshapiro /* 16490792Sgshapiro ** If using ldap_init(), the actual connection to the server 16590792Sgshapiro ** happens at ldap_bind_s() so we need the timeout here. 16690792Sgshapiro */ 16790792Sgshapiro 16890792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 16990792Sgshapiro# endif /* USE_LDAP_INIT */ 17090792Sgshapiro 17190792Sgshapiro# ifdef LDAP_AUTH_KRBV4 17290792Sgshapiro if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 17390792Sgshapiro lmap->ldap_secret != NULL) 17490792Sgshapiro { 17590792Sgshapiro /* 17690792Sgshapiro ** Need to put ticket in environment here instead of 17790792Sgshapiro ** during parseargs as there may be different tickets 17890792Sgshapiro ** for different LDAP connections. 17990792Sgshapiro */ 18090792Sgshapiro 18190792Sgshapiro (void) putenv(lmap->ldap_secret); 18290792Sgshapiro } 18390792Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 18490792Sgshapiro 18590792Sgshapiro bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 18690792Sgshapiro lmap->ldap_secret, lmap->ldap_method); 18790792Sgshapiro 18890792Sgshapiro# if USE_LDAP_INIT 18990792Sgshapiro /* clear the event if it has not sprung */ 19090792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 19190792Sgshapiro# endif /* USE_LDAP_INIT */ 19290792Sgshapiro 19390792Sgshapiro if (bind_result != LDAP_SUCCESS) 19490792Sgshapiro { 19590792Sgshapiro errno = bind_result + E_LDAPBASE; 19690792Sgshapiro return false; 19790792Sgshapiro } 19890792Sgshapiro 19990792Sgshapiro /* Save PID to make sure only this PID closes the LDAP connection */ 20090792Sgshapiro lmap->ldap_pid = getpid(); 20190792Sgshapiro lmap->ldap_ld = ld; 20290792Sgshapiro return true; 20390792Sgshapiro} 20490792Sgshapiro 20590792Sgshapiro/* ARGSUSED */ 20690792Sgshapirostatic void 20790792Sgshapiroldaptimeout(unused) 20890792Sgshapiro int unused; 20990792Sgshapiro{ 21090792Sgshapiro /* 21190792Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 21290792Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 21390792Sgshapiro ** DOING. 21490792Sgshapiro */ 21590792Sgshapiro 21690792Sgshapiro errno = ETIMEDOUT; 21790792Sgshapiro longjmp(LDAPTimeout, 1); 21890792Sgshapiro} 21990792Sgshapiro 22090792Sgshapiro/* 22190792Sgshapiro** SM_LDAP_SEARCH -- iniate LDAP search 22290792Sgshapiro** 22390792Sgshapiro** Initiate an LDAP search, return the msgid. 22490792Sgshapiro** The calling function must collect the results. 22590792Sgshapiro** 22690792Sgshapiro** Parameters: 22790792Sgshapiro** lmap -- LDAP map information 22890792Sgshapiro** key -- key to substitute in LDAP filter 22990792Sgshapiro** 23090792Sgshapiro** Returns: 23190792Sgshapiro** -1 on failure, msgid on success 23290792Sgshapiro** 23390792Sgshapiro*/ 23490792Sgshapiro 23590792Sgshapiroint 23690792Sgshapirosm_ldap_search(lmap, key) 23790792Sgshapiro SM_LDAP_STRUCT *lmap; 23890792Sgshapiro char *key; 23990792Sgshapiro{ 24090792Sgshapiro int msgid; 24190792Sgshapiro char *fp, *p, *q; 24290792Sgshapiro char filter[LDAPMAP_MAX_FILTER + 1]; 24390792Sgshapiro 24490792Sgshapiro /* substitute key into filter, perhaps multiple times */ 24590792Sgshapiro memset(filter, '\0', sizeof filter); 24690792Sgshapiro fp = filter; 24790792Sgshapiro p = lmap->ldap_filter; 24890792Sgshapiro while ((q = strchr(p, '%')) != NULL) 24990792Sgshapiro { 25090792Sgshapiro if (q[1] == 's') 25190792Sgshapiro { 25290792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 25390792Sgshapiro "%.*s%s", (int) (q - p), p, key); 25490792Sgshapiro fp += strlen(fp); 25590792Sgshapiro p = q + 2; 25690792Sgshapiro } 25790792Sgshapiro else if (q[1] == '0') 25890792Sgshapiro { 25990792Sgshapiro char *k = key; 26090792Sgshapiro 26190792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 26290792Sgshapiro "%.*s", (int) (q - p), p); 26390792Sgshapiro fp += strlen(fp); 26490792Sgshapiro p = q + 2; 26590792Sgshapiro 26690792Sgshapiro /* Properly escape LDAP special characters */ 26790792Sgshapiro while (SPACELEFT(filter, fp) > 0 && 26890792Sgshapiro *k != '\0') 26990792Sgshapiro { 27090792Sgshapiro if (*k == '*' || *k == '(' || 27190792Sgshapiro *k == ')' || *k == '\\') 27290792Sgshapiro { 27390792Sgshapiro (void) sm_strlcat(fp, 27490792Sgshapiro (*k == '*' ? "\\2A" : 27590792Sgshapiro (*k == '(' ? "\\28" : 27690792Sgshapiro (*k == ')' ? "\\29" : 27790792Sgshapiro (*k == '\\' ? "\\5C" : 27890792Sgshapiro "\00")))), 27990792Sgshapiro SPACELEFT(filter, fp)); 28090792Sgshapiro fp += strlen(fp); 28190792Sgshapiro k++; 28290792Sgshapiro } 28390792Sgshapiro else 28490792Sgshapiro *fp++ = *k++; 28590792Sgshapiro } 28690792Sgshapiro } 28790792Sgshapiro else 28890792Sgshapiro { 28990792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 29090792Sgshapiro "%.*s", (int) (q - p + 1), p); 29190792Sgshapiro p = q + (q[1] == '%' ? 2 : 1); 29290792Sgshapiro fp += strlen(fp); 29390792Sgshapiro } 29490792Sgshapiro } 29590792Sgshapiro (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 29690792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 20)) 29790792Sgshapiro sm_dprintf("ldap search filter=%s\n", filter); 29890792Sgshapiro 29990792Sgshapiro lmap->ldap_res = NULL; 30090792Sgshapiro msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope, 30190792Sgshapiro filter, 30290792Sgshapiro (lmap->ldap_attr[0] == NULL ? NULL : 30390792Sgshapiro lmap->ldap_attr), 30490792Sgshapiro lmap->ldap_attrsonly); 30590792Sgshapiro return msgid; 30690792Sgshapiro} 30790792Sgshapiro 30890792Sgshapiro# if _FFR_LDAP_RECURSION 30990792Sgshapiro/* 31090792Sgshapiro** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 31190792Sgshapiro** 31290792Sgshapiro** Parameters: 31390792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 31490792Sgshapiro** msgid -- msgid returned by sm_ldap_search() 31590792Sgshapiro** flags -- flags for the lookup 31690792Sgshapiro** delim -- delimiter for result concatenation 31790792Sgshapiro** rpool -- memory pool for storage 31890792Sgshapiro** result -- return string 31990792Sgshapiro** recurse -- recursion list 32090792Sgshapiro** 32190792Sgshapiro** Returns: 32290792Sgshapiro** status (sysexit) 32390792Sgshapiro*/ 32490792Sgshapiro 32590792Sgshapiro# define LDAPMAP_ERROR_CLEANUP() \ 32690792Sgshapiro{ \ 32790792Sgshapiro if (lmap->ldap_res != NULL) \ 32890792Sgshapiro { \ 32990792Sgshapiro ldap_msgfree(lmap->ldap_res); \ 33090792Sgshapiro lmap->ldap_res = NULL; \ 33190792Sgshapiro } \ 33290792Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); \ 33390792Sgshapiro} 33490792Sgshapiro 33590792Sgshapirostatic int 33690792Sgshapiroldapmap_add_recurse(top, item, type, rpool) 33790792Sgshapiro SM_LDAP_RECURSE_LIST **top; 33890792Sgshapiro char *item; 33990792Sgshapiro int type; 34090792Sgshapiro SM_RPOOL_T *rpool; 34190792Sgshapiro{ 34290792Sgshapiro SM_LDAP_RECURSE_LIST *p; 34390792Sgshapiro SM_LDAP_RECURSE_LIST *last; 34490792Sgshapiro 34590792Sgshapiro last = NULL; 34690792Sgshapiro for (p = *top; p != NULL; p = p->lr_next) 34790792Sgshapiro { 34890792Sgshapiro if (strcasecmp(item, p->lr_search) == 0 && 34990792Sgshapiro type == p->lr_type) 35090792Sgshapiro { 35190792Sgshapiro /* already on list */ 35290792Sgshapiro return 1; 35390792Sgshapiro } 35490792Sgshapiro last = p; 35590792Sgshapiro } 35690792Sgshapiro 35790792Sgshapiro /* not on list, add it */ 35890792Sgshapiro p = sm_rpool_malloc_x(rpool, sizeof *p); 35990792Sgshapiro p->lr_search = sm_rpool_strdup_x(rpool, item); 36090792Sgshapiro p->lr_type = type; 36190792Sgshapiro p->lr_next = NULL; 36290792Sgshapiro if (last == NULL) 36390792Sgshapiro *top = p; 36490792Sgshapiro else 36590792Sgshapiro last->lr_next = p; 36690792Sgshapiro return 0; 36790792Sgshapiro} 36890792Sgshapiro 36990792Sgshapiroint 37090792Sgshapirosm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse) 37190792Sgshapiro SM_LDAP_STRUCT *lmap; 37290792Sgshapiro int msgid; 37390792Sgshapiro int flags; 37490792Sgshapiro char delim; 37590792Sgshapiro SM_RPOOL_T *rpool; 37690792Sgshapiro char **result; 37790792Sgshapiro SM_LDAP_RECURSE_LIST *recurse; 37890792Sgshapiro{ 37990792Sgshapiro bool toplevel; 38090792Sgshapiro int i; 38190792Sgshapiro int entries = 0; 38290792Sgshapiro int statp; 38390792Sgshapiro int vsize; 38490792Sgshapiro int ret; 38590792Sgshapiro int save_errno; 38690792Sgshapiro char *p; 38790792Sgshapiro 38890792Sgshapiro /* Are we the top top level of the search? */ 38990792Sgshapiro toplevel = (recurse == NULL); 39090792Sgshapiro 39190792Sgshapiro /* Get results */ 39290792Sgshapiro statp = EX_NOTFOUND; 39390792Sgshapiro while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 39490792Sgshapiro (lmap->ldap_timeout.tv_sec == 0 ? NULL : 39590792Sgshapiro &(lmap->ldap_timeout)), 39690792Sgshapiro &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 39790792Sgshapiro { 39890792Sgshapiro LDAPMessage *entry; 39990792Sgshapiro 40090792Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, flags)) 40190792Sgshapiro { 40290792Sgshapiro entries += ldap_count_entries(lmap->ldap_ld, 40390792Sgshapiro lmap->ldap_res); 40490792Sgshapiro if (entries > 1) 40590792Sgshapiro { 40690792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 40790792Sgshapiro errno = ENOENT; 40890792Sgshapiro return EX_NOTFOUND; 40990792Sgshapiro } 41090792Sgshapiro } 41190792Sgshapiro 41290792Sgshapiro /* If we don't want multiple values and we have one, break */ 41390792Sgshapiro if (delim == '\0' && *result != NULL) 41490792Sgshapiro break; 41590792Sgshapiro 41690792Sgshapiro /* Cycle through all entries */ 41790792Sgshapiro for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 41890792Sgshapiro entry != NULL; 41990792Sgshapiro entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 42090792Sgshapiro { 42190792Sgshapiro BerElement *ber; 42290792Sgshapiro char *attr; 42390792Sgshapiro char **vals = NULL; 42490792Sgshapiro char *dn; 42590792Sgshapiro 42690792Sgshapiro /* 42790792Sgshapiro ** If matching only and found an entry, 42890792Sgshapiro ** no need to spin through attributes 42990792Sgshapiro */ 43090792Sgshapiro 43190792Sgshapiro if (statp == EX_OK && 43290792Sgshapiro bitset(SM_LDAP_MATCHONLY, flags)) 43390792Sgshapiro continue; 43490792Sgshapiro 43590792Sgshapiro /* record completed DN's to prevent loops */ 43690792Sgshapiro dn = ldap_get_dn(lmap->ldap_ld, entry); 43790792Sgshapiro if (dn == NULL) 43890792Sgshapiro { 43990792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 44090792Sgshapiro save_errno += E_LDAPBASE; 44190792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 44290792Sgshapiro errno = save_errno; 44390792Sgshapiro return EX_OSERR; 44490792Sgshapiro } 44590792Sgshapiro 44690792Sgshapiro switch (ldapmap_add_recurse(&recurse, dn, 44790792Sgshapiro LDAPMAP_ATTR_NORMAL, 44890792Sgshapiro rpool)) 44990792Sgshapiro { 45090792Sgshapiro case -1: 45190792Sgshapiro /* error adding */ 45290792Sgshapiro ldap_memfree(dn); 45390792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 45490792Sgshapiro errno = ENOMEM; 45590792Sgshapiro return EX_OSERR; 45690792Sgshapiro 45790792Sgshapiro case 1: 45890792Sgshapiro /* already on list, skip it */ 45990792Sgshapiro ldap_memfree(dn); 46090792Sgshapiro continue; 46190792Sgshapiro } 46290792Sgshapiro ldap_memfree(dn); 46390792Sgshapiro 46490792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 46590792Sgshapiro /* 46690792Sgshapiro ** Reset value to prevent lingering 46790792Sgshapiro ** LDAP_DECODING_ERROR due to 46890792Sgshapiro ** OpenLDAP 1.X's hack (see below) 46990792Sgshapiro */ 47090792Sgshapiro 47190792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 47290792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 47390792Sgshapiro 47490792Sgshapiro for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 47590792Sgshapiro &ber); 47690792Sgshapiro attr != NULL; 47790792Sgshapiro attr = ldap_next_attribute(lmap->ldap_ld, entry, 47890792Sgshapiro ber)) 47990792Sgshapiro { 48090792Sgshapiro char *tmp, *vp_tmp; 48190792Sgshapiro int type; 48290792Sgshapiro 48390792Sgshapiro for (i = 0; lmap->ldap_attr[i] != NULL; i++) 48490792Sgshapiro { 48590792Sgshapiro if (sm_strcasecmp(lmap->ldap_attr[i], 48690792Sgshapiro attr) == 0) 48790792Sgshapiro { 48890792Sgshapiro type = lmap->ldap_attr_type[i]; 48990792Sgshapiro break; 49090792Sgshapiro } 49190792Sgshapiro } 49290792Sgshapiro if (lmap->ldap_attr[i] == NULL) 49390792Sgshapiro { 49490792Sgshapiro /* attribute not requested */ 49590792Sgshapiro# if USING_NETSCAPE_LDAP 49690792Sgshapiro ldap_memfree(attr); 49790792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 49890792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 49990792Sgshapiro errno = EFAULT; 50090792Sgshapiro return EX_SOFTWARE; 50190792Sgshapiro } 50290792Sgshapiro 50390792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 50490792Sgshapiro { 50590792Sgshapiro vals = ldap_get_values(lmap->ldap_ld, 50690792Sgshapiro entry, 50790792Sgshapiro attr); 50890792Sgshapiro if (vals == NULL) 50990792Sgshapiro { 51090792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 51190792Sgshapiro if (save_errno == LDAP_SUCCESS) 51290792Sgshapiro { 51390792Sgshapiro# if USING_NETSCAPE_LDAP 51490792Sgshapiro ldap_memfree(attr); 51590792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 51690792Sgshapiro continue; 51790792Sgshapiro } 51890792Sgshapiro 51990792Sgshapiro /* Must be an error */ 52090792Sgshapiro save_errno += E_LDAPBASE; 52190792Sgshapiro# if USING_NETSCAPE_LDAP 52290792Sgshapiro ldap_memfree(attr); 52390792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 52490792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 52590792Sgshapiro errno = save_errno; 52690792Sgshapiro return EX_TEMPFAIL; 52790792Sgshapiro } 52890792Sgshapiro } 52990792Sgshapiro 53090792Sgshapiro statp = EX_OK; 53190792Sgshapiro 53290792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 53390792Sgshapiro /* 53490792Sgshapiro ** Reset value to prevent lingering 53590792Sgshapiro ** LDAP_DECODING_ERROR due to 53690792Sgshapiro ** OpenLDAP 1.X's hack (see below) 53790792Sgshapiro */ 53890792Sgshapiro 53990792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 54090792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 54190792Sgshapiro 54290792Sgshapiro /* 54390792Sgshapiro ** If matching only, 54490792Sgshapiro ** no need to spin through entries 54590792Sgshapiro */ 54690792Sgshapiro 54790792Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 54890792Sgshapiro { 54990792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 55090792Sgshapiro ldap_value_free(vals); 55190792Sgshapiro 55290792Sgshapiro# if USING_NETSCAPE_LDAP 55390792Sgshapiro ldap_memfree(attr); 55490792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 55590792Sgshapiro continue; 55690792Sgshapiro } 55790792Sgshapiro 55890792Sgshapiro /* 55990792Sgshapiro ** If we don't want multiple values, 56090792Sgshapiro ** return first found. 56190792Sgshapiro */ 56290792Sgshapiro 56390792Sgshapiro if (delim == '\0') 56490792Sgshapiro { 56590792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 56690792Sgshapiro { 56790792Sgshapiro *result = sm_rpool_strdup_x(rpool, 56890792Sgshapiro attr); 56990792Sgshapiro# if USING_NETSCAPE_LDAP 57090792Sgshapiro ldap_memfree(attr); 57190792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 57290792Sgshapiro break; 57390792Sgshapiro } 57490792Sgshapiro 57590792Sgshapiro if (vals[0] == NULL) 57690792Sgshapiro { 57790792Sgshapiro ldap_value_free(vals); 57890792Sgshapiro# if USING_NETSCAPE_LDAP 57990792Sgshapiro ldap_memfree(attr); 58090792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 58190792Sgshapiro continue; 58290792Sgshapiro } 58390792Sgshapiro 58490792Sgshapiro vsize = strlen(vals[0]) + 1; 58590792Sgshapiro if (lmap->ldap_attrsep != '\0') 58690792Sgshapiro vsize += strlen(attr) + 1; 58790792Sgshapiro *result = sm_rpool_malloc_x(rpool, 58890792Sgshapiro vsize); 58990792Sgshapiro if (lmap->ldap_attrsep != '\0') 59090792Sgshapiro sm_snprintf(*result, vsize, 59190792Sgshapiro "%s%c%s", 59290792Sgshapiro attr, 59390792Sgshapiro lmap->ldap_attrsep, 59490792Sgshapiro vals[0]); 59590792Sgshapiro else 59690792Sgshapiro sm_strlcpy(*result, vals[0], 59790792Sgshapiro vsize); 59890792Sgshapiro ldap_value_free(vals); 59990792Sgshapiro# if USING_NETSCAPE_LDAP 60090792Sgshapiro ldap_memfree(attr); 60190792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 60290792Sgshapiro break; 60390792Sgshapiro } 60490792Sgshapiro 60590792Sgshapiro /* attributes only */ 60690792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 60790792Sgshapiro { 60890792Sgshapiro if (*result == NULL) 60990792Sgshapiro *result = sm_rpool_strdup_x(rpool, 61090792Sgshapiro attr); 61190792Sgshapiro else 61290792Sgshapiro { 61390792Sgshapiro vsize = strlen(*result) + 61490792Sgshapiro strlen(attr) + 2; 61590792Sgshapiro tmp = sm_rpool_malloc_x(rpool, 61690792Sgshapiro vsize); 61790792Sgshapiro (void) sm_snprintf(tmp, 61890792Sgshapiro vsize, "%s%c%s", 61990792Sgshapiro *result, delim, 62090792Sgshapiro attr); 62190792Sgshapiro *result = tmp; 62290792Sgshapiro } 62390792Sgshapiro# if USING_NETSCAPE_LDAP 62490792Sgshapiro ldap_memfree(attr); 62590792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 62690792Sgshapiro continue; 62790792Sgshapiro } 62890792Sgshapiro 62990792Sgshapiro /* 63090792Sgshapiro ** If there is more than one, 63190792Sgshapiro ** munge then into a map_coldelim 63290792Sgshapiro ** separated string 63390792Sgshapiro */ 63490792Sgshapiro 63590792Sgshapiro vsize = 0; 63690792Sgshapiro for (i = 0; vals[i] != NULL; i++) 63790792Sgshapiro { 63890792Sgshapiro if (type == LDAPMAP_ATTR_DN || 63990792Sgshapiro type == LDAPMAP_ATTR_FILTER || 64090792Sgshapiro type == LDAPMAP_ATTR_URL) 64190792Sgshapiro { 64290792Sgshapiro if (ldapmap_add_recurse(&recurse, 64390792Sgshapiro vals[i], 64490792Sgshapiro type) < 0) 64590792Sgshapiro { 64690792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 64790792Sgshapiro errno = ENOMEM; 64890792Sgshapiro return EX_OSERR; 64990792Sgshapiro } 65090792Sgshapiro } 65190792Sgshapiro if (type != LDAPMAP_ATTR_NORMAL) 65290792Sgshapiro { 65390792Sgshapiro# if USING_NETSCAPE_LDAP 65490792Sgshapiro ldap_memfree(attr); 65590792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 65690792Sgshapiro continue; 65790792Sgshapiro } 65890792Sgshapiro vsize += strlen(vals[i]) + 1; 65990792Sgshapiro if (lmap->ldap_attrsep != '\0') 66090792Sgshapiro vsize += strlen(attr) + 1; 66190792Sgshapiro } 66290792Sgshapiro vp_tmp = sm_rpool_malloc_x(rpool, vsize); 66390792Sgshapiro *vp_tmp = '\0'; 66490792Sgshapiro 66590792Sgshapiro p = vp_tmp; 66690792Sgshapiro for (i = 0; vals[i] != NULL; i++) 66790792Sgshapiro { 66890792Sgshapiro if (lmap->ldap_attrsep != '\0') 66990792Sgshapiro { 67090792Sgshapiro p += sm_strlcpy(p, attr, 67190792Sgshapiro vsize - (p - vp_tmp)); 67290792Sgshapiro *p++ = lmap->ldap_attrsep; 67390792Sgshapiro } 67490792Sgshapiro p += sm_strlcpy(p, vals[i], 67590792Sgshapiro vsize - (p - vp_tmp)); 67690792Sgshapiro if (p >= vp_tmp + vsize) 67790792Sgshapiro { 67890792Sgshapiro /* Internal error: buffer too small for LDAP values */ 67990792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 68090792Sgshapiro errno = ENOMEM; 68190792Sgshapiro return EX_OSERR; 68290792Sgshapiro } 68390792Sgshapiro if (vals[i + 1] != NULL) 68490792Sgshapiro *p++ = delim; 68590792Sgshapiro } 68690792Sgshapiro 68790792Sgshapiro ldap_value_free(vals); 68890792Sgshapiro# if USING_NETSCAPE_LDAP 68990792Sgshapiro ldap_memfree(attr); 69090792Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 69190792Sgshapiro if (*result == NULL) 69290792Sgshapiro { 69390792Sgshapiro *result = vp_tmp; 69490792Sgshapiro continue; 69590792Sgshapiro } 69690792Sgshapiro vsize = strlen(*result) + strlen(vp_tmp) + 2; 69790792Sgshapiro tmp = sm_rpool_malloc_x(rpool, vsize); 69890792Sgshapiro (void) sm_snprintf(tmp, vsize, "%s%c%s", 69990792Sgshapiro *result, delim, vp_tmp); 70090792Sgshapiro *result = tmp; 70190792Sgshapiro } 70290792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 70390792Sgshapiro 70490792Sgshapiro /* 70590792Sgshapiro ** We check save_errno != LDAP_DECODING_ERROR since 70690792Sgshapiro ** OpenLDAP 1.X has a very ugly *undocumented* 70790792Sgshapiro ** hack of returning this error code from 70890792Sgshapiro ** ldap_next_attribute() if the library freed the 70990792Sgshapiro ** ber attribute. See: 71090792Sgshapiro ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 71190792Sgshapiro */ 71290792Sgshapiro 71390792Sgshapiro if (save_errno != LDAP_SUCCESS && 71490792Sgshapiro save_errno != LDAP_DECODING_ERROR) 71590792Sgshapiro { 71690792Sgshapiro /* Must be an error */ 71790792Sgshapiro save_errno += E_LDAPBASE; 71890792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 71990792Sgshapiro errno = save_errno; 72090792Sgshapiro return EX_TEMPFAIL; 72190792Sgshapiro } 72290792Sgshapiro 72390792Sgshapiro /* We don't want multiple values and we have one */ 72490792Sgshapiro if (delim == '\0' && *result != NULL) 72590792Sgshapiro break; 72690792Sgshapiro } 72790792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 72890792Sgshapiro if (save_errno != LDAP_SUCCESS && 72990792Sgshapiro save_errno != LDAP_DECODING_ERROR) 73090792Sgshapiro { 73190792Sgshapiro /* Must be an error */ 73290792Sgshapiro save_errno += E_LDAPBASE; 73390792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 73490792Sgshapiro errno = save_errno; 73590792Sgshapiro return EX_TEMPFAIL; 73690792Sgshapiro } 73790792Sgshapiro ldap_msgfree(lmap->ldap_res); 73890792Sgshapiro lmap->ldap_res = NULL; 73990792Sgshapiro } 74090792Sgshapiro 74190792Sgshapiro if (ret == 0) 74290792Sgshapiro save_errno = ETIMEDOUT; 74390792Sgshapiro else 74490792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 74590792Sgshapiro if (save_errno != LDAP_SUCCESS) 74690792Sgshapiro { 74790792Sgshapiro statp = EX_TEMPFAIL; 74890792Sgshapiro if (ret != 0) 74990792Sgshapiro { 75090792Sgshapiro switch (save_errno) 75190792Sgshapiro { 75290792Sgshapiro#ifdef LDAP_SERVER_DOWN 75390792Sgshapiro case LDAP_SERVER_DOWN: 75490792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 75590792Sgshapiro case LDAP_TIMEOUT: 75690792Sgshapiro case LDAP_UNAVAILABLE: 75790792Sgshapiro /* server disappeared, try reopen on next search */ 75890792Sgshapiro statp = EX_RESTART; 75990792Sgshapiro break; 76090792Sgshapiro } 76190792Sgshapiro save_errno += E_LDAPBASE; 76290792Sgshapiro } 76390792Sgshapiro LDAPMAP_ERROR_CLEANUP(); 76490792Sgshapiro errno = save_errno; 76590792Sgshapiro return statp; 76690792Sgshapiro } 76790792Sgshapiro 76890792Sgshapiro if (lmap->ldap_res != NULL) 76990792Sgshapiro { 77090792Sgshapiro ldap_msgfree(lmap->ldap_res); 77190792Sgshapiro lmap->ldap_res = NULL; 77290792Sgshapiro } 77390792Sgshapiro 77490792Sgshapiro if (toplevel) 77590792Sgshapiro { 77690792Sgshapiro SM_LDAP_RECURSE_LIST *rl; 77790792Sgshapiro 77890792Sgshapiro /* 77990792Sgshapiro ** Spin through the built-up recurse list at the top 78090792Sgshapiro ** of the recursion. Since new items are added at the 78190792Sgshapiro ** end of the shared list, we actually only ever get 78290792Sgshapiro ** one level of recursion before things pop back to the 78390792Sgshapiro ** top. Any items added to the list during that recursion 78490792Sgshapiro ** will be expanded by the top level. 78590792Sgshapiro */ 78690792Sgshapiro 78790792Sgshapiro for (rl = recurse; rl != NULL; rl = rl->lr_next) 78890792Sgshapiro { 78990792Sgshapiro int sid; 79090792Sgshapiro int status; 79190792Sgshapiro 79290792Sgshapiro if (rl->lr_type == LDAPMAP_ATTR_NORMAL) 79390792Sgshapiro { 79490792Sgshapiro /* already expanded */ 79590792Sgshapiro continue; 79690792Sgshapiro } 79790792Sgshapiro else if (rl->lr_type == LDAPMAP_ATTR_DN) 79890792Sgshapiro { 79990792Sgshapiro /* do DN search */ 80090792Sgshapiro sid = ldap_search(lmap->ldap_ld, 80190792Sgshapiro rl->lr_search, 80290792Sgshapiro lmap->ldap_scope, 80390792Sgshapiro "(objectClass=*)", 80490792Sgshapiro lmap->ldap_attr_final, 80590792Sgshapiro lmap->ldap_attrsonly); 80690792Sgshapiro } 80790792Sgshapiro else if (rl->lr_type == LDAPMAP_ATTR_FILTER) 80890792Sgshapiro { 80990792Sgshapiro /* do new search */ 81090792Sgshapiro sid = ldap_search(lmap->ldap_ld, 81190792Sgshapiro lmap->ldap_base, 81290792Sgshapiro lmap->ldap_scope, 81390792Sgshapiro rl->lr_search, 81490792Sgshapiro lmap->ldap_attr_final, 81590792Sgshapiro lmap->ldap_attrsonly); 81690792Sgshapiro } 81790792Sgshapiro else if (rl->lr_type == LDAPMAP_ATTR_URL) 81890792Sgshapiro { 81990792Sgshapiro /* do new URL search */ 82090792Sgshapiro sid = ldap_url_search(lmap->ldap_ld, 82190792Sgshapiro rl->lr_search, 82290792Sgshapiro lmap->ldap_attrsonly); 82390792Sgshapiro } 82490792Sgshapiro else 82590792Sgshapiro { 82690792Sgshapiro /* unknown or illegal attribute type */ 82790792Sgshapiro errno = EFAULT; 82890792Sgshapiro return EX_SOFTWARE; 82990792Sgshapiro } 83090792Sgshapiro 83190792Sgshapiro /* Collect results */ 83290792Sgshapiro if (sid == -1) 83390792Sgshapiro { 83490792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 83590792Sgshapiro statp = EX_TEMPFAIL; 83690792Sgshapiro switch (save_errno) 83790792Sgshapiro { 83890792Sgshapiro#ifdef LDAP_SERVER_DOWN 83990792Sgshapiro case LDAP_SERVER_DOWN: 84090792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 84190792Sgshapiro case LDAP_TIMEOUT: 84290792Sgshapiro case LDAP_UNAVAILABLE: 84390792Sgshapiro /* server disappeared, try reopen on next search */ 84490792Sgshapiro statp = EX_RESTART; 84590792Sgshapiro break; 84690792Sgshapiro } 84790792Sgshapiro errno = save_errno + E_LDAPBASE; 84890792Sgshapiro return statp; 84990792Sgshapiro } 85090792Sgshapiro 85190792Sgshapiro status = sm_ldap_results(lmap, sid, flags, delim, 85290792Sgshapiro rpool, result, recurse); 85390792Sgshapiro save_errno = errno; 85490792Sgshapiro if (status != EX_OK && status != EX_NOTFOUND) 85590792Sgshapiro { 85690792Sgshapiro errno = save_errno; 85790792Sgshapiro return status; 85890792Sgshapiro } 85990792Sgshapiro 86090792Sgshapiro /* Mark as done */ 86190792Sgshapiro rl->lr_type = LDAPMAP_ATTR_NORMAL; 86290792Sgshapiro } 86390792Sgshapiro } 86490792Sgshapiro return statp; 86590792Sgshapiro} 86690792Sgshapiro#endif /* _FFR_LDAP_RECURSION */ 86790792Sgshapiro 86890792Sgshapiro/* 86990792Sgshapiro** SM_LDAP_CLOSE -- close LDAP connection 87090792Sgshapiro** 87190792Sgshapiro** Parameters: 87290792Sgshapiro** lmap -- LDAP map information 87390792Sgshapiro** 87490792Sgshapiro** Returns: 87590792Sgshapiro** None. 87690792Sgshapiro** 87790792Sgshapiro*/ 87890792Sgshapiro 87990792Sgshapirovoid 88090792Sgshapirosm_ldap_close(lmap) 88190792Sgshapiro SM_LDAP_STRUCT *lmap; 88290792Sgshapiro{ 88390792Sgshapiro if (lmap->ldap_ld == NULL) 88490792Sgshapiro return; 88590792Sgshapiro 88690792Sgshapiro if (lmap->ldap_pid == getpid()) 88790792Sgshapiro ldap_unbind(lmap->ldap_ld); 88890792Sgshapiro lmap->ldap_ld = NULL; 88990792Sgshapiro lmap->ldap_pid = 0; 89090792Sgshapiro} 89190792Sgshapiro 89290792Sgshapiro/* 89390792Sgshapiro** SM_LDAP_SETOPTS -- set LDAP options 89490792Sgshapiro** 89590792Sgshapiro** Parameters: 89690792Sgshapiro** ld -- LDAP session handle 89790792Sgshapiro** lmap -- LDAP map information 89890792Sgshapiro** 89990792Sgshapiro** Returns: 90090792Sgshapiro** None. 90190792Sgshapiro** 90290792Sgshapiro*/ 90390792Sgshapiro 90490792Sgshapirovoid 90590792Sgshapirosm_ldap_setopts(ld, lmap) 90690792Sgshapiro LDAP *ld; 90790792Sgshapiro SM_LDAP_STRUCT *lmap; 90890792Sgshapiro{ 90990792Sgshapiro# if USE_LDAP_SET_OPTION 91090792Sgshapiro ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 91190792Sgshapiro if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 91290792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 91390792Sgshapiro else 91490792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 91590792Sgshapiro ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 91690792Sgshapiro ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 91790792Sgshapiro# else /* USE_LDAP_SET_OPTION */ 91890792Sgshapiro /* From here on in we can use ldap internal timelimits */ 91990792Sgshapiro ld->ld_deref = lmap->ldap_deref; 92090792Sgshapiro ld->ld_options = lmap->ldap_options; 92190792Sgshapiro ld->ld_sizelimit = lmap->ldap_sizelimit; 92290792Sgshapiro ld->ld_timelimit = lmap->ldap_timelimit; 92390792Sgshapiro# endif /* USE_LDAP_SET_OPTION */ 92490792Sgshapiro} 92590792Sgshapiro 92690792Sgshapiro/* 92790792Sgshapiro** SM_LDAP_GETERRNO -- get ldap errno value 92890792Sgshapiro** 92990792Sgshapiro** Parameters: 93090792Sgshapiro** ld -- LDAP session handle 93190792Sgshapiro** 93290792Sgshapiro** Returns: 93390792Sgshapiro** LDAP errno. 93490792Sgshapiro** 93590792Sgshapiro*/ 93690792Sgshapiro 93790792Sgshapiroint 93890792Sgshapirosm_ldap_geterrno(ld) 93990792Sgshapiro LDAP *ld; 94090792Sgshapiro{ 94190792Sgshapiro int err = LDAP_SUCCESS; 94290792Sgshapiro 94390792Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 94490792Sgshapiro (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 94590792Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 94690792Sgshapiro# ifdef LDAP_OPT_SIZELIMIT 94790792Sgshapiro err = ldap_get_lderrno(ld, NULL, NULL); 94890792Sgshapiro# else /* LDAP_OPT_SIZELIMIT */ 94990792Sgshapiro err = ld->ld_errno; 95090792Sgshapiro 95190792Sgshapiro /* 95290792Sgshapiro ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 95390792Sgshapiro ** OpenLDAP 1.X's hack (see above) 95490792Sgshapiro */ 95590792Sgshapiro 95690792Sgshapiro ld->ld_errno = LDAP_SUCCESS; 95790792Sgshapiro# endif /* LDAP_OPT_SIZELIMIT */ 95890792Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 95990792Sgshapiro return err; 96090792Sgshapiro} 96190792Sgshapiro# endif /* LDAPMAP */ 962