ldap.c revision 125820
190792Sgshapiro/* 2125820Sgshapiro * Copyright (c) 2001-2003 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> 11125820SgshapiroSM_RCSID("@(#)$Id: ldap.c,v 1.44.2.5 2003/12/23 21:21:56 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> 2794334Sgshapiro# ifdef EX_OK 2894334Sgshapiro# undef EX_OK /* for SVr4.2 SMP */ 2994334Sgshapiro# endif /* EX_OK */ 3090792Sgshapiro# include <sm/sysexits.h> 3190792Sgshapiro 3290792SgshapiroSM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", 3390792Sgshapiro "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); 3490792Sgshapiro 3590792Sgshapirostatic void ldaptimeout __P((int)); 3690792Sgshapiro 3790792Sgshapiro/* 3890792Sgshapiro** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT 3990792Sgshapiro** 4090792Sgshapiro** Parameters: 4190792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT to clear 4290792Sgshapiro** 4390792Sgshapiro** Returns: 4490792Sgshapiro** None. 4590792Sgshapiro** 4690792Sgshapiro*/ 4790792Sgshapiro 4890792Sgshapirovoid 4990792Sgshapirosm_ldap_clear(lmap) 5090792Sgshapiro SM_LDAP_STRUCT *lmap; 5190792Sgshapiro{ 5290792Sgshapiro if (lmap == NULL) 5390792Sgshapiro return; 5490792Sgshapiro 5594334Sgshapiro lmap->ldap_target = NULL; 5690792Sgshapiro lmap->ldap_port = LDAP_PORT; 5794334Sgshapiro#if _FFR_LDAP_URI 5894334Sgshapiro lmap->ldap_uri = false; 5994334Sgshapiro#endif /* _FFR_LDAP_URI */ 6094334Sgshapiro# if _FFR_LDAP_SETVERSION 6194334Sgshapiro lmap->ldap_version = 0; 6294334Sgshapiro# endif /* _FFR_LDAP_SETVERSION */ 6390792Sgshapiro lmap->ldap_deref = LDAP_DEREF_NEVER; 6490792Sgshapiro lmap->ldap_timelimit = LDAP_NO_LIMIT; 6590792Sgshapiro lmap->ldap_sizelimit = LDAP_NO_LIMIT; 6690792Sgshapiro# ifdef LDAP_REFERRALS 6790792Sgshapiro lmap->ldap_options = LDAP_OPT_REFERRALS; 6890792Sgshapiro# else /* LDAP_REFERRALS */ 6990792Sgshapiro lmap->ldap_options = 0; 7090792Sgshapiro# endif /* LDAP_REFERRALS */ 7190792Sgshapiro lmap->ldap_attrsep = '\0'; 7290792Sgshapiro lmap->ldap_binddn = NULL; 7390792Sgshapiro lmap->ldap_secret = NULL; 7490792Sgshapiro lmap->ldap_method = LDAP_AUTH_SIMPLE; 7590792Sgshapiro lmap->ldap_base = NULL; 7690792Sgshapiro lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 7790792Sgshapiro lmap->ldap_attrsonly = LDAPMAP_FALSE; 7890792Sgshapiro lmap->ldap_timeout.tv_sec = 0; 7990792Sgshapiro lmap->ldap_timeout.tv_usec = 0; 8090792Sgshapiro lmap->ldap_ld = NULL; 8190792Sgshapiro lmap->ldap_filter = NULL; 8290792Sgshapiro lmap->ldap_attr[0] = NULL; 8390792Sgshapiro#if _FFR_LDAP_RECURSION 8494334Sgshapiro lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; 8594334Sgshapiro lmap->ldap_attr_needobjclass[0] = NULL; 8690792Sgshapiro#endif /* _FFR_LDAP_RECURSION */ 8790792Sgshapiro lmap->ldap_res = NULL; 8890792Sgshapiro lmap->ldap_next = NULL; 8990792Sgshapiro lmap->ldap_pid = 0; 9090792Sgshapiro} 9190792Sgshapiro 9290792Sgshapiro/* 9390792Sgshapiro** SM_LDAP_START -- actually connect to an LDAP server 9490792Sgshapiro** 9590792Sgshapiro** Parameters: 9690792Sgshapiro** name -- name of map for debug output. 9790792Sgshapiro** lmap -- the LDAP map being opened. 9890792Sgshapiro** 9990792Sgshapiro** Returns: 10090792Sgshapiro** true if connection is successful, false otherwise. 10190792Sgshapiro** 10290792Sgshapiro** Side Effects: 10390792Sgshapiro** Populates lmap->ldap_ld. 10490792Sgshapiro*/ 10590792Sgshapiro 10690792Sgshapirostatic jmp_buf LDAPTimeout; 10790792Sgshapiro 10890792Sgshapiro#define SM_LDAP_SETTIMEOUT(to) \ 10990792Sgshapirodo \ 11090792Sgshapiro{ \ 11190792Sgshapiro if (to != 0) \ 11290792Sgshapiro { \ 11390792Sgshapiro if (setjmp(LDAPTimeout) != 0) \ 11490792Sgshapiro { \ 11590792Sgshapiro errno = ETIMEDOUT; \ 11690792Sgshapiro return false; \ 11790792Sgshapiro } \ 11890792Sgshapiro ev = sm_setevent(to, ldaptimeout, 0); \ 11990792Sgshapiro } \ 12090792Sgshapiro} while (0) 12190792Sgshapiro 12290792Sgshapiro#define SM_LDAP_CLEARTIMEOUT() \ 12390792Sgshapirodo \ 12490792Sgshapiro{ \ 12590792Sgshapiro if (ev != NULL) \ 12690792Sgshapiro sm_clrevent(ev); \ 12790792Sgshapiro} while (0) 12890792Sgshapiro 12990792Sgshapirobool 13090792Sgshapirosm_ldap_start(name, lmap) 13190792Sgshapiro char *name; 13290792Sgshapiro SM_LDAP_STRUCT *lmap; 13390792Sgshapiro{ 13490792Sgshapiro int bind_result; 13590792Sgshapiro int save_errno; 13690792Sgshapiro SM_EVENT *ev = NULL; 13790792Sgshapiro LDAP *ld; 13890792Sgshapiro 13990792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 2)) 14090792Sgshapiro sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 14190792Sgshapiro 14290792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 9)) 14390792Sgshapiro sm_dprintf("ldapmap_start(%s, %d)\n", 14494334Sgshapiro lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target, 14590792Sgshapiro lmap->ldap_port); 14690792Sgshapiro 14790792Sgshapiro# if USE_LDAP_INIT 14894334Sgshapiro# if _FFR_LDAP_URI 14994334Sgshapiro if (lmap->ldap_uri) 15094334Sgshapiro errno = ldap_initialize(&ld, lmap->ldap_target); 15194334Sgshapiro else 15294334Sgshapiro# endif /* _FFR_LDAP_URI */ 15394334Sgshapiro ld = ldap_init(lmap->ldap_target, lmap->ldap_port); 15490792Sgshapiro save_errno = errno; 15590792Sgshapiro# else /* USE_LDAP_INIT */ 15690792Sgshapiro /* 15790792Sgshapiro ** If using ldap_open(), the actual connection to the server 15890792Sgshapiro ** happens now so we need the timeout here. For ldap_init(), 15990792Sgshapiro ** the connection happens at bind time. 16090792Sgshapiro */ 16190792Sgshapiro 16290792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 16394334Sgshapiro ld = ldap_open(lmap->ldap_target, lmap->ldap_port); 16490792Sgshapiro save_errno = errno; 16590792Sgshapiro 16690792Sgshapiro /* clear the event if it has not sprung */ 16790792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 16890792Sgshapiro# endif /* USE_LDAP_INIT */ 16990792Sgshapiro 17090792Sgshapiro errno = save_errno; 17190792Sgshapiro if (ld == NULL) 17290792Sgshapiro return false; 17390792Sgshapiro 17490792Sgshapiro sm_ldap_setopts(ld, lmap); 17590792Sgshapiro 17690792Sgshapiro# if USE_LDAP_INIT 17790792Sgshapiro /* 17890792Sgshapiro ** If using ldap_init(), the actual connection to the server 17990792Sgshapiro ** happens at ldap_bind_s() so we need the timeout here. 18090792Sgshapiro */ 18190792Sgshapiro 18290792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 18390792Sgshapiro# endif /* USE_LDAP_INIT */ 18490792Sgshapiro 18590792Sgshapiro# ifdef LDAP_AUTH_KRBV4 18690792Sgshapiro if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 18790792Sgshapiro lmap->ldap_secret != NULL) 18890792Sgshapiro { 18990792Sgshapiro /* 19090792Sgshapiro ** Need to put ticket in environment here instead of 19190792Sgshapiro ** during parseargs as there may be different tickets 19290792Sgshapiro ** for different LDAP connections. 19390792Sgshapiro */ 19490792Sgshapiro 19590792Sgshapiro (void) putenv(lmap->ldap_secret); 19690792Sgshapiro } 19790792Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 19890792Sgshapiro 19990792Sgshapiro bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 20090792Sgshapiro lmap->ldap_secret, lmap->ldap_method); 20190792Sgshapiro 20290792Sgshapiro# if USE_LDAP_INIT 20390792Sgshapiro /* clear the event if it has not sprung */ 20490792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 20590792Sgshapiro# endif /* USE_LDAP_INIT */ 20690792Sgshapiro 20790792Sgshapiro if (bind_result != LDAP_SUCCESS) 20890792Sgshapiro { 20990792Sgshapiro errno = bind_result + E_LDAPBASE; 21090792Sgshapiro return false; 21190792Sgshapiro } 21290792Sgshapiro 21390792Sgshapiro /* Save PID to make sure only this PID closes the LDAP connection */ 21490792Sgshapiro lmap->ldap_pid = getpid(); 21590792Sgshapiro lmap->ldap_ld = ld; 21690792Sgshapiro return true; 21790792Sgshapiro} 21890792Sgshapiro 21990792Sgshapiro/* ARGSUSED */ 22090792Sgshapirostatic void 22190792Sgshapiroldaptimeout(unused) 22290792Sgshapiro int unused; 22390792Sgshapiro{ 22490792Sgshapiro /* 22590792Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 22690792Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 22790792Sgshapiro ** DOING. 22890792Sgshapiro */ 22990792Sgshapiro 23090792Sgshapiro errno = ETIMEDOUT; 23190792Sgshapiro longjmp(LDAPTimeout, 1); 23290792Sgshapiro} 23390792Sgshapiro 23490792Sgshapiro/* 23590792Sgshapiro** SM_LDAP_SEARCH -- iniate LDAP search 23690792Sgshapiro** 23790792Sgshapiro** Initiate an LDAP search, return the msgid. 23890792Sgshapiro** The calling function must collect the results. 23990792Sgshapiro** 24090792Sgshapiro** Parameters: 24190792Sgshapiro** lmap -- LDAP map information 24290792Sgshapiro** key -- key to substitute in LDAP filter 24390792Sgshapiro** 24490792Sgshapiro** Returns: 24590792Sgshapiro** -1 on failure, msgid on success 24690792Sgshapiro** 24790792Sgshapiro*/ 24890792Sgshapiro 24990792Sgshapiroint 25090792Sgshapirosm_ldap_search(lmap, key) 25190792Sgshapiro SM_LDAP_STRUCT *lmap; 25290792Sgshapiro char *key; 25390792Sgshapiro{ 25490792Sgshapiro int msgid; 25590792Sgshapiro char *fp, *p, *q; 25690792Sgshapiro char filter[LDAPMAP_MAX_FILTER + 1]; 25790792Sgshapiro 25890792Sgshapiro /* substitute key into filter, perhaps multiple times */ 25990792Sgshapiro memset(filter, '\0', sizeof filter); 26090792Sgshapiro fp = filter; 26190792Sgshapiro p = lmap->ldap_filter; 26290792Sgshapiro while ((q = strchr(p, '%')) != NULL) 26390792Sgshapiro { 26490792Sgshapiro if (q[1] == 's') 26590792Sgshapiro { 26690792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 26790792Sgshapiro "%.*s%s", (int) (q - p), p, key); 26890792Sgshapiro fp += strlen(fp); 26990792Sgshapiro p = q + 2; 27090792Sgshapiro } 27190792Sgshapiro else if (q[1] == '0') 27290792Sgshapiro { 27390792Sgshapiro char *k = key; 27490792Sgshapiro 27590792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 27690792Sgshapiro "%.*s", (int) (q - p), p); 27790792Sgshapiro fp += strlen(fp); 27890792Sgshapiro p = q + 2; 27990792Sgshapiro 28090792Sgshapiro /* Properly escape LDAP special characters */ 28190792Sgshapiro while (SPACELEFT(filter, fp) > 0 && 28290792Sgshapiro *k != '\0') 28390792Sgshapiro { 28490792Sgshapiro if (*k == '*' || *k == '(' || 28590792Sgshapiro *k == ')' || *k == '\\') 28690792Sgshapiro { 28790792Sgshapiro (void) sm_strlcat(fp, 28890792Sgshapiro (*k == '*' ? "\\2A" : 28990792Sgshapiro (*k == '(' ? "\\28" : 29090792Sgshapiro (*k == ')' ? "\\29" : 29190792Sgshapiro (*k == '\\' ? "\\5C" : 29290792Sgshapiro "\00")))), 29390792Sgshapiro SPACELEFT(filter, fp)); 29490792Sgshapiro fp += strlen(fp); 29590792Sgshapiro k++; 29690792Sgshapiro } 29790792Sgshapiro else 29890792Sgshapiro *fp++ = *k++; 29990792Sgshapiro } 30090792Sgshapiro } 30190792Sgshapiro else 30290792Sgshapiro { 30390792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 30490792Sgshapiro "%.*s", (int) (q - p + 1), p); 30590792Sgshapiro p = q + (q[1] == '%' ? 2 : 1); 30690792Sgshapiro fp += strlen(fp); 30790792Sgshapiro } 30890792Sgshapiro } 30990792Sgshapiro (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 31090792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 20)) 31190792Sgshapiro sm_dprintf("ldap search filter=%s\n", filter); 31290792Sgshapiro 31390792Sgshapiro lmap->ldap_res = NULL; 31494334Sgshapiro msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, 31594334Sgshapiro lmap->ldap_scope, filter, 31690792Sgshapiro (lmap->ldap_attr[0] == NULL ? NULL : 31790792Sgshapiro lmap->ldap_attr), 31890792Sgshapiro lmap->ldap_attrsonly); 31990792Sgshapiro return msgid; 32090792Sgshapiro} 32190792Sgshapiro 32290792Sgshapiro# if _FFR_LDAP_RECURSION 32390792Sgshapiro/* 32494334Sgshapiro** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a 32594334Sgshapiro** particular objectClass 32694334Sgshapiro** 32794334Sgshapiro** Parameters: 32894334Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 32994334Sgshapiro** entry -- current LDAP entry struct 33094334Sgshapiro** ocvalue -- particular objectclass in question. 33194334Sgshapiro** may be of form (fee|foo|fum) meaning 33294334Sgshapiro** any entry can be part of either fee, 33394334Sgshapiro** foo or fum objectclass 33494334Sgshapiro** 33594334Sgshapiro** Returns: 33694334Sgshapiro** true if item has that objectClass 33794334Sgshapiro*/ 33894334Sgshapiro 33994334Sgshapirostatic bool 34094334Sgshapirosm_ldap_has_objectclass(lmap, entry, ocvalue) 34194334Sgshapiro SM_LDAP_STRUCT *lmap; 34294334Sgshapiro LDAPMessage *entry; 34394334Sgshapiro char *ocvalue; 34494334Sgshapiro{ 34594334Sgshapiro char **vals = NULL; 34694334Sgshapiro int i; 34794334Sgshapiro 34894334Sgshapiro if (ocvalue == NULL) 34994334Sgshapiro return false; 35094334Sgshapiro 35194334Sgshapiro vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); 35294334Sgshapiro if (vals == NULL) 35394334Sgshapiro return false; 35494334Sgshapiro 35594334Sgshapiro for (i = 0; vals[i] != NULL; i++) 35694334Sgshapiro { 35794334Sgshapiro char *p; 35894334Sgshapiro char *q; 35994334Sgshapiro 36094334Sgshapiro p = q = ocvalue; 36194334Sgshapiro while (*p != '\0') 36294334Sgshapiro { 36394334Sgshapiro while (*p != '\0' && *p != '|') 36494334Sgshapiro p++; 36594334Sgshapiro 36694334Sgshapiro if ((p - q) == strlen(vals[i]) && 36794334Sgshapiro sm_strncasecmp(vals[i], q, p - q) == 0) 36894334Sgshapiro { 36994334Sgshapiro ldap_value_free(vals); 37094334Sgshapiro return true; 37194334Sgshapiro } 37294334Sgshapiro 37394334Sgshapiro while (*p == '|') 37494334Sgshapiro p++; 37594334Sgshapiro q = p; 37694334Sgshapiro } 37794334Sgshapiro } 37894334Sgshapiro 37994334Sgshapiro ldap_value_free(vals); 38094334Sgshapiro return false; 38194334Sgshapiro} 38294334Sgshapiro 38394334Sgshapiro/* 38490792Sgshapiro** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 38590792Sgshapiro** 38690792Sgshapiro** Parameters: 38790792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 38890792Sgshapiro** msgid -- msgid returned by sm_ldap_search() 38990792Sgshapiro** flags -- flags for the lookup 39090792Sgshapiro** delim -- delimiter for result concatenation 39190792Sgshapiro** rpool -- memory pool for storage 39290792Sgshapiro** result -- return string 39390792Sgshapiro** recurse -- recursion list 39490792Sgshapiro** 39590792Sgshapiro** Returns: 39690792Sgshapiro** status (sysexit) 39790792Sgshapiro*/ 39890792Sgshapiro 39994334Sgshapiro# define SM_LDAP_ERROR_CLEANUP() \ 40090792Sgshapiro{ \ 40190792Sgshapiro if (lmap->ldap_res != NULL) \ 40290792Sgshapiro { \ 40390792Sgshapiro ldap_msgfree(lmap->ldap_res); \ 40490792Sgshapiro lmap->ldap_res = NULL; \ 40590792Sgshapiro } \ 40690792Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); \ 40790792Sgshapiro} 40890792Sgshapiro 40994334Sgshapirostatic SM_LDAP_RECURSE_ENTRY * 41094334Sgshapirosm_ldap_add_recurse(top, item, type, rpool) 41190792Sgshapiro SM_LDAP_RECURSE_LIST **top; 41290792Sgshapiro char *item; 41390792Sgshapiro int type; 41490792Sgshapiro SM_RPOOL_T *rpool; 41590792Sgshapiro{ 41694334Sgshapiro int n; 41794334Sgshapiro int m; 41894334Sgshapiro int p; 41994334Sgshapiro int insertat; 42094334Sgshapiro int moveb; 42194334Sgshapiro int oldsizeb; 42294334Sgshapiro int rc; 42394334Sgshapiro SM_LDAP_RECURSE_ENTRY *newe; 42494334Sgshapiro SM_LDAP_RECURSE_ENTRY **olddata; 42590792Sgshapiro 42694334Sgshapiro /* 42794334Sgshapiro ** This code will maintain a list of 42894334Sgshapiro ** SM_LDAP_RECURSE_ENTRY structures 42994334Sgshapiro ** in ascending order. 43094334Sgshapiro */ 43194334Sgshapiro 43294334Sgshapiro if (*top == NULL) 43390792Sgshapiro { 43494334Sgshapiro /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ 43594334Sgshapiro *top = sm_rpool_malloc_x(rpool, sizeof **top); 43694334Sgshapiro (*top)->lr_cnt = 0; 43794334Sgshapiro (*top)->lr_size = 0; 43894334Sgshapiro (*top)->lr_data = NULL; 43994334Sgshapiro } 44094334Sgshapiro 44194334Sgshapiro if ((*top)->lr_cnt >= (*top)->lr_size) 44294334Sgshapiro { 44394334Sgshapiro /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ 44494334Sgshapiro olddata = (*top)->lr_data; 44594334Sgshapiro if ((*top)->lr_size == 0) 44690792Sgshapiro { 44794334Sgshapiro oldsizeb = 0; 44894334Sgshapiro (*top)->lr_size = 256; 44990792Sgshapiro } 45094334Sgshapiro else 45194334Sgshapiro { 45294334Sgshapiro oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); 45394334Sgshapiro (*top)->lr_size *= 2; 45494334Sgshapiro } 45594334Sgshapiro (*top)->lr_data = sm_rpool_malloc_x(rpool, 45694334Sgshapiro (*top)->lr_size * sizeof *((*top)->lr_data)); 45794334Sgshapiro if (oldsizeb > 0) 45894334Sgshapiro memcpy((*top)->lr_data, olddata, oldsizeb); 45990792Sgshapiro } 46090792Sgshapiro 46194334Sgshapiro /* 46294334Sgshapiro ** Binary search/insert item:type into list. 46394334Sgshapiro ** Return current entry pointer if already exists. 46494334Sgshapiro */ 46594334Sgshapiro 46694334Sgshapiro n = 0; 46794334Sgshapiro m = (*top)->lr_cnt - 1; 46894334Sgshapiro if (m < 0) 46994334Sgshapiro insertat = 0; 47090792Sgshapiro else 47194334Sgshapiro insertat = -1; 47294334Sgshapiro 47394334Sgshapiro while (insertat == -1) 47494334Sgshapiro { 47594334Sgshapiro p = (m + n) / 2; 47694334Sgshapiro 47794334Sgshapiro rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); 47894334Sgshapiro if (rc == 0) 47994334Sgshapiro rc = type - (*top)->lr_data[p]->lr_type; 48094334Sgshapiro 48194334Sgshapiro if (rc < 0) 48294334Sgshapiro m = p - 1; 48394334Sgshapiro else if (rc > 0) 48494334Sgshapiro n = p + 1; 48594334Sgshapiro else 48694334Sgshapiro return (*top)->lr_data[p]; 48794334Sgshapiro 48894334Sgshapiro if (m == -1) 48994334Sgshapiro insertat = 0; 49094334Sgshapiro else if (n >= (*top)->lr_cnt) 49194334Sgshapiro insertat = (*top)->lr_cnt; 49294334Sgshapiro else if (m < n) 49394334Sgshapiro insertat = m + 1; 49494334Sgshapiro } 49594334Sgshapiro 49694334Sgshapiro /* 49794334Sgshapiro ** Not found in list, make room 49894334Sgshapiro ** at insert point and add it. 49994334Sgshapiro */ 50094334Sgshapiro 50194334Sgshapiro newe = sm_rpool_malloc_x(rpool, sizeof *newe); 50294334Sgshapiro if (newe != NULL) 50394334Sgshapiro { 50494334Sgshapiro moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); 50594334Sgshapiro if (moveb > 0) 50694334Sgshapiro memmove(&((*top)->lr_data[insertat + 1]), 50794334Sgshapiro &((*top)->lr_data[insertat]), 50894334Sgshapiro moveb); 50994334Sgshapiro 51094334Sgshapiro newe->lr_search = sm_rpool_strdup_x(rpool, item); 51194334Sgshapiro newe->lr_type = type; 51294334Sgshapiro newe->lr_done = false; 51394334Sgshapiro 51494334Sgshapiro ((*top)->lr_data)[insertat] = newe; 51594334Sgshapiro (*top)->lr_cnt++; 51694334Sgshapiro } 51794334Sgshapiro return newe; 51890792Sgshapiro} 51990792Sgshapiro 52090792Sgshapiroint 52194334Sgshapirosm_ldap_results(lmap, msgid, flags, delim, rpool, result, 52294334Sgshapiro resultln, resultsz, recurse) 52390792Sgshapiro SM_LDAP_STRUCT *lmap; 52490792Sgshapiro int msgid; 52590792Sgshapiro int flags; 52694334Sgshapiro int delim; 52790792Sgshapiro SM_RPOOL_T *rpool; 52890792Sgshapiro char **result; 52994334Sgshapiro int *resultln; 53094334Sgshapiro int *resultsz; 53190792Sgshapiro SM_LDAP_RECURSE_LIST *recurse; 53290792Sgshapiro{ 53390792Sgshapiro bool toplevel; 53490792Sgshapiro int i; 53590792Sgshapiro int statp; 53690792Sgshapiro int vsize; 53790792Sgshapiro int ret; 53890792Sgshapiro int save_errno; 53990792Sgshapiro char *p; 54094334Sgshapiro SM_LDAP_RECURSE_ENTRY *rl; 54190792Sgshapiro 54290792Sgshapiro /* Are we the top top level of the search? */ 54390792Sgshapiro toplevel = (recurse == NULL); 54490792Sgshapiro 54590792Sgshapiro /* Get results */ 54690792Sgshapiro statp = EX_NOTFOUND; 54790792Sgshapiro while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 54890792Sgshapiro (lmap->ldap_timeout.tv_sec == 0 ? NULL : 54990792Sgshapiro &(lmap->ldap_timeout)), 55090792Sgshapiro &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 55190792Sgshapiro { 55290792Sgshapiro LDAPMessage *entry; 55390792Sgshapiro 55490792Sgshapiro /* If we don't want multiple values and we have one, break */ 55594334Sgshapiro if ((char) delim == '\0' && *result != NULL) 55690792Sgshapiro break; 55790792Sgshapiro 55890792Sgshapiro /* Cycle through all entries */ 55990792Sgshapiro for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 56090792Sgshapiro entry != NULL; 56190792Sgshapiro entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 56290792Sgshapiro { 56390792Sgshapiro BerElement *ber; 56490792Sgshapiro char *attr; 56590792Sgshapiro char **vals = NULL; 56690792Sgshapiro char *dn; 56790792Sgshapiro 56890792Sgshapiro /* 56990792Sgshapiro ** If matching only and found an entry, 57090792Sgshapiro ** no need to spin through attributes 57190792Sgshapiro */ 57290792Sgshapiro 573125820Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 574125820Sgshapiro { 575125820Sgshapiro statp = EX_OK; 57690792Sgshapiro continue; 577125820Sgshapiro } 57890792Sgshapiro 57990792Sgshapiro /* record completed DN's to prevent loops */ 58090792Sgshapiro dn = ldap_get_dn(lmap->ldap_ld, entry); 58190792Sgshapiro if (dn == NULL) 58290792Sgshapiro { 58390792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 58490792Sgshapiro save_errno += E_LDAPBASE; 58594334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 58690792Sgshapiro errno = save_errno; 587120256Sgshapiro return EX_TEMPFAIL; 58890792Sgshapiro } 58990792Sgshapiro 59094334Sgshapiro rl = sm_ldap_add_recurse(&recurse, dn, 59194334Sgshapiro SM_LDAP_ATTR_DN, 59294334Sgshapiro rpool); 59394334Sgshapiro 59494334Sgshapiro if (rl == NULL) 59590792Sgshapiro { 59690792Sgshapiro ldap_memfree(dn); 59794334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 59890792Sgshapiro errno = ENOMEM; 59990792Sgshapiro return EX_OSERR; 60094334Sgshapiro } 60194334Sgshapiro else if (rl->lr_done) 60294334Sgshapiro { 60390792Sgshapiro /* already on list, skip it */ 60490792Sgshapiro ldap_memfree(dn); 60590792Sgshapiro continue; 60690792Sgshapiro } 60790792Sgshapiro ldap_memfree(dn); 60890792Sgshapiro 60990792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 61090792Sgshapiro /* 61190792Sgshapiro ** Reset value to prevent lingering 61290792Sgshapiro ** LDAP_DECODING_ERROR due to 61390792Sgshapiro ** OpenLDAP 1.X's hack (see below) 61490792Sgshapiro */ 61590792Sgshapiro 61690792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 61790792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 61890792Sgshapiro 61990792Sgshapiro for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 62090792Sgshapiro &ber); 62190792Sgshapiro attr != NULL; 62290792Sgshapiro attr = ldap_next_attribute(lmap->ldap_ld, entry, 62390792Sgshapiro ber)) 62490792Sgshapiro { 62590792Sgshapiro char *tmp, *vp_tmp; 62690792Sgshapiro int type; 62794334Sgshapiro char *needobjclass = NULL; 62890792Sgshapiro 62994334Sgshapiro type = SM_LDAP_ATTR_NONE; 63090792Sgshapiro for (i = 0; lmap->ldap_attr[i] != NULL; i++) 63190792Sgshapiro { 63290792Sgshapiro if (sm_strcasecmp(lmap->ldap_attr[i], 63390792Sgshapiro attr) == 0) 63490792Sgshapiro { 63590792Sgshapiro type = lmap->ldap_attr_type[i]; 63694334Sgshapiro needobjclass = lmap->ldap_attr_needobjclass[i]; 63790792Sgshapiro break; 63890792Sgshapiro } 63990792Sgshapiro } 64094334Sgshapiro 64194334Sgshapiro if (bitset(SM_LDAP_USE_ALLATTR, flags) && 64294334Sgshapiro type == SM_LDAP_ATTR_NONE) 64390792Sgshapiro { 64494334Sgshapiro /* URL lookups specify attrs to use */ 64594334Sgshapiro type = SM_LDAP_ATTR_NORMAL; 64694334Sgshapiro needobjclass = NULL; 64794334Sgshapiro } 64894334Sgshapiro 64994334Sgshapiro if (type == SM_LDAP_ATTR_NONE) 65094334Sgshapiro { 65190792Sgshapiro /* attribute not requested */ 65290792Sgshapiro ldap_memfree(attr); 65394334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 65490792Sgshapiro errno = EFAULT; 65590792Sgshapiro return EX_SOFTWARE; 65690792Sgshapiro } 65790792Sgshapiro 65894334Sgshapiro /* 65994334Sgshapiro ** For recursion on a particular attribute, 66094334Sgshapiro ** we may need to see if this entry is 66194334Sgshapiro ** part of a particular objectclass. 66294334Sgshapiro ** Also, ignore objectClass attribute. 66394334Sgshapiro ** Otherwise we just ignore this attribute. 66494334Sgshapiro */ 66594334Sgshapiro 66694334Sgshapiro if (type == SM_LDAP_ATTR_OBJCLASS || 66794334Sgshapiro (needobjclass != NULL && 66894334Sgshapiro !sm_ldap_has_objectclass(lmap, entry, 66994334Sgshapiro needobjclass))) 67094334Sgshapiro { 67194334Sgshapiro ldap_memfree(attr); 67294334Sgshapiro continue; 67394334Sgshapiro } 67494334Sgshapiro 67590792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 67690792Sgshapiro { 67790792Sgshapiro vals = ldap_get_values(lmap->ldap_ld, 67890792Sgshapiro entry, 67990792Sgshapiro attr); 68090792Sgshapiro if (vals == NULL) 68190792Sgshapiro { 68290792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 68390792Sgshapiro if (save_errno == LDAP_SUCCESS) 68490792Sgshapiro { 68590792Sgshapiro ldap_memfree(attr); 68690792Sgshapiro continue; 68790792Sgshapiro } 68890792Sgshapiro 68990792Sgshapiro /* Must be an error */ 69090792Sgshapiro save_errno += E_LDAPBASE; 69190792Sgshapiro ldap_memfree(attr); 69294334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 69390792Sgshapiro errno = save_errno; 69490792Sgshapiro return EX_TEMPFAIL; 69590792Sgshapiro } 69690792Sgshapiro } 69790792Sgshapiro 69890792Sgshapiro statp = EX_OK; 69990792Sgshapiro 70090792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 70190792Sgshapiro /* 70290792Sgshapiro ** Reset value to prevent lingering 70390792Sgshapiro ** LDAP_DECODING_ERROR due to 70490792Sgshapiro ** OpenLDAP 1.X's hack (see below) 70590792Sgshapiro */ 70690792Sgshapiro 70790792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 70890792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 70990792Sgshapiro 71090792Sgshapiro /* 71190792Sgshapiro ** If matching only, 71290792Sgshapiro ** no need to spin through entries 71390792Sgshapiro */ 71490792Sgshapiro 71590792Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 71690792Sgshapiro { 71790792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 71890792Sgshapiro ldap_value_free(vals); 71990792Sgshapiro ldap_memfree(attr); 72090792Sgshapiro continue; 72190792Sgshapiro } 72290792Sgshapiro 72390792Sgshapiro /* 72490792Sgshapiro ** If we don't want multiple values, 72590792Sgshapiro ** return first found. 72690792Sgshapiro */ 72790792Sgshapiro 72894334Sgshapiro if ((char) delim == '\0') 72990792Sgshapiro { 73094334Sgshapiro if (*result != NULL) 73194334Sgshapiro { 73294334Sgshapiro /* already have a value */ 73394334Sgshapiro break; 73494334Sgshapiro } 73594334Sgshapiro 73694334Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 73794334Sgshapiro flags) && 73894334Sgshapiro *result != NULL) 73994334Sgshapiro { 74094334Sgshapiro /* only wanted one match */ 74194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 74294334Sgshapiro errno = ENOENT; 74394334Sgshapiro return EX_NOTFOUND; 74494334Sgshapiro } 74594334Sgshapiro 74690792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 74790792Sgshapiro { 74890792Sgshapiro *result = sm_rpool_strdup_x(rpool, 74990792Sgshapiro attr); 75090792Sgshapiro ldap_memfree(attr); 75190792Sgshapiro break; 75290792Sgshapiro } 75390792Sgshapiro 75490792Sgshapiro if (vals[0] == NULL) 75590792Sgshapiro { 75690792Sgshapiro ldap_value_free(vals); 75790792Sgshapiro ldap_memfree(attr); 75890792Sgshapiro continue; 75990792Sgshapiro } 76090792Sgshapiro 76190792Sgshapiro vsize = strlen(vals[0]) + 1; 76290792Sgshapiro if (lmap->ldap_attrsep != '\0') 76390792Sgshapiro vsize += strlen(attr) + 1; 76490792Sgshapiro *result = sm_rpool_malloc_x(rpool, 76590792Sgshapiro vsize); 76690792Sgshapiro if (lmap->ldap_attrsep != '\0') 76790792Sgshapiro sm_snprintf(*result, vsize, 76890792Sgshapiro "%s%c%s", 76990792Sgshapiro attr, 77090792Sgshapiro lmap->ldap_attrsep, 77190792Sgshapiro vals[0]); 77290792Sgshapiro else 77390792Sgshapiro sm_strlcpy(*result, vals[0], 77490792Sgshapiro vsize); 77590792Sgshapiro ldap_value_free(vals); 77690792Sgshapiro ldap_memfree(attr); 77790792Sgshapiro break; 77890792Sgshapiro } 77990792Sgshapiro 78090792Sgshapiro /* attributes only */ 78190792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 78290792Sgshapiro { 78390792Sgshapiro if (*result == NULL) 78490792Sgshapiro *result = sm_rpool_strdup_x(rpool, 78590792Sgshapiro attr); 78690792Sgshapiro else 78790792Sgshapiro { 78894334Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 78994334Sgshapiro flags) && 79094334Sgshapiro *result != NULL) 79194334Sgshapiro { 79294334Sgshapiro /* only wanted one match */ 79394334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 79494334Sgshapiro errno = ENOENT; 79594334Sgshapiro return EX_NOTFOUND; 79694334Sgshapiro } 79794334Sgshapiro 79890792Sgshapiro vsize = strlen(*result) + 79990792Sgshapiro strlen(attr) + 2; 80090792Sgshapiro tmp = sm_rpool_malloc_x(rpool, 80190792Sgshapiro vsize); 80290792Sgshapiro (void) sm_snprintf(tmp, 80390792Sgshapiro vsize, "%s%c%s", 80494334Sgshapiro *result, (char) delim, 80590792Sgshapiro attr); 80690792Sgshapiro *result = tmp; 80790792Sgshapiro } 80890792Sgshapiro ldap_memfree(attr); 80990792Sgshapiro continue; 81090792Sgshapiro } 81190792Sgshapiro 81290792Sgshapiro /* 81394334Sgshapiro ** If there is more than one, munge then 81494334Sgshapiro ** into a map_coldelim separated string. 81594334Sgshapiro ** If we are recursing we may have an entry 81694334Sgshapiro ** with no 'normal' values to put in the 81794334Sgshapiro ** string. 81894334Sgshapiro ** This is not an error. 81990792Sgshapiro */ 82090792Sgshapiro 82194334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && 82294334Sgshapiro bitset(SM_LDAP_SINGLEMATCH, flags) && 82394334Sgshapiro *result != NULL) 82494334Sgshapiro { 82594334Sgshapiro /* only wanted one match */ 82694334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 82794334Sgshapiro errno = ENOENT; 82894334Sgshapiro return EX_NOTFOUND; 82994334Sgshapiro } 83094334Sgshapiro 83190792Sgshapiro vsize = 0; 83290792Sgshapiro for (i = 0; vals[i] != NULL; i++) 83390792Sgshapiro { 83494334Sgshapiro if (type == SM_LDAP_ATTR_DN || 83594334Sgshapiro type == SM_LDAP_ATTR_FILTER || 83694334Sgshapiro type == SM_LDAP_ATTR_URL) 83790792Sgshapiro { 83894334Sgshapiro /* add to recursion */ 83994334Sgshapiro if (sm_ldap_add_recurse(&recurse, 84090792Sgshapiro vals[i], 84194334Sgshapiro type, 84294334Sgshapiro rpool) == NULL) 84390792Sgshapiro { 84494334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 84590792Sgshapiro errno = ENOMEM; 84690792Sgshapiro return EX_OSERR; 84790792Sgshapiro } 84890792Sgshapiro continue; 84990792Sgshapiro } 85094334Sgshapiro 85190792Sgshapiro vsize += strlen(vals[i]) + 1; 85290792Sgshapiro if (lmap->ldap_attrsep != '\0') 85390792Sgshapiro vsize += strlen(attr) + 1; 85490792Sgshapiro } 85590792Sgshapiro 85694334Sgshapiro /* 85794334Sgshapiro ** Create/Append to string any normal 85894334Sgshapiro ** attribute values. Otherwise, just free 85994334Sgshapiro ** memory and move on to the next 86094334Sgshapiro ** attribute in this entry. 86194334Sgshapiro */ 86294334Sgshapiro 86394334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) 86490792Sgshapiro { 86594334Sgshapiro char *pe; 86694334Sgshapiro 86794334Sgshapiro /* Grow result string if needed */ 86894334Sgshapiro if ((*resultln + vsize) >= *resultsz) 86990792Sgshapiro { 87094334Sgshapiro while ((*resultln + vsize) >= *resultsz) 87194334Sgshapiro { 87294334Sgshapiro if (*resultsz == 0) 87394334Sgshapiro *resultsz = 1024; 87494334Sgshapiro else 87594334Sgshapiro *resultsz *= 2; 87694334Sgshapiro } 87794334Sgshapiro 87894334Sgshapiro vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); 87994334Sgshapiro *vp_tmp = '\0'; 88094334Sgshapiro 88194334Sgshapiro if (*result != NULL) 88294334Sgshapiro sm_strlcpy(vp_tmp, 88394334Sgshapiro *result, 88494334Sgshapiro *resultsz); 88594334Sgshapiro *result = vp_tmp; 88690792Sgshapiro } 88794334Sgshapiro 88894334Sgshapiro p = *result + *resultln; 88994334Sgshapiro pe = *result + *resultsz; 89094334Sgshapiro 89194334Sgshapiro for (i = 0; vals[i] != NULL; i++) 89290792Sgshapiro { 893102528Sgshapiro if (*resultln > 0 && 894102528Sgshapiro p < pe) 89594334Sgshapiro *p++ = (char) delim; 89694334Sgshapiro 89794334Sgshapiro if (lmap->ldap_attrsep != '\0') 89894334Sgshapiro { 89994334Sgshapiro p += sm_strlcpy(p, attr, 90094334Sgshapiro pe - p); 90194334Sgshapiro if (p < pe) 90294334Sgshapiro *p++ = lmap->ldap_attrsep; 90394334Sgshapiro } 90494334Sgshapiro 90594334Sgshapiro p += sm_strlcpy(p, vals[i], 90694334Sgshapiro pe - p); 90794334Sgshapiro *resultln = p - (*result); 90894334Sgshapiro if (p >= pe) 90994334Sgshapiro { 91094334Sgshapiro /* Internal error: buffer too small for LDAP values */ 91194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 91294334Sgshapiro errno = ENOMEM; 91394334Sgshapiro return EX_OSERR; 91494334Sgshapiro } 91590792Sgshapiro } 91690792Sgshapiro } 91790792Sgshapiro 91890792Sgshapiro ldap_value_free(vals); 91990792Sgshapiro ldap_memfree(attr); 92090792Sgshapiro } 92190792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 92290792Sgshapiro 92390792Sgshapiro /* 92490792Sgshapiro ** We check save_errno != LDAP_DECODING_ERROR since 92590792Sgshapiro ** OpenLDAP 1.X has a very ugly *undocumented* 92690792Sgshapiro ** hack of returning this error code from 92790792Sgshapiro ** ldap_next_attribute() if the library freed the 92890792Sgshapiro ** ber attribute. See: 92990792Sgshapiro ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 93090792Sgshapiro */ 93190792Sgshapiro 93290792Sgshapiro if (save_errno != LDAP_SUCCESS && 93390792Sgshapiro save_errno != LDAP_DECODING_ERROR) 93490792Sgshapiro { 93590792Sgshapiro /* Must be an error */ 93690792Sgshapiro save_errno += E_LDAPBASE; 93794334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 93890792Sgshapiro errno = save_errno; 93990792Sgshapiro return EX_TEMPFAIL; 94090792Sgshapiro } 94190792Sgshapiro 94294334Sgshapiro /* mark this DN as done */ 94394334Sgshapiro rl->lr_done = true; 94494334Sgshapiro 94590792Sgshapiro /* We don't want multiple values and we have one */ 94694334Sgshapiro if ((char) delim == '\0' && *result != NULL) 94790792Sgshapiro break; 94890792Sgshapiro } 94990792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 95090792Sgshapiro if (save_errno != LDAP_SUCCESS && 95190792Sgshapiro save_errno != LDAP_DECODING_ERROR) 95290792Sgshapiro { 95390792Sgshapiro /* Must be an error */ 95490792Sgshapiro save_errno += E_LDAPBASE; 95594334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 95690792Sgshapiro errno = save_errno; 95790792Sgshapiro return EX_TEMPFAIL; 95890792Sgshapiro } 95990792Sgshapiro ldap_msgfree(lmap->ldap_res); 96090792Sgshapiro lmap->ldap_res = NULL; 96190792Sgshapiro } 96290792Sgshapiro 96390792Sgshapiro if (ret == 0) 96490792Sgshapiro save_errno = ETIMEDOUT; 96590792Sgshapiro else 96690792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 96790792Sgshapiro if (save_errno != LDAP_SUCCESS) 96890792Sgshapiro { 96990792Sgshapiro statp = EX_TEMPFAIL; 97090792Sgshapiro if (ret != 0) 97190792Sgshapiro { 97290792Sgshapiro switch (save_errno) 97390792Sgshapiro { 97490792Sgshapiro#ifdef LDAP_SERVER_DOWN 97590792Sgshapiro case LDAP_SERVER_DOWN: 97690792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 97790792Sgshapiro case LDAP_TIMEOUT: 97890792Sgshapiro case LDAP_UNAVAILABLE: 97994334Sgshapiro 98094334Sgshapiro /* 98194334Sgshapiro ** server disappeared, 98294334Sgshapiro ** try reopen on next search 98394334Sgshapiro */ 98494334Sgshapiro 98590792Sgshapiro statp = EX_RESTART; 98690792Sgshapiro break; 98790792Sgshapiro } 98890792Sgshapiro save_errno += E_LDAPBASE; 98990792Sgshapiro } 99094334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 99190792Sgshapiro errno = save_errno; 99290792Sgshapiro return statp; 99390792Sgshapiro } 99490792Sgshapiro 99590792Sgshapiro if (lmap->ldap_res != NULL) 99690792Sgshapiro { 99790792Sgshapiro ldap_msgfree(lmap->ldap_res); 99890792Sgshapiro lmap->ldap_res = NULL; 99990792Sgshapiro } 100090792Sgshapiro 100190792Sgshapiro if (toplevel) 100290792Sgshapiro { 100394334Sgshapiro int rlidx; 100490792Sgshapiro 100590792Sgshapiro /* 100690792Sgshapiro ** Spin through the built-up recurse list at the top 100790792Sgshapiro ** of the recursion. Since new items are added at the 100890792Sgshapiro ** end of the shared list, we actually only ever get 100990792Sgshapiro ** one level of recursion before things pop back to the 101090792Sgshapiro ** top. Any items added to the list during that recursion 101190792Sgshapiro ** will be expanded by the top level. 101290792Sgshapiro */ 101390792Sgshapiro 101494334Sgshapiro for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++) 101590792Sgshapiro { 101694334Sgshapiro int newflags; 101790792Sgshapiro int sid; 101890792Sgshapiro int status; 101990792Sgshapiro 102094334Sgshapiro rl = recurse->lr_data[rlidx]; 102194334Sgshapiro 102294334Sgshapiro newflags = flags; 102394334Sgshapiro if (rl->lr_done) 102490792Sgshapiro { 102590792Sgshapiro /* already expanded */ 102690792Sgshapiro continue; 102790792Sgshapiro } 102894334Sgshapiro 102994334Sgshapiro if (rl->lr_type == SM_LDAP_ATTR_DN) 103090792Sgshapiro { 103190792Sgshapiro /* do DN search */ 103290792Sgshapiro sid = ldap_search(lmap->ldap_ld, 103390792Sgshapiro rl->lr_search, 103490792Sgshapiro lmap->ldap_scope, 103590792Sgshapiro "(objectClass=*)", 103694334Sgshapiro (lmap->ldap_attr[0] == NULL ? 103794334Sgshapiro NULL : lmap->ldap_attr), 103890792Sgshapiro lmap->ldap_attrsonly); 103990792Sgshapiro } 104094334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_FILTER) 104190792Sgshapiro { 104290792Sgshapiro /* do new search */ 104390792Sgshapiro sid = ldap_search(lmap->ldap_ld, 104490792Sgshapiro lmap->ldap_base, 104590792Sgshapiro lmap->ldap_scope, 104690792Sgshapiro rl->lr_search, 104794334Sgshapiro (lmap->ldap_attr[0] == NULL ? 104894334Sgshapiro NULL : lmap->ldap_attr), 104990792Sgshapiro lmap->ldap_attrsonly); 105090792Sgshapiro } 105194334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_URL) 105290792Sgshapiro { 105390792Sgshapiro /* do new URL search */ 105490792Sgshapiro sid = ldap_url_search(lmap->ldap_ld, 105590792Sgshapiro rl->lr_search, 105690792Sgshapiro lmap->ldap_attrsonly); 105794334Sgshapiro newflags |= SM_LDAP_USE_ALLATTR; 105890792Sgshapiro } 105990792Sgshapiro else 106090792Sgshapiro { 106190792Sgshapiro /* unknown or illegal attribute type */ 106290792Sgshapiro errno = EFAULT; 106390792Sgshapiro return EX_SOFTWARE; 106490792Sgshapiro } 106590792Sgshapiro 106690792Sgshapiro /* Collect results */ 106790792Sgshapiro if (sid == -1) 106890792Sgshapiro { 106990792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 107090792Sgshapiro statp = EX_TEMPFAIL; 107190792Sgshapiro switch (save_errno) 107290792Sgshapiro { 107390792Sgshapiro#ifdef LDAP_SERVER_DOWN 107490792Sgshapiro case LDAP_SERVER_DOWN: 107590792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 107690792Sgshapiro case LDAP_TIMEOUT: 107790792Sgshapiro case LDAP_UNAVAILABLE: 107894334Sgshapiro 107994334Sgshapiro /* 108094334Sgshapiro ** server disappeared, 108194334Sgshapiro ** try reopen on next search 108294334Sgshapiro */ 108394334Sgshapiro 108490792Sgshapiro statp = EX_RESTART; 108590792Sgshapiro break; 108690792Sgshapiro } 108790792Sgshapiro errno = save_errno + E_LDAPBASE; 108890792Sgshapiro return statp; 108990792Sgshapiro } 109090792Sgshapiro 109194334Sgshapiro status = sm_ldap_results(lmap, sid, newflags, delim, 109294334Sgshapiro rpool, result, resultln, 109394334Sgshapiro resultsz, recurse); 109490792Sgshapiro save_errno = errno; 109590792Sgshapiro if (status != EX_OK && status != EX_NOTFOUND) 109690792Sgshapiro { 109790792Sgshapiro errno = save_errno; 109890792Sgshapiro return status; 109990792Sgshapiro } 110090792Sgshapiro 110190792Sgshapiro /* Mark as done */ 110294334Sgshapiro rl->lr_done = true; 110394334Sgshapiro 110494334Sgshapiro /* Reset rlidx as new items may have been added */ 110594334Sgshapiro rlidx = -1; 110690792Sgshapiro } 110790792Sgshapiro } 110890792Sgshapiro return statp; 110990792Sgshapiro} 111090792Sgshapiro#endif /* _FFR_LDAP_RECURSION */ 111190792Sgshapiro 111290792Sgshapiro/* 111390792Sgshapiro** SM_LDAP_CLOSE -- close LDAP connection 111490792Sgshapiro** 111590792Sgshapiro** Parameters: 111690792Sgshapiro** lmap -- LDAP map information 111790792Sgshapiro** 111890792Sgshapiro** Returns: 111990792Sgshapiro** None. 112090792Sgshapiro** 112190792Sgshapiro*/ 112290792Sgshapiro 112390792Sgshapirovoid 112490792Sgshapirosm_ldap_close(lmap) 112590792Sgshapiro SM_LDAP_STRUCT *lmap; 112690792Sgshapiro{ 112790792Sgshapiro if (lmap->ldap_ld == NULL) 112890792Sgshapiro return; 112990792Sgshapiro 113090792Sgshapiro if (lmap->ldap_pid == getpid()) 113190792Sgshapiro ldap_unbind(lmap->ldap_ld); 113290792Sgshapiro lmap->ldap_ld = NULL; 113390792Sgshapiro lmap->ldap_pid = 0; 113490792Sgshapiro} 113590792Sgshapiro 113690792Sgshapiro/* 113790792Sgshapiro** SM_LDAP_SETOPTS -- set LDAP options 113890792Sgshapiro** 113990792Sgshapiro** Parameters: 114090792Sgshapiro** ld -- LDAP session handle 114190792Sgshapiro** lmap -- LDAP map information 114290792Sgshapiro** 114390792Sgshapiro** Returns: 114490792Sgshapiro** None. 114590792Sgshapiro** 114690792Sgshapiro*/ 114790792Sgshapiro 114890792Sgshapirovoid 114990792Sgshapirosm_ldap_setopts(ld, lmap) 115090792Sgshapiro LDAP *ld; 115190792Sgshapiro SM_LDAP_STRUCT *lmap; 115290792Sgshapiro{ 115390792Sgshapiro# if USE_LDAP_SET_OPTION 115494334Sgshapiro# if _FFR_LDAP_SETVERSION 115594334Sgshapiro if (lmap->ldap_version != 0) 115694334Sgshapiro { 115794334Sgshapiro ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 115894334Sgshapiro &lmap->ldap_version); 115994334Sgshapiro } 116094334Sgshapiro# endif /* _FFR_LDAP_SETVERSION */ 116190792Sgshapiro ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 116290792Sgshapiro if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 116390792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 116490792Sgshapiro else 116590792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 116690792Sgshapiro ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 116790792Sgshapiro ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 1168102528Sgshapiro# ifdef LDAP_OPT_RESTART 1169102528Sgshapiro ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1170102528Sgshapiro# endif /* LDAP_OPT_RESTART */ 117190792Sgshapiro# else /* USE_LDAP_SET_OPTION */ 117290792Sgshapiro /* From here on in we can use ldap internal timelimits */ 117390792Sgshapiro ld->ld_deref = lmap->ldap_deref; 117490792Sgshapiro ld->ld_options = lmap->ldap_options; 117590792Sgshapiro ld->ld_sizelimit = lmap->ldap_sizelimit; 117690792Sgshapiro ld->ld_timelimit = lmap->ldap_timelimit; 117790792Sgshapiro# endif /* USE_LDAP_SET_OPTION */ 117890792Sgshapiro} 117990792Sgshapiro 118090792Sgshapiro/* 118190792Sgshapiro** SM_LDAP_GETERRNO -- get ldap errno value 118290792Sgshapiro** 118390792Sgshapiro** Parameters: 118490792Sgshapiro** ld -- LDAP session handle 118590792Sgshapiro** 118690792Sgshapiro** Returns: 118790792Sgshapiro** LDAP errno. 118890792Sgshapiro** 118990792Sgshapiro*/ 119090792Sgshapiro 119190792Sgshapiroint 119290792Sgshapirosm_ldap_geterrno(ld) 119390792Sgshapiro LDAP *ld; 119490792Sgshapiro{ 119590792Sgshapiro int err = LDAP_SUCCESS; 119690792Sgshapiro 119790792Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 119890792Sgshapiro (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 119990792Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 120090792Sgshapiro# ifdef LDAP_OPT_SIZELIMIT 120190792Sgshapiro err = ldap_get_lderrno(ld, NULL, NULL); 120290792Sgshapiro# else /* LDAP_OPT_SIZELIMIT */ 120390792Sgshapiro err = ld->ld_errno; 120490792Sgshapiro 120590792Sgshapiro /* 120690792Sgshapiro ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 120790792Sgshapiro ** OpenLDAP 1.X's hack (see above) 120890792Sgshapiro */ 120990792Sgshapiro 121090792Sgshapiro ld->ld_errno = LDAP_SUCCESS; 121190792Sgshapiro# endif /* LDAP_OPT_SIZELIMIT */ 121290792Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 121390792Sgshapiro return err; 121490792Sgshapiro} 121590792Sgshapiro# endif /* LDAPMAP */ 1216