ldap.c revision 132943
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> 11132943SgshapiroSM_RCSID("@(#)$Id: ldap.c,v 1.59 2003/12/23 21:20:15 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 55132943Sgshapiro lmap->ldap_host = NULL; 5690792Sgshapiro lmap->ldap_port = LDAP_PORT; 57132943Sgshapiro lmap->ldap_uri = NULL; 5894334Sgshapiro lmap->ldap_version = 0; 5990792Sgshapiro lmap->ldap_deref = LDAP_DEREF_NEVER; 6090792Sgshapiro lmap->ldap_timelimit = LDAP_NO_LIMIT; 6190792Sgshapiro lmap->ldap_sizelimit = LDAP_NO_LIMIT; 6290792Sgshapiro# ifdef LDAP_REFERRALS 6390792Sgshapiro lmap->ldap_options = LDAP_OPT_REFERRALS; 6490792Sgshapiro# else /* LDAP_REFERRALS */ 6590792Sgshapiro lmap->ldap_options = 0; 6690792Sgshapiro# endif /* LDAP_REFERRALS */ 6790792Sgshapiro lmap->ldap_attrsep = '\0'; 6890792Sgshapiro lmap->ldap_binddn = NULL; 6990792Sgshapiro lmap->ldap_secret = NULL; 7090792Sgshapiro lmap->ldap_method = LDAP_AUTH_SIMPLE; 7190792Sgshapiro lmap->ldap_base = NULL; 7290792Sgshapiro lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 7390792Sgshapiro lmap->ldap_attrsonly = LDAPMAP_FALSE; 7490792Sgshapiro lmap->ldap_timeout.tv_sec = 0; 7590792Sgshapiro lmap->ldap_timeout.tv_usec = 0; 7690792Sgshapiro lmap->ldap_ld = NULL; 7790792Sgshapiro lmap->ldap_filter = NULL; 7890792Sgshapiro lmap->ldap_attr[0] = NULL; 7994334Sgshapiro lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; 8094334Sgshapiro lmap->ldap_attr_needobjclass[0] = NULL; 8190792Sgshapiro lmap->ldap_res = NULL; 8290792Sgshapiro lmap->ldap_next = NULL; 8390792Sgshapiro lmap->ldap_pid = 0; 8490792Sgshapiro} 8590792Sgshapiro 8690792Sgshapiro/* 8790792Sgshapiro** SM_LDAP_START -- actually connect to an LDAP server 8890792Sgshapiro** 8990792Sgshapiro** Parameters: 9090792Sgshapiro** name -- name of map for debug output. 9190792Sgshapiro** lmap -- the LDAP map being opened. 9290792Sgshapiro** 9390792Sgshapiro** Returns: 9490792Sgshapiro** true if connection is successful, false otherwise. 9590792Sgshapiro** 9690792Sgshapiro** Side Effects: 9790792Sgshapiro** Populates lmap->ldap_ld. 9890792Sgshapiro*/ 9990792Sgshapiro 10090792Sgshapirostatic jmp_buf LDAPTimeout; 10190792Sgshapiro 10290792Sgshapiro#define SM_LDAP_SETTIMEOUT(to) \ 10390792Sgshapirodo \ 10490792Sgshapiro{ \ 10590792Sgshapiro if (to != 0) \ 10690792Sgshapiro { \ 10790792Sgshapiro if (setjmp(LDAPTimeout) != 0) \ 10890792Sgshapiro { \ 10990792Sgshapiro errno = ETIMEDOUT; \ 11090792Sgshapiro return false; \ 11190792Sgshapiro } \ 11290792Sgshapiro ev = sm_setevent(to, ldaptimeout, 0); \ 11390792Sgshapiro } \ 11490792Sgshapiro} while (0) 11590792Sgshapiro 11690792Sgshapiro#define SM_LDAP_CLEARTIMEOUT() \ 11790792Sgshapirodo \ 11890792Sgshapiro{ \ 11990792Sgshapiro if (ev != NULL) \ 12090792Sgshapiro sm_clrevent(ev); \ 12190792Sgshapiro} while (0) 12290792Sgshapiro 12390792Sgshapirobool 12490792Sgshapirosm_ldap_start(name, lmap) 12590792Sgshapiro char *name; 12690792Sgshapiro SM_LDAP_STRUCT *lmap; 12790792Sgshapiro{ 12890792Sgshapiro int bind_result; 12990792Sgshapiro int save_errno; 130132943Sgshapiro char *id; 13190792Sgshapiro SM_EVENT *ev = NULL; 132132943Sgshapiro LDAP *ld = NULL; 13390792Sgshapiro 13490792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 2)) 13590792Sgshapiro sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 13690792Sgshapiro 137132943Sgshapiro if (lmap->ldap_host != NULL) 138132943Sgshapiro id = lmap->ldap_host; 139132943Sgshapiro else if (lmap->ldap_uri != NULL) 140132943Sgshapiro id = lmap->ldap_uri; 141132943Sgshapiro else 142132943Sgshapiro id = "localhost"; 143132943Sgshapiro 14490792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 9)) 145132943Sgshapiro { 146132943Sgshapiro /* Don't print a port number for LDAP URIs */ 147132943Sgshapiro if (lmap->ldap_uri != NULL) 148132943Sgshapiro sm_dprintf("ldapmap_start(%s)\n", id); 149132943Sgshapiro else 150132943Sgshapiro sm_dprintf("ldapmap_start(%s, %d)\n", id, 151132943Sgshapiro lmap->ldap_port); 152132943Sgshapiro } 15390792Sgshapiro 154132943Sgshapiro if (lmap->ldap_uri != NULL) 155132943Sgshapiro { 156132943Sgshapiro#if SM_CONF_LDAP_INITIALIZE 157132943Sgshapiro /* LDAP server supports URIs so use them directly */ 158132943Sgshapiro save_errno = ldap_initialize(&ld, lmap->ldap_uri); 159132943Sgshapiro#else /* SM_CONF_LDAP_INITIALIZE */ 160132943Sgshapiro int err; 161132943Sgshapiro LDAPURLDesc *ludp = NULL; 162132943Sgshapiro 163132943Sgshapiro /* Blast apart URL and use the ldap_init/ldap_open below */ 164132943Sgshapiro err = ldap_url_parse(lmap->ldap_uri, &ludp); 165132943Sgshapiro if (err != 0) 166132943Sgshapiro { 167132943Sgshapiro errno = err + E_LDAPURLBASE; 168132943Sgshapiro return false; 169132943Sgshapiro } 170132943Sgshapiro lmap->ldap_host = sm_strdup_x(ludp->lud_host); 171132943Sgshapiro if (lmap->ldap_host == NULL) 172132943Sgshapiro { 173132943Sgshapiro save_errno = errno; 174132943Sgshapiro ldap_free_urldesc(ludp); 175132943Sgshapiro errno = save_errno; 176132943Sgshapiro return false; 177132943Sgshapiro } 178132943Sgshapiro lmap->ldap_port = ludp->lud_port; 179132943Sgshapiro ldap_free_urldesc(ludp); 180132943Sgshapiro#endif /* SM_CONF_LDAP_INITIALIZE */ 181132943Sgshapiro } 182132943Sgshapiro 183132943Sgshapiro if (ld == NULL) 184132943Sgshapiro { 18590792Sgshapiro# if USE_LDAP_INIT 186132943Sgshapiro ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 187132943Sgshapiro save_errno = errno; 18890792Sgshapiro# else /* USE_LDAP_INIT */ 189132943Sgshapiro /* 190132943Sgshapiro ** If using ldap_open(), the actual connection to the server 191132943Sgshapiro ** happens now so we need the timeout here. For ldap_init(), 192132943Sgshapiro ** the connection happens at bind time. 193132943Sgshapiro */ 19490792Sgshapiro 195132943Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 196132943Sgshapiro ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 197132943Sgshapiro save_errno = errno; 19890792Sgshapiro 199132943Sgshapiro /* clear the event if it has not sprung */ 200132943Sgshapiro SM_LDAP_CLEARTIMEOUT(); 20190792Sgshapiro# endif /* USE_LDAP_INIT */ 202132943Sgshapiro } 20390792Sgshapiro 20490792Sgshapiro errno = save_errno; 20590792Sgshapiro if (ld == NULL) 20690792Sgshapiro return false; 20790792Sgshapiro 20890792Sgshapiro sm_ldap_setopts(ld, lmap); 20990792Sgshapiro 21090792Sgshapiro# if USE_LDAP_INIT 21190792Sgshapiro /* 21290792Sgshapiro ** If using ldap_init(), the actual connection to the server 21390792Sgshapiro ** happens at ldap_bind_s() so we need the timeout here. 21490792Sgshapiro */ 21590792Sgshapiro 21690792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 21790792Sgshapiro# endif /* USE_LDAP_INIT */ 21890792Sgshapiro 21990792Sgshapiro# ifdef LDAP_AUTH_KRBV4 22090792Sgshapiro if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 22190792Sgshapiro lmap->ldap_secret != NULL) 22290792Sgshapiro { 22390792Sgshapiro /* 22490792Sgshapiro ** Need to put ticket in environment here instead of 22590792Sgshapiro ** during parseargs as there may be different tickets 22690792Sgshapiro ** for different LDAP connections. 22790792Sgshapiro */ 22890792Sgshapiro 22990792Sgshapiro (void) putenv(lmap->ldap_secret); 23090792Sgshapiro } 23190792Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 23290792Sgshapiro 23390792Sgshapiro bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 23490792Sgshapiro lmap->ldap_secret, lmap->ldap_method); 23590792Sgshapiro 23690792Sgshapiro# if USE_LDAP_INIT 23790792Sgshapiro /* clear the event if it has not sprung */ 23890792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 23990792Sgshapiro# endif /* USE_LDAP_INIT */ 24090792Sgshapiro 24190792Sgshapiro if (bind_result != LDAP_SUCCESS) 24290792Sgshapiro { 24390792Sgshapiro errno = bind_result + E_LDAPBASE; 24490792Sgshapiro return false; 24590792Sgshapiro } 24690792Sgshapiro 24790792Sgshapiro /* Save PID to make sure only this PID closes the LDAP connection */ 24890792Sgshapiro lmap->ldap_pid = getpid(); 24990792Sgshapiro lmap->ldap_ld = ld; 25090792Sgshapiro return true; 25190792Sgshapiro} 25290792Sgshapiro 25390792Sgshapiro/* ARGSUSED */ 25490792Sgshapirostatic void 25590792Sgshapiroldaptimeout(unused) 25690792Sgshapiro int unused; 25790792Sgshapiro{ 25890792Sgshapiro /* 25990792Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 26090792Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 26190792Sgshapiro ** DOING. 26290792Sgshapiro */ 26390792Sgshapiro 26490792Sgshapiro errno = ETIMEDOUT; 26590792Sgshapiro longjmp(LDAPTimeout, 1); 26690792Sgshapiro} 26790792Sgshapiro 26890792Sgshapiro/* 269132943Sgshapiro** SM_LDAP_SEARCH -- initiate LDAP search 27090792Sgshapiro** 27190792Sgshapiro** Initiate an LDAP search, return the msgid. 27290792Sgshapiro** The calling function must collect the results. 27390792Sgshapiro** 27490792Sgshapiro** Parameters: 27590792Sgshapiro** lmap -- LDAP map information 27690792Sgshapiro** key -- key to substitute in LDAP filter 27790792Sgshapiro** 27890792Sgshapiro** Returns: 27990792Sgshapiro** -1 on failure, msgid on success 28090792Sgshapiro** 28190792Sgshapiro*/ 28290792Sgshapiro 28390792Sgshapiroint 28490792Sgshapirosm_ldap_search(lmap, key) 28590792Sgshapiro SM_LDAP_STRUCT *lmap; 28690792Sgshapiro char *key; 28790792Sgshapiro{ 28890792Sgshapiro int msgid; 28990792Sgshapiro char *fp, *p, *q; 29090792Sgshapiro char filter[LDAPMAP_MAX_FILTER + 1]; 29190792Sgshapiro 29290792Sgshapiro /* substitute key into filter, perhaps multiple times */ 29390792Sgshapiro memset(filter, '\0', sizeof filter); 29490792Sgshapiro fp = filter; 29590792Sgshapiro p = lmap->ldap_filter; 29690792Sgshapiro while ((q = strchr(p, '%')) != NULL) 29790792Sgshapiro { 29890792Sgshapiro if (q[1] == 's') 29990792Sgshapiro { 30090792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 30190792Sgshapiro "%.*s%s", (int) (q - p), p, key); 30290792Sgshapiro fp += strlen(fp); 30390792Sgshapiro p = q + 2; 30490792Sgshapiro } 30590792Sgshapiro else if (q[1] == '0') 30690792Sgshapiro { 30790792Sgshapiro char *k = key; 30890792Sgshapiro 30990792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 31090792Sgshapiro "%.*s", (int) (q - p), p); 31190792Sgshapiro fp += strlen(fp); 31290792Sgshapiro p = q + 2; 31390792Sgshapiro 31490792Sgshapiro /* Properly escape LDAP special characters */ 31590792Sgshapiro while (SPACELEFT(filter, fp) > 0 && 31690792Sgshapiro *k != '\0') 31790792Sgshapiro { 31890792Sgshapiro if (*k == '*' || *k == '(' || 31990792Sgshapiro *k == ')' || *k == '\\') 32090792Sgshapiro { 32190792Sgshapiro (void) sm_strlcat(fp, 32290792Sgshapiro (*k == '*' ? "\\2A" : 32390792Sgshapiro (*k == '(' ? "\\28" : 32490792Sgshapiro (*k == ')' ? "\\29" : 32590792Sgshapiro (*k == '\\' ? "\\5C" : 32690792Sgshapiro "\00")))), 32790792Sgshapiro SPACELEFT(filter, fp)); 32890792Sgshapiro fp += strlen(fp); 32990792Sgshapiro k++; 33090792Sgshapiro } 33190792Sgshapiro else 33290792Sgshapiro *fp++ = *k++; 33390792Sgshapiro } 33490792Sgshapiro } 33590792Sgshapiro else 33690792Sgshapiro { 33790792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 33890792Sgshapiro "%.*s", (int) (q - p + 1), p); 33990792Sgshapiro p = q + (q[1] == '%' ? 2 : 1); 34090792Sgshapiro fp += strlen(fp); 34190792Sgshapiro } 34290792Sgshapiro } 34390792Sgshapiro (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 34490792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 20)) 34590792Sgshapiro sm_dprintf("ldap search filter=%s\n", filter); 34690792Sgshapiro 34790792Sgshapiro lmap->ldap_res = NULL; 34894334Sgshapiro msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, 34994334Sgshapiro lmap->ldap_scope, filter, 35090792Sgshapiro (lmap->ldap_attr[0] == NULL ? NULL : 35190792Sgshapiro lmap->ldap_attr), 35290792Sgshapiro lmap->ldap_attrsonly); 35390792Sgshapiro return msgid; 35490792Sgshapiro} 35590792Sgshapiro 35690792Sgshapiro/* 35794334Sgshapiro** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a 35894334Sgshapiro** particular objectClass 35994334Sgshapiro** 36094334Sgshapiro** Parameters: 36194334Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 36294334Sgshapiro** entry -- current LDAP entry struct 36394334Sgshapiro** ocvalue -- particular objectclass in question. 36494334Sgshapiro** may be of form (fee|foo|fum) meaning 36594334Sgshapiro** any entry can be part of either fee, 36694334Sgshapiro** foo or fum objectclass 36794334Sgshapiro** 36894334Sgshapiro** Returns: 36994334Sgshapiro** true if item has that objectClass 37094334Sgshapiro*/ 37194334Sgshapiro 37294334Sgshapirostatic bool 37394334Sgshapirosm_ldap_has_objectclass(lmap, entry, ocvalue) 37494334Sgshapiro SM_LDAP_STRUCT *lmap; 37594334Sgshapiro LDAPMessage *entry; 37694334Sgshapiro char *ocvalue; 37794334Sgshapiro{ 37894334Sgshapiro char **vals = NULL; 37994334Sgshapiro int i; 38094334Sgshapiro 38194334Sgshapiro if (ocvalue == NULL) 38294334Sgshapiro return false; 38394334Sgshapiro 38494334Sgshapiro vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); 38594334Sgshapiro if (vals == NULL) 38694334Sgshapiro return false; 38794334Sgshapiro 38894334Sgshapiro for (i = 0; vals[i] != NULL; i++) 38994334Sgshapiro { 39094334Sgshapiro char *p; 39194334Sgshapiro char *q; 39294334Sgshapiro 39394334Sgshapiro p = q = ocvalue; 39494334Sgshapiro while (*p != '\0') 39594334Sgshapiro { 39694334Sgshapiro while (*p != '\0' && *p != '|') 39794334Sgshapiro p++; 39894334Sgshapiro 39994334Sgshapiro if ((p - q) == strlen(vals[i]) && 40094334Sgshapiro sm_strncasecmp(vals[i], q, p - q) == 0) 40194334Sgshapiro { 40294334Sgshapiro ldap_value_free(vals); 40394334Sgshapiro return true; 40494334Sgshapiro } 40594334Sgshapiro 40694334Sgshapiro while (*p == '|') 40794334Sgshapiro p++; 40894334Sgshapiro q = p; 40994334Sgshapiro } 41094334Sgshapiro } 41194334Sgshapiro 41294334Sgshapiro ldap_value_free(vals); 41394334Sgshapiro return false; 41494334Sgshapiro} 41594334Sgshapiro 41694334Sgshapiro/* 41790792Sgshapiro** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 41890792Sgshapiro** 41990792Sgshapiro** Parameters: 42090792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 42190792Sgshapiro** msgid -- msgid returned by sm_ldap_search() 42290792Sgshapiro** flags -- flags for the lookup 42390792Sgshapiro** delim -- delimiter for result concatenation 42490792Sgshapiro** rpool -- memory pool for storage 42590792Sgshapiro** result -- return string 42690792Sgshapiro** recurse -- recursion list 42790792Sgshapiro** 42890792Sgshapiro** Returns: 42990792Sgshapiro** status (sysexit) 43090792Sgshapiro*/ 43190792Sgshapiro 43294334Sgshapiro# define SM_LDAP_ERROR_CLEANUP() \ 43390792Sgshapiro{ \ 43490792Sgshapiro if (lmap->ldap_res != NULL) \ 43590792Sgshapiro { \ 43690792Sgshapiro ldap_msgfree(lmap->ldap_res); \ 43790792Sgshapiro lmap->ldap_res = NULL; \ 43890792Sgshapiro } \ 43990792Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); \ 44090792Sgshapiro} 44190792Sgshapiro 44294334Sgshapirostatic SM_LDAP_RECURSE_ENTRY * 44394334Sgshapirosm_ldap_add_recurse(top, item, type, rpool) 44490792Sgshapiro SM_LDAP_RECURSE_LIST **top; 44590792Sgshapiro char *item; 44690792Sgshapiro int type; 44790792Sgshapiro SM_RPOOL_T *rpool; 44890792Sgshapiro{ 44994334Sgshapiro int n; 45094334Sgshapiro int m; 45194334Sgshapiro int p; 45294334Sgshapiro int insertat; 45394334Sgshapiro int moveb; 45494334Sgshapiro int oldsizeb; 45594334Sgshapiro int rc; 45694334Sgshapiro SM_LDAP_RECURSE_ENTRY *newe; 45794334Sgshapiro SM_LDAP_RECURSE_ENTRY **olddata; 45890792Sgshapiro 45994334Sgshapiro /* 46094334Sgshapiro ** This code will maintain a list of 46194334Sgshapiro ** SM_LDAP_RECURSE_ENTRY structures 46294334Sgshapiro ** in ascending order. 46394334Sgshapiro */ 46494334Sgshapiro 46594334Sgshapiro if (*top == NULL) 46690792Sgshapiro { 46794334Sgshapiro /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ 46894334Sgshapiro *top = sm_rpool_malloc_x(rpool, sizeof **top); 46994334Sgshapiro (*top)->lr_cnt = 0; 47094334Sgshapiro (*top)->lr_size = 0; 47194334Sgshapiro (*top)->lr_data = NULL; 47294334Sgshapiro } 47394334Sgshapiro 47494334Sgshapiro if ((*top)->lr_cnt >= (*top)->lr_size) 47594334Sgshapiro { 47694334Sgshapiro /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ 47794334Sgshapiro olddata = (*top)->lr_data; 47894334Sgshapiro if ((*top)->lr_size == 0) 47990792Sgshapiro { 48094334Sgshapiro oldsizeb = 0; 48194334Sgshapiro (*top)->lr_size = 256; 48290792Sgshapiro } 48394334Sgshapiro else 48494334Sgshapiro { 48594334Sgshapiro oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); 48694334Sgshapiro (*top)->lr_size *= 2; 48794334Sgshapiro } 48894334Sgshapiro (*top)->lr_data = sm_rpool_malloc_x(rpool, 48994334Sgshapiro (*top)->lr_size * sizeof *((*top)->lr_data)); 49094334Sgshapiro if (oldsizeb > 0) 49194334Sgshapiro memcpy((*top)->lr_data, olddata, oldsizeb); 49290792Sgshapiro } 49390792Sgshapiro 49494334Sgshapiro /* 49594334Sgshapiro ** Binary search/insert item:type into list. 49694334Sgshapiro ** Return current entry pointer if already exists. 49794334Sgshapiro */ 49894334Sgshapiro 49994334Sgshapiro n = 0; 50094334Sgshapiro m = (*top)->lr_cnt - 1; 50194334Sgshapiro if (m < 0) 50294334Sgshapiro insertat = 0; 50390792Sgshapiro else 50494334Sgshapiro insertat = -1; 50594334Sgshapiro 50694334Sgshapiro while (insertat == -1) 50794334Sgshapiro { 50894334Sgshapiro p = (m + n) / 2; 50994334Sgshapiro 51094334Sgshapiro rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); 51194334Sgshapiro if (rc == 0) 51294334Sgshapiro rc = type - (*top)->lr_data[p]->lr_type; 51394334Sgshapiro 51494334Sgshapiro if (rc < 0) 51594334Sgshapiro m = p - 1; 51694334Sgshapiro else if (rc > 0) 51794334Sgshapiro n = p + 1; 51894334Sgshapiro else 51994334Sgshapiro return (*top)->lr_data[p]; 52094334Sgshapiro 52194334Sgshapiro if (m == -1) 52294334Sgshapiro insertat = 0; 52394334Sgshapiro else if (n >= (*top)->lr_cnt) 52494334Sgshapiro insertat = (*top)->lr_cnt; 52594334Sgshapiro else if (m < n) 52694334Sgshapiro insertat = m + 1; 52794334Sgshapiro } 52894334Sgshapiro 52994334Sgshapiro /* 53094334Sgshapiro ** Not found in list, make room 53194334Sgshapiro ** at insert point and add it. 53294334Sgshapiro */ 53394334Sgshapiro 53494334Sgshapiro newe = sm_rpool_malloc_x(rpool, sizeof *newe); 53594334Sgshapiro if (newe != NULL) 53694334Sgshapiro { 53794334Sgshapiro moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); 53894334Sgshapiro if (moveb > 0) 53994334Sgshapiro memmove(&((*top)->lr_data[insertat + 1]), 54094334Sgshapiro &((*top)->lr_data[insertat]), 54194334Sgshapiro moveb); 54294334Sgshapiro 54394334Sgshapiro newe->lr_search = sm_rpool_strdup_x(rpool, item); 54494334Sgshapiro newe->lr_type = type; 545132943Sgshapiro newe->lr_ludp = NULL; 546132943Sgshapiro newe->lr_attrs = NULL; 54794334Sgshapiro newe->lr_done = false; 54894334Sgshapiro 54994334Sgshapiro ((*top)->lr_data)[insertat] = newe; 55094334Sgshapiro (*top)->lr_cnt++; 55194334Sgshapiro } 55294334Sgshapiro return newe; 55390792Sgshapiro} 55490792Sgshapiro 55590792Sgshapiroint 55694334Sgshapirosm_ldap_results(lmap, msgid, flags, delim, rpool, result, 55794334Sgshapiro resultln, resultsz, recurse) 55890792Sgshapiro SM_LDAP_STRUCT *lmap; 55990792Sgshapiro int msgid; 56090792Sgshapiro int flags; 56194334Sgshapiro int delim; 56290792Sgshapiro SM_RPOOL_T *rpool; 56390792Sgshapiro char **result; 56494334Sgshapiro int *resultln; 56594334Sgshapiro int *resultsz; 56690792Sgshapiro SM_LDAP_RECURSE_LIST *recurse; 56790792Sgshapiro{ 56890792Sgshapiro bool toplevel; 56990792Sgshapiro int i; 57090792Sgshapiro int statp; 57190792Sgshapiro int vsize; 57290792Sgshapiro int ret; 57390792Sgshapiro int save_errno; 57490792Sgshapiro char *p; 57594334Sgshapiro SM_LDAP_RECURSE_ENTRY *rl; 57690792Sgshapiro 57790792Sgshapiro /* Are we the top top level of the search? */ 57890792Sgshapiro toplevel = (recurse == NULL); 57990792Sgshapiro 58090792Sgshapiro /* Get results */ 58190792Sgshapiro statp = EX_NOTFOUND; 58290792Sgshapiro while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 58390792Sgshapiro (lmap->ldap_timeout.tv_sec == 0 ? NULL : 58490792Sgshapiro &(lmap->ldap_timeout)), 58590792Sgshapiro &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 58690792Sgshapiro { 58790792Sgshapiro LDAPMessage *entry; 58890792Sgshapiro 58990792Sgshapiro /* If we don't want multiple values and we have one, break */ 59094334Sgshapiro if ((char) delim == '\0' && *result != NULL) 59190792Sgshapiro break; 59290792Sgshapiro 59390792Sgshapiro /* Cycle through all entries */ 59490792Sgshapiro for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 59590792Sgshapiro entry != NULL; 59690792Sgshapiro entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 59790792Sgshapiro { 59890792Sgshapiro BerElement *ber; 59990792Sgshapiro char *attr; 60090792Sgshapiro char **vals = NULL; 60190792Sgshapiro char *dn; 60290792Sgshapiro 60390792Sgshapiro /* 60490792Sgshapiro ** If matching only and found an entry, 60590792Sgshapiro ** no need to spin through attributes 60690792Sgshapiro */ 60790792Sgshapiro 608125820Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 609125820Sgshapiro { 610125820Sgshapiro statp = EX_OK; 61190792Sgshapiro continue; 612125820Sgshapiro } 61390792Sgshapiro 61490792Sgshapiro /* record completed DN's to prevent loops */ 61590792Sgshapiro dn = ldap_get_dn(lmap->ldap_ld, entry); 61690792Sgshapiro if (dn == NULL) 61790792Sgshapiro { 61890792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 61990792Sgshapiro save_errno += E_LDAPBASE; 62094334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 62190792Sgshapiro errno = save_errno; 622120256Sgshapiro return EX_TEMPFAIL; 62390792Sgshapiro } 62490792Sgshapiro 62594334Sgshapiro rl = sm_ldap_add_recurse(&recurse, dn, 62694334Sgshapiro SM_LDAP_ATTR_DN, 62794334Sgshapiro rpool); 62894334Sgshapiro 62994334Sgshapiro if (rl == NULL) 63090792Sgshapiro { 63190792Sgshapiro ldap_memfree(dn); 63294334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 63390792Sgshapiro errno = ENOMEM; 63490792Sgshapiro return EX_OSERR; 63594334Sgshapiro } 63694334Sgshapiro else if (rl->lr_done) 63794334Sgshapiro { 63890792Sgshapiro /* already on list, skip it */ 63990792Sgshapiro ldap_memfree(dn); 64090792Sgshapiro continue; 64190792Sgshapiro } 64290792Sgshapiro ldap_memfree(dn); 64390792Sgshapiro 64490792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 64590792Sgshapiro /* 64690792Sgshapiro ** Reset value to prevent lingering 64790792Sgshapiro ** LDAP_DECODING_ERROR due to 64890792Sgshapiro ** OpenLDAP 1.X's hack (see below) 64990792Sgshapiro */ 65090792Sgshapiro 65190792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 65290792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 65390792Sgshapiro 65490792Sgshapiro for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 65590792Sgshapiro &ber); 65690792Sgshapiro attr != NULL; 65790792Sgshapiro attr = ldap_next_attribute(lmap->ldap_ld, entry, 65890792Sgshapiro ber)) 65990792Sgshapiro { 66090792Sgshapiro char *tmp, *vp_tmp; 66190792Sgshapiro int type; 66294334Sgshapiro char *needobjclass = NULL; 66390792Sgshapiro 66494334Sgshapiro type = SM_LDAP_ATTR_NONE; 66590792Sgshapiro for (i = 0; lmap->ldap_attr[i] != NULL; i++) 66690792Sgshapiro { 66790792Sgshapiro if (sm_strcasecmp(lmap->ldap_attr[i], 66890792Sgshapiro attr) == 0) 66990792Sgshapiro { 67090792Sgshapiro type = lmap->ldap_attr_type[i]; 67194334Sgshapiro needobjclass = lmap->ldap_attr_needobjclass[i]; 67290792Sgshapiro break; 67390792Sgshapiro } 67490792Sgshapiro } 67594334Sgshapiro 67694334Sgshapiro if (bitset(SM_LDAP_USE_ALLATTR, flags) && 67794334Sgshapiro type == SM_LDAP_ATTR_NONE) 67890792Sgshapiro { 67994334Sgshapiro /* URL lookups specify attrs to use */ 68094334Sgshapiro type = SM_LDAP_ATTR_NORMAL; 68194334Sgshapiro needobjclass = NULL; 68294334Sgshapiro } 68394334Sgshapiro 68494334Sgshapiro if (type == SM_LDAP_ATTR_NONE) 68594334Sgshapiro { 68690792Sgshapiro /* attribute not requested */ 68790792Sgshapiro ldap_memfree(attr); 68894334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 68990792Sgshapiro errno = EFAULT; 69090792Sgshapiro return EX_SOFTWARE; 69190792Sgshapiro } 69290792Sgshapiro 69394334Sgshapiro /* 69494334Sgshapiro ** For recursion on a particular attribute, 69594334Sgshapiro ** we may need to see if this entry is 69694334Sgshapiro ** part of a particular objectclass. 69794334Sgshapiro ** Also, ignore objectClass attribute. 69894334Sgshapiro ** Otherwise we just ignore this attribute. 69994334Sgshapiro */ 70094334Sgshapiro 70194334Sgshapiro if (type == SM_LDAP_ATTR_OBJCLASS || 70294334Sgshapiro (needobjclass != NULL && 70394334Sgshapiro !sm_ldap_has_objectclass(lmap, entry, 70494334Sgshapiro needobjclass))) 70594334Sgshapiro { 70694334Sgshapiro ldap_memfree(attr); 70794334Sgshapiro continue; 70894334Sgshapiro } 70994334Sgshapiro 71090792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 71190792Sgshapiro { 71290792Sgshapiro vals = ldap_get_values(lmap->ldap_ld, 71390792Sgshapiro entry, 71490792Sgshapiro attr); 71590792Sgshapiro if (vals == NULL) 71690792Sgshapiro { 71790792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 71890792Sgshapiro if (save_errno == LDAP_SUCCESS) 71990792Sgshapiro { 72090792Sgshapiro ldap_memfree(attr); 72190792Sgshapiro continue; 72290792Sgshapiro } 72390792Sgshapiro 72490792Sgshapiro /* Must be an error */ 72590792Sgshapiro save_errno += E_LDAPBASE; 72690792Sgshapiro ldap_memfree(attr); 72794334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 72890792Sgshapiro errno = save_errno; 72990792Sgshapiro return EX_TEMPFAIL; 73090792Sgshapiro } 73190792Sgshapiro } 73290792Sgshapiro 73390792Sgshapiro statp = EX_OK; 73490792Sgshapiro 73590792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 73690792Sgshapiro /* 73790792Sgshapiro ** Reset value to prevent lingering 73890792Sgshapiro ** LDAP_DECODING_ERROR due to 73990792Sgshapiro ** OpenLDAP 1.X's hack (see below) 74090792Sgshapiro */ 74190792Sgshapiro 74290792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 74390792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 74490792Sgshapiro 74590792Sgshapiro /* 74690792Sgshapiro ** If matching only, 74790792Sgshapiro ** no need to spin through entries 74890792Sgshapiro */ 74990792Sgshapiro 75090792Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 75190792Sgshapiro { 75290792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 75390792Sgshapiro ldap_value_free(vals); 75490792Sgshapiro ldap_memfree(attr); 75590792Sgshapiro continue; 75690792Sgshapiro } 75790792Sgshapiro 75890792Sgshapiro /* 75990792Sgshapiro ** If we don't want multiple values, 76090792Sgshapiro ** return first found. 76190792Sgshapiro */ 76290792Sgshapiro 76394334Sgshapiro if ((char) delim == '\0') 76490792Sgshapiro { 76594334Sgshapiro if (*result != NULL) 76694334Sgshapiro { 76794334Sgshapiro /* already have a value */ 76894334Sgshapiro break; 76994334Sgshapiro } 77094334Sgshapiro 77194334Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 77294334Sgshapiro flags) && 77394334Sgshapiro *result != NULL) 77494334Sgshapiro { 77594334Sgshapiro /* only wanted one match */ 77694334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 77794334Sgshapiro errno = ENOENT; 77894334Sgshapiro return EX_NOTFOUND; 77994334Sgshapiro } 78094334Sgshapiro 78190792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 78290792Sgshapiro { 78390792Sgshapiro *result = sm_rpool_strdup_x(rpool, 78490792Sgshapiro attr); 78590792Sgshapiro ldap_memfree(attr); 78690792Sgshapiro break; 78790792Sgshapiro } 78890792Sgshapiro 78990792Sgshapiro if (vals[0] == NULL) 79090792Sgshapiro { 79190792Sgshapiro ldap_value_free(vals); 79290792Sgshapiro ldap_memfree(attr); 79390792Sgshapiro continue; 79490792Sgshapiro } 79590792Sgshapiro 79690792Sgshapiro vsize = strlen(vals[0]) + 1; 79790792Sgshapiro if (lmap->ldap_attrsep != '\0') 79890792Sgshapiro vsize += strlen(attr) + 1; 79990792Sgshapiro *result = sm_rpool_malloc_x(rpool, 80090792Sgshapiro vsize); 80190792Sgshapiro if (lmap->ldap_attrsep != '\0') 80290792Sgshapiro sm_snprintf(*result, vsize, 80390792Sgshapiro "%s%c%s", 80490792Sgshapiro attr, 80590792Sgshapiro lmap->ldap_attrsep, 80690792Sgshapiro vals[0]); 80790792Sgshapiro else 80890792Sgshapiro sm_strlcpy(*result, vals[0], 80990792Sgshapiro vsize); 81090792Sgshapiro ldap_value_free(vals); 81190792Sgshapiro ldap_memfree(attr); 81290792Sgshapiro break; 81390792Sgshapiro } 81490792Sgshapiro 81590792Sgshapiro /* attributes only */ 81690792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 81790792Sgshapiro { 81890792Sgshapiro if (*result == NULL) 81990792Sgshapiro *result = sm_rpool_strdup_x(rpool, 82090792Sgshapiro attr); 82190792Sgshapiro else 82290792Sgshapiro { 82394334Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 82494334Sgshapiro flags) && 82594334Sgshapiro *result != NULL) 82694334Sgshapiro { 82794334Sgshapiro /* only wanted one match */ 82894334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 82994334Sgshapiro errno = ENOENT; 83094334Sgshapiro return EX_NOTFOUND; 83194334Sgshapiro } 83294334Sgshapiro 83390792Sgshapiro vsize = strlen(*result) + 83490792Sgshapiro strlen(attr) + 2; 83590792Sgshapiro tmp = sm_rpool_malloc_x(rpool, 83690792Sgshapiro vsize); 83790792Sgshapiro (void) sm_snprintf(tmp, 83890792Sgshapiro vsize, "%s%c%s", 83994334Sgshapiro *result, (char) delim, 84090792Sgshapiro attr); 84190792Sgshapiro *result = tmp; 84290792Sgshapiro } 84390792Sgshapiro ldap_memfree(attr); 84490792Sgshapiro continue; 84590792Sgshapiro } 84690792Sgshapiro 84790792Sgshapiro /* 84894334Sgshapiro ** If there is more than one, munge then 84994334Sgshapiro ** into a map_coldelim separated string. 85094334Sgshapiro ** If we are recursing we may have an entry 85194334Sgshapiro ** with no 'normal' values to put in the 85294334Sgshapiro ** string. 85394334Sgshapiro ** This is not an error. 85490792Sgshapiro */ 85590792Sgshapiro 85694334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && 85794334Sgshapiro bitset(SM_LDAP_SINGLEMATCH, flags) && 85894334Sgshapiro *result != NULL) 85994334Sgshapiro { 86094334Sgshapiro /* only wanted one match */ 86194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 86294334Sgshapiro errno = ENOENT; 86394334Sgshapiro return EX_NOTFOUND; 86494334Sgshapiro } 86594334Sgshapiro 86690792Sgshapiro vsize = 0; 86790792Sgshapiro for (i = 0; vals[i] != NULL; i++) 86890792Sgshapiro { 86994334Sgshapiro if (type == SM_LDAP_ATTR_DN || 87094334Sgshapiro type == SM_LDAP_ATTR_FILTER || 87194334Sgshapiro type == SM_LDAP_ATTR_URL) 87290792Sgshapiro { 87394334Sgshapiro /* add to recursion */ 87494334Sgshapiro if (sm_ldap_add_recurse(&recurse, 87590792Sgshapiro vals[i], 87694334Sgshapiro type, 87794334Sgshapiro rpool) == NULL) 87890792Sgshapiro { 87994334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 88090792Sgshapiro errno = ENOMEM; 88190792Sgshapiro return EX_OSERR; 88290792Sgshapiro } 88390792Sgshapiro continue; 88490792Sgshapiro } 88594334Sgshapiro 88690792Sgshapiro vsize += strlen(vals[i]) + 1; 88790792Sgshapiro if (lmap->ldap_attrsep != '\0') 88890792Sgshapiro vsize += strlen(attr) + 1; 88990792Sgshapiro } 89090792Sgshapiro 89194334Sgshapiro /* 89294334Sgshapiro ** Create/Append to string any normal 89394334Sgshapiro ** attribute values. Otherwise, just free 89494334Sgshapiro ** memory and move on to the next 89594334Sgshapiro ** attribute in this entry. 89694334Sgshapiro */ 89794334Sgshapiro 89894334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) 89990792Sgshapiro { 90094334Sgshapiro char *pe; 90194334Sgshapiro 90294334Sgshapiro /* Grow result string if needed */ 90394334Sgshapiro if ((*resultln + vsize) >= *resultsz) 90490792Sgshapiro { 90594334Sgshapiro while ((*resultln + vsize) >= *resultsz) 90694334Sgshapiro { 90794334Sgshapiro if (*resultsz == 0) 90894334Sgshapiro *resultsz = 1024; 90994334Sgshapiro else 91094334Sgshapiro *resultsz *= 2; 91194334Sgshapiro } 91294334Sgshapiro 91394334Sgshapiro vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); 91494334Sgshapiro *vp_tmp = '\0'; 91594334Sgshapiro 91694334Sgshapiro if (*result != NULL) 91794334Sgshapiro sm_strlcpy(vp_tmp, 91894334Sgshapiro *result, 91994334Sgshapiro *resultsz); 92094334Sgshapiro *result = vp_tmp; 92190792Sgshapiro } 92294334Sgshapiro 92394334Sgshapiro p = *result + *resultln; 92494334Sgshapiro pe = *result + *resultsz; 92594334Sgshapiro 92694334Sgshapiro for (i = 0; vals[i] != NULL; i++) 92790792Sgshapiro { 928102528Sgshapiro if (*resultln > 0 && 929102528Sgshapiro p < pe) 93094334Sgshapiro *p++ = (char) delim; 93194334Sgshapiro 93294334Sgshapiro if (lmap->ldap_attrsep != '\0') 93394334Sgshapiro { 93494334Sgshapiro p += sm_strlcpy(p, attr, 93594334Sgshapiro pe - p); 93694334Sgshapiro if (p < pe) 93794334Sgshapiro *p++ = lmap->ldap_attrsep; 93894334Sgshapiro } 93994334Sgshapiro 94094334Sgshapiro p += sm_strlcpy(p, vals[i], 94194334Sgshapiro pe - p); 94294334Sgshapiro *resultln = p - (*result); 94394334Sgshapiro if (p >= pe) 94494334Sgshapiro { 94594334Sgshapiro /* Internal error: buffer too small for LDAP values */ 94694334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 94794334Sgshapiro errno = ENOMEM; 94894334Sgshapiro return EX_OSERR; 94994334Sgshapiro } 95090792Sgshapiro } 95190792Sgshapiro } 95290792Sgshapiro 95390792Sgshapiro ldap_value_free(vals); 95490792Sgshapiro ldap_memfree(attr); 95590792Sgshapiro } 95690792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 95790792Sgshapiro 95890792Sgshapiro /* 95990792Sgshapiro ** We check save_errno != LDAP_DECODING_ERROR since 96090792Sgshapiro ** OpenLDAP 1.X has a very ugly *undocumented* 96190792Sgshapiro ** hack of returning this error code from 96290792Sgshapiro ** ldap_next_attribute() if the library freed the 96390792Sgshapiro ** ber attribute. See: 96490792Sgshapiro ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 96590792Sgshapiro */ 96690792Sgshapiro 96790792Sgshapiro if (save_errno != LDAP_SUCCESS && 96890792Sgshapiro save_errno != LDAP_DECODING_ERROR) 96990792Sgshapiro { 97090792Sgshapiro /* Must be an error */ 97190792Sgshapiro save_errno += E_LDAPBASE; 97294334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 97390792Sgshapiro errno = save_errno; 97490792Sgshapiro return EX_TEMPFAIL; 97590792Sgshapiro } 97690792Sgshapiro 97794334Sgshapiro /* mark this DN as done */ 97894334Sgshapiro rl->lr_done = true; 979132943Sgshapiro if (rl->lr_ludp != NULL) 980132943Sgshapiro { 981132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 982132943Sgshapiro rl->lr_ludp = NULL; 983132943Sgshapiro } 984132943Sgshapiro if (rl->lr_attrs != NULL) 985132943Sgshapiro { 986132943Sgshapiro free(rl->lr_attrs); 987132943Sgshapiro rl->lr_attrs = NULL; 988132943Sgshapiro } 98994334Sgshapiro 99090792Sgshapiro /* We don't want multiple values and we have one */ 99194334Sgshapiro if ((char) delim == '\0' && *result != NULL) 99290792Sgshapiro break; 99390792Sgshapiro } 99490792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 99590792Sgshapiro if (save_errno != LDAP_SUCCESS && 99690792Sgshapiro save_errno != LDAP_DECODING_ERROR) 99790792Sgshapiro { 99890792Sgshapiro /* Must be an error */ 99990792Sgshapiro save_errno += E_LDAPBASE; 100094334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 100190792Sgshapiro errno = save_errno; 100290792Sgshapiro return EX_TEMPFAIL; 100390792Sgshapiro } 100490792Sgshapiro ldap_msgfree(lmap->ldap_res); 100590792Sgshapiro lmap->ldap_res = NULL; 100690792Sgshapiro } 100790792Sgshapiro 100890792Sgshapiro if (ret == 0) 100990792Sgshapiro save_errno = ETIMEDOUT; 101090792Sgshapiro else 101190792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 101290792Sgshapiro if (save_errno != LDAP_SUCCESS) 101390792Sgshapiro { 101490792Sgshapiro statp = EX_TEMPFAIL; 101590792Sgshapiro if (ret != 0) 101690792Sgshapiro { 101790792Sgshapiro switch (save_errno) 101890792Sgshapiro { 101990792Sgshapiro#ifdef LDAP_SERVER_DOWN 102090792Sgshapiro case LDAP_SERVER_DOWN: 102190792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 102290792Sgshapiro case LDAP_TIMEOUT: 102390792Sgshapiro case LDAP_UNAVAILABLE: 102494334Sgshapiro 102594334Sgshapiro /* 102694334Sgshapiro ** server disappeared, 102794334Sgshapiro ** try reopen on next search 102894334Sgshapiro */ 102994334Sgshapiro 103090792Sgshapiro statp = EX_RESTART; 103190792Sgshapiro break; 103290792Sgshapiro } 103390792Sgshapiro save_errno += E_LDAPBASE; 103490792Sgshapiro } 103594334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 103690792Sgshapiro errno = save_errno; 103790792Sgshapiro return statp; 103890792Sgshapiro } 103990792Sgshapiro 104090792Sgshapiro if (lmap->ldap_res != NULL) 104190792Sgshapiro { 104290792Sgshapiro ldap_msgfree(lmap->ldap_res); 104390792Sgshapiro lmap->ldap_res = NULL; 104490792Sgshapiro } 104590792Sgshapiro 104690792Sgshapiro if (toplevel) 104790792Sgshapiro { 104894334Sgshapiro int rlidx; 104990792Sgshapiro 105090792Sgshapiro /* 105190792Sgshapiro ** Spin through the built-up recurse list at the top 105290792Sgshapiro ** of the recursion. Since new items are added at the 105390792Sgshapiro ** end of the shared list, we actually only ever get 105490792Sgshapiro ** one level of recursion before things pop back to the 105590792Sgshapiro ** top. Any items added to the list during that recursion 105690792Sgshapiro ** will be expanded by the top level. 105790792Sgshapiro */ 105890792Sgshapiro 105994334Sgshapiro for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++) 106090792Sgshapiro { 106194334Sgshapiro int newflags; 106290792Sgshapiro int sid; 106390792Sgshapiro int status; 106490792Sgshapiro 106594334Sgshapiro rl = recurse->lr_data[rlidx]; 106694334Sgshapiro 106794334Sgshapiro newflags = flags; 106894334Sgshapiro if (rl->lr_done) 106990792Sgshapiro { 107090792Sgshapiro /* already expanded */ 107190792Sgshapiro continue; 107290792Sgshapiro } 107394334Sgshapiro 107494334Sgshapiro if (rl->lr_type == SM_LDAP_ATTR_DN) 107590792Sgshapiro { 107690792Sgshapiro /* do DN search */ 107790792Sgshapiro sid = ldap_search(lmap->ldap_ld, 107890792Sgshapiro rl->lr_search, 107990792Sgshapiro lmap->ldap_scope, 108090792Sgshapiro "(objectClass=*)", 108194334Sgshapiro (lmap->ldap_attr[0] == NULL ? 108294334Sgshapiro NULL : lmap->ldap_attr), 108390792Sgshapiro lmap->ldap_attrsonly); 108490792Sgshapiro } 108594334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_FILTER) 108690792Sgshapiro { 108790792Sgshapiro /* do new search */ 108890792Sgshapiro sid = ldap_search(lmap->ldap_ld, 108990792Sgshapiro lmap->ldap_base, 109090792Sgshapiro lmap->ldap_scope, 109190792Sgshapiro rl->lr_search, 109294334Sgshapiro (lmap->ldap_attr[0] == NULL ? 109394334Sgshapiro NULL : lmap->ldap_attr), 109490792Sgshapiro lmap->ldap_attrsonly); 109590792Sgshapiro } 109694334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_URL) 109790792Sgshapiro { 1098132943Sgshapiro /* Parse URL */ 1099132943Sgshapiro sid = ldap_url_parse(rl->lr_search, 1100132943Sgshapiro &rl->lr_ludp); 1101132943Sgshapiro 1102132943Sgshapiro if (sid != 0) 1103132943Sgshapiro { 1104132943Sgshapiro errno = sid + E_LDAPURLBASE; 1105132943Sgshapiro return EX_TEMPFAIL; 1106132943Sgshapiro } 1107132943Sgshapiro 1108132943Sgshapiro /* We need to add objectClass */ 1109132943Sgshapiro if (rl->lr_ludp->lud_attrs != NULL) 1110132943Sgshapiro { 1111132943Sgshapiro int attrnum = 0; 1112132943Sgshapiro 1113132943Sgshapiro while (rl->lr_ludp->lud_attrs[attrnum] != NULL) 1114132943Sgshapiro { 1115132943Sgshapiro if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum], 1116132943Sgshapiro "objectClass") == 0) 1117132943Sgshapiro { 1118132943Sgshapiro /* already requested */ 1119132943Sgshapiro attrnum = -1; 1120132943Sgshapiro break; 1121132943Sgshapiro } 1122132943Sgshapiro attrnum++; 1123132943Sgshapiro } 1124132943Sgshapiro 1125132943Sgshapiro if (attrnum >= 0) 1126132943Sgshapiro { 1127132943Sgshapiro int i; 1128132943Sgshapiro 1129132943Sgshapiro rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2)); 1130132943Sgshapiro if (rl->lr_attrs == NULL) 1131132943Sgshapiro { 1132132943Sgshapiro save_errno = errno; 1133132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 1134132943Sgshapiro errno = save_errno; 1135132943Sgshapiro return EX_TEMPFAIL; 1136132943Sgshapiro } 1137132943Sgshapiro for (i = 0 ; i < attrnum; i++) 1138132943Sgshapiro { 1139132943Sgshapiro rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i]; 1140132943Sgshapiro } 1141132943Sgshapiro rl->lr_attrs[i++] = "objectClass"; 1142132943Sgshapiro rl->lr_attrs[i++] = NULL; 1143132943Sgshapiro } 1144132943Sgshapiro } 1145132943Sgshapiro 1146132943Sgshapiro /* 1147132943Sgshapiro ** Use the existing connection 1148132943Sgshapiro ** for this search. It really 1149132943Sgshapiro ** should use lud_scheme://lud_host:lud_port/ 1150132943Sgshapiro ** instead but that would require 1151132943Sgshapiro ** opening a new connection. 1152132943Sgshapiro ** This should be fixed ASAP. 1153132943Sgshapiro */ 1154132943Sgshapiro 1155132943Sgshapiro sid = ldap_search(lmap->ldap_ld, 1156132943Sgshapiro rl->lr_ludp->lud_dn, 1157132943Sgshapiro rl->lr_ludp->lud_scope, 1158132943Sgshapiro rl->lr_ludp->lud_filter, 1159132943Sgshapiro rl->lr_attrs, 1160132943Sgshapiro lmap->ldap_attrsonly); 1161132943Sgshapiro 1162132943Sgshapiro /* Use the attributes specified by URL */ 116394334Sgshapiro newflags |= SM_LDAP_USE_ALLATTR; 116490792Sgshapiro } 116590792Sgshapiro else 116690792Sgshapiro { 116790792Sgshapiro /* unknown or illegal attribute type */ 116890792Sgshapiro errno = EFAULT; 116990792Sgshapiro return EX_SOFTWARE; 117090792Sgshapiro } 117190792Sgshapiro 117290792Sgshapiro /* Collect results */ 117390792Sgshapiro if (sid == -1) 117490792Sgshapiro { 117590792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 117690792Sgshapiro statp = EX_TEMPFAIL; 117790792Sgshapiro switch (save_errno) 117890792Sgshapiro { 117990792Sgshapiro#ifdef LDAP_SERVER_DOWN 118090792Sgshapiro case LDAP_SERVER_DOWN: 118190792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 118290792Sgshapiro case LDAP_TIMEOUT: 118390792Sgshapiro case LDAP_UNAVAILABLE: 118494334Sgshapiro 118594334Sgshapiro /* 118694334Sgshapiro ** server disappeared, 118794334Sgshapiro ** try reopen on next search 118894334Sgshapiro */ 118994334Sgshapiro 119090792Sgshapiro statp = EX_RESTART; 119190792Sgshapiro break; 119290792Sgshapiro } 119390792Sgshapiro errno = save_errno + E_LDAPBASE; 119490792Sgshapiro return statp; 119590792Sgshapiro } 119690792Sgshapiro 119794334Sgshapiro status = sm_ldap_results(lmap, sid, newflags, delim, 119894334Sgshapiro rpool, result, resultln, 119994334Sgshapiro resultsz, recurse); 120090792Sgshapiro save_errno = errno; 120190792Sgshapiro if (status != EX_OK && status != EX_NOTFOUND) 120290792Sgshapiro { 120390792Sgshapiro errno = save_errno; 120490792Sgshapiro return status; 120590792Sgshapiro } 120690792Sgshapiro 120790792Sgshapiro /* Mark as done */ 120894334Sgshapiro rl->lr_done = true; 1209132943Sgshapiro if (rl->lr_ludp != NULL) 1210132943Sgshapiro { 1211132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 1212132943Sgshapiro rl->lr_ludp = NULL; 1213132943Sgshapiro } 1214132943Sgshapiro if (rl->lr_attrs != NULL) 1215132943Sgshapiro { 1216132943Sgshapiro free(rl->lr_attrs); 1217132943Sgshapiro rl->lr_attrs = NULL; 1218132943Sgshapiro } 121994334Sgshapiro 122094334Sgshapiro /* Reset rlidx as new items may have been added */ 122194334Sgshapiro rlidx = -1; 122290792Sgshapiro } 122390792Sgshapiro } 122490792Sgshapiro return statp; 122590792Sgshapiro} 122690792Sgshapiro 122790792Sgshapiro/* 122890792Sgshapiro** SM_LDAP_CLOSE -- close LDAP connection 122990792Sgshapiro** 123090792Sgshapiro** Parameters: 123190792Sgshapiro** lmap -- LDAP map information 123290792Sgshapiro** 123390792Sgshapiro** Returns: 123490792Sgshapiro** None. 123590792Sgshapiro** 123690792Sgshapiro*/ 123790792Sgshapiro 123890792Sgshapirovoid 123990792Sgshapirosm_ldap_close(lmap) 124090792Sgshapiro SM_LDAP_STRUCT *lmap; 124190792Sgshapiro{ 124290792Sgshapiro if (lmap->ldap_ld == NULL) 124390792Sgshapiro return; 124490792Sgshapiro 124590792Sgshapiro if (lmap->ldap_pid == getpid()) 124690792Sgshapiro ldap_unbind(lmap->ldap_ld); 124790792Sgshapiro lmap->ldap_ld = NULL; 124890792Sgshapiro lmap->ldap_pid = 0; 124990792Sgshapiro} 125090792Sgshapiro 125190792Sgshapiro/* 125290792Sgshapiro** SM_LDAP_SETOPTS -- set LDAP options 125390792Sgshapiro** 125490792Sgshapiro** Parameters: 125590792Sgshapiro** ld -- LDAP session handle 125690792Sgshapiro** lmap -- LDAP map information 125790792Sgshapiro** 125890792Sgshapiro** Returns: 125990792Sgshapiro** None. 126090792Sgshapiro** 126190792Sgshapiro*/ 126290792Sgshapiro 126390792Sgshapirovoid 126490792Sgshapirosm_ldap_setopts(ld, lmap) 126590792Sgshapiro LDAP *ld; 126690792Sgshapiro SM_LDAP_STRUCT *lmap; 126790792Sgshapiro{ 126890792Sgshapiro# if USE_LDAP_SET_OPTION 126994334Sgshapiro if (lmap->ldap_version != 0) 127094334Sgshapiro { 127194334Sgshapiro ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 127294334Sgshapiro &lmap->ldap_version); 127394334Sgshapiro } 127490792Sgshapiro ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 127590792Sgshapiro if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 127690792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 127790792Sgshapiro else 127890792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 127990792Sgshapiro ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 128090792Sgshapiro ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 1281102528Sgshapiro# ifdef LDAP_OPT_RESTART 1282102528Sgshapiro ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1283102528Sgshapiro# endif /* LDAP_OPT_RESTART */ 128490792Sgshapiro# else /* USE_LDAP_SET_OPTION */ 128590792Sgshapiro /* From here on in we can use ldap internal timelimits */ 128690792Sgshapiro ld->ld_deref = lmap->ldap_deref; 128790792Sgshapiro ld->ld_options = lmap->ldap_options; 128890792Sgshapiro ld->ld_sizelimit = lmap->ldap_sizelimit; 128990792Sgshapiro ld->ld_timelimit = lmap->ldap_timelimit; 129090792Sgshapiro# endif /* USE_LDAP_SET_OPTION */ 129190792Sgshapiro} 129290792Sgshapiro 129390792Sgshapiro/* 129490792Sgshapiro** SM_LDAP_GETERRNO -- get ldap errno value 129590792Sgshapiro** 129690792Sgshapiro** Parameters: 129790792Sgshapiro** ld -- LDAP session handle 129890792Sgshapiro** 129990792Sgshapiro** Returns: 130090792Sgshapiro** LDAP errno. 130190792Sgshapiro** 130290792Sgshapiro*/ 130390792Sgshapiro 130490792Sgshapiroint 130590792Sgshapirosm_ldap_geterrno(ld) 130690792Sgshapiro LDAP *ld; 130790792Sgshapiro{ 130890792Sgshapiro int err = LDAP_SUCCESS; 130990792Sgshapiro 131090792Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 131190792Sgshapiro (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 131290792Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 131390792Sgshapiro# ifdef LDAP_OPT_SIZELIMIT 131490792Sgshapiro err = ldap_get_lderrno(ld, NULL, NULL); 131590792Sgshapiro# else /* LDAP_OPT_SIZELIMIT */ 131690792Sgshapiro err = ld->ld_errno; 131790792Sgshapiro 131890792Sgshapiro /* 131990792Sgshapiro ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 132090792Sgshapiro ** OpenLDAP 1.X's hack (see above) 132190792Sgshapiro */ 132290792Sgshapiro 132390792Sgshapiro ld->ld_errno = LDAP_SUCCESS; 132490792Sgshapiro# endif /* LDAP_OPT_SIZELIMIT */ 132590792Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 132690792Sgshapiro return err; 132790792Sgshapiro} 132890792Sgshapiro# endif /* LDAPMAP */ 1329