190792Sgshapiro/* 2261370Sgshapiro * Copyright (c) 2001-2009 Proofpoint, 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 10168515Sgshapiro/* some "deprecated" calls are used, e.g., ldap_get_values() */ 11168515Sgshapiro#define LDAP_DEPRECATED 1 12168515Sgshapiro 1390792Sgshapiro#include <sm/gen.h> 14266711SgshapiroSM_RCSID("@(#)$Id: ldap.c,v 1.86 2013-11-22 20:51:43 ca Exp $") 1590792Sgshapiro 1690792Sgshapiro#if LDAPMAP 1790792Sgshapiro# include <sys/types.h> 1890792Sgshapiro# include <errno.h> 1990792Sgshapiro# include <setjmp.h> 2090792Sgshapiro# include <stdlib.h> 2190792Sgshapiro# include <unistd.h> 2290792Sgshapiro 2390792Sgshapiro# include <sm/bitops.h> 2490792Sgshapiro# include <sm/clock.h> 2590792Sgshapiro# include <sm/conf.h> 2690792Sgshapiro# include <sm/debug.h> 2790792Sgshapiro# include <sm/errstring.h> 2890792Sgshapiro# include <sm/ldap.h> 2990792Sgshapiro# include <sm/string.h> 3094334Sgshapiro# ifdef EX_OK 3194334Sgshapiro# undef EX_OK /* for SVr4.2 SMP */ 3294334Sgshapiro# endif /* EX_OK */ 3390792Sgshapiro# include <sm/sysexits.h> 3490792Sgshapiro 3590792SgshapiroSM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", 3690792Sgshapiro "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); 3790792Sgshapiro 3890792Sgshapirostatic void ldaptimeout __P((int)); 39141858Sgshapirostatic bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *)); 40141858Sgshapirostatic SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *)); 4190792Sgshapiro 4290792Sgshapiro/* 4390792Sgshapiro** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT 4490792Sgshapiro** 4590792Sgshapiro** Parameters: 4690792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT to clear 4790792Sgshapiro** 4890792Sgshapiro** Returns: 4990792Sgshapiro** None. 5090792Sgshapiro** 5190792Sgshapiro*/ 5290792Sgshapiro 53157001Sgshapiro#if _FFR_LDAP_VERSION 54157001Sgshapiro# if defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX 55157001Sgshapiro ERROR FFR_LDAP_VERSION > _LDAP_VERSION_MAX 56157001Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX */ 57157001Sgshapiro# if defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN 58157001Sgshapiro ERROR FFR_LDAP_VERSION < _LDAP_VERSION_MIN 59157001Sgshapiro# endif /* defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN */ 60157001Sgshapiro# define SM_LDAP_VERSION_DEFAULT _FFR_LDAP_VERSION 61157001Sgshapiro#else /* _FFR_LDAP_VERSION */ 62157001Sgshapiro# define SM_LDAP_VERSION_DEFAULT 0 63157001Sgshapiro#endif /* _FFR_LDAP_VERSION */ 64157001Sgshapiro 6590792Sgshapirovoid 6690792Sgshapirosm_ldap_clear(lmap) 6790792Sgshapiro SM_LDAP_STRUCT *lmap; 6890792Sgshapiro{ 6990792Sgshapiro if (lmap == NULL) 7090792Sgshapiro return; 7190792Sgshapiro 72132943Sgshapiro lmap->ldap_host = NULL; 7390792Sgshapiro lmap->ldap_port = LDAP_PORT; 74132943Sgshapiro lmap->ldap_uri = NULL; 75157001Sgshapiro lmap->ldap_version = SM_LDAP_VERSION_DEFAULT; 7690792Sgshapiro lmap->ldap_deref = LDAP_DEREF_NEVER; 7790792Sgshapiro lmap->ldap_timelimit = LDAP_NO_LIMIT; 7890792Sgshapiro lmap->ldap_sizelimit = LDAP_NO_LIMIT; 7990792Sgshapiro# ifdef LDAP_REFERRALS 8090792Sgshapiro lmap->ldap_options = LDAP_OPT_REFERRALS; 8190792Sgshapiro# else /* LDAP_REFERRALS */ 8290792Sgshapiro lmap->ldap_options = 0; 8390792Sgshapiro# endif /* LDAP_REFERRALS */ 8490792Sgshapiro lmap->ldap_attrsep = '\0'; 8590792Sgshapiro lmap->ldap_binddn = NULL; 8690792Sgshapiro lmap->ldap_secret = NULL; 8790792Sgshapiro lmap->ldap_method = LDAP_AUTH_SIMPLE; 8890792Sgshapiro lmap->ldap_base = NULL; 8990792Sgshapiro lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 9090792Sgshapiro lmap->ldap_attrsonly = LDAPMAP_FALSE; 9190792Sgshapiro lmap->ldap_timeout.tv_sec = 0; 9290792Sgshapiro lmap->ldap_timeout.tv_usec = 0; 9390792Sgshapiro lmap->ldap_ld = NULL; 9490792Sgshapiro lmap->ldap_filter = NULL; 9590792Sgshapiro lmap->ldap_attr[0] = NULL; 9694334Sgshapiro lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; 9794334Sgshapiro lmap->ldap_attr_needobjclass[0] = NULL; 9890792Sgshapiro lmap->ldap_res = NULL; 9990792Sgshapiro lmap->ldap_next = NULL; 10090792Sgshapiro lmap->ldap_pid = 0; 101168515Sgshapiro lmap->ldap_multi_args = false; 10290792Sgshapiro} 10390792Sgshapiro 10490792Sgshapiro/* 10590792Sgshapiro** SM_LDAP_START -- actually connect to an LDAP server 10690792Sgshapiro** 10790792Sgshapiro** Parameters: 10890792Sgshapiro** name -- name of map for debug output. 10990792Sgshapiro** lmap -- the LDAP map being opened. 11090792Sgshapiro** 11190792Sgshapiro** Returns: 11290792Sgshapiro** true if connection is successful, false otherwise. 11390792Sgshapiro** 11490792Sgshapiro** Side Effects: 11590792Sgshapiro** Populates lmap->ldap_ld. 11690792Sgshapiro*/ 11790792Sgshapiro 11890792Sgshapirostatic jmp_buf LDAPTimeout; 11990792Sgshapiro 12090792Sgshapiro#define SM_LDAP_SETTIMEOUT(to) \ 12190792Sgshapirodo \ 12290792Sgshapiro{ \ 12390792Sgshapiro if (to != 0) \ 12490792Sgshapiro { \ 12590792Sgshapiro if (setjmp(LDAPTimeout) != 0) \ 12690792Sgshapiro { \ 12790792Sgshapiro errno = ETIMEDOUT; \ 12890792Sgshapiro return false; \ 12990792Sgshapiro } \ 13090792Sgshapiro ev = sm_setevent(to, ldaptimeout, 0); \ 13190792Sgshapiro } \ 13290792Sgshapiro} while (0) 13390792Sgshapiro 13490792Sgshapiro#define SM_LDAP_CLEARTIMEOUT() \ 13590792Sgshapirodo \ 13690792Sgshapiro{ \ 13790792Sgshapiro if (ev != NULL) \ 13890792Sgshapiro sm_clrevent(ev); \ 13990792Sgshapiro} while (0) 14090792Sgshapiro 14190792Sgshapirobool 14290792Sgshapirosm_ldap_start(name, lmap) 14390792Sgshapiro char *name; 14490792Sgshapiro SM_LDAP_STRUCT *lmap; 14590792Sgshapiro{ 14690792Sgshapiro int bind_result; 147141858Sgshapiro int save_errno = 0; 148132943Sgshapiro char *id; 14990792Sgshapiro SM_EVENT *ev = NULL; 150132943Sgshapiro LDAP *ld = NULL; 15190792Sgshapiro 15290792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 2)) 15390792Sgshapiro sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); 15490792Sgshapiro 155132943Sgshapiro if (lmap->ldap_host != NULL) 156132943Sgshapiro id = lmap->ldap_host; 157132943Sgshapiro else if (lmap->ldap_uri != NULL) 158132943Sgshapiro id = lmap->ldap_uri; 159132943Sgshapiro else 160132943Sgshapiro id = "localhost"; 161132943Sgshapiro 16290792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 9)) 163132943Sgshapiro { 164132943Sgshapiro /* Don't print a port number for LDAP URIs */ 165132943Sgshapiro if (lmap->ldap_uri != NULL) 166132943Sgshapiro sm_dprintf("ldapmap_start(%s)\n", id); 167132943Sgshapiro else 168132943Sgshapiro sm_dprintf("ldapmap_start(%s, %d)\n", id, 169132943Sgshapiro lmap->ldap_port); 170132943Sgshapiro } 17190792Sgshapiro 172132943Sgshapiro if (lmap->ldap_uri != NULL) 173132943Sgshapiro { 174132943Sgshapiro#if SM_CONF_LDAP_INITIALIZE 175132943Sgshapiro /* LDAP server supports URIs so use them directly */ 176132943Sgshapiro save_errno = ldap_initialize(&ld, lmap->ldap_uri); 177132943Sgshapiro#else /* SM_CONF_LDAP_INITIALIZE */ 178132943Sgshapiro int err; 179132943Sgshapiro LDAPURLDesc *ludp = NULL; 180132943Sgshapiro 181132943Sgshapiro /* Blast apart URL and use the ldap_init/ldap_open below */ 182132943Sgshapiro err = ldap_url_parse(lmap->ldap_uri, &ludp); 183132943Sgshapiro if (err != 0) 184132943Sgshapiro { 185132943Sgshapiro errno = err + E_LDAPURLBASE; 186132943Sgshapiro return false; 187132943Sgshapiro } 188132943Sgshapiro lmap->ldap_host = sm_strdup_x(ludp->lud_host); 189132943Sgshapiro if (lmap->ldap_host == NULL) 190132943Sgshapiro { 191132943Sgshapiro save_errno = errno; 192132943Sgshapiro ldap_free_urldesc(ludp); 193132943Sgshapiro errno = save_errno; 194132943Sgshapiro return false; 195132943Sgshapiro } 196132943Sgshapiro lmap->ldap_port = ludp->lud_port; 197132943Sgshapiro ldap_free_urldesc(ludp); 198132943Sgshapiro#endif /* SM_CONF_LDAP_INITIALIZE */ 199132943Sgshapiro } 200132943Sgshapiro 201132943Sgshapiro if (ld == NULL) 202132943Sgshapiro { 20390792Sgshapiro# if USE_LDAP_INIT 204132943Sgshapiro ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 205132943Sgshapiro save_errno = errno; 20690792Sgshapiro# else /* USE_LDAP_INIT */ 207132943Sgshapiro /* 208132943Sgshapiro ** If using ldap_open(), the actual connection to the server 209132943Sgshapiro ** happens now so we need the timeout here. For ldap_init(), 210132943Sgshapiro ** the connection happens at bind time. 211132943Sgshapiro */ 21290792Sgshapiro 213132943Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 214132943Sgshapiro ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 215132943Sgshapiro save_errno = errno; 21690792Sgshapiro 217132943Sgshapiro /* clear the event if it has not sprung */ 218132943Sgshapiro SM_LDAP_CLEARTIMEOUT(); 21990792Sgshapiro# endif /* USE_LDAP_INIT */ 220132943Sgshapiro } 22190792Sgshapiro 22290792Sgshapiro errno = save_errno; 22390792Sgshapiro if (ld == NULL) 22490792Sgshapiro return false; 22590792Sgshapiro 22690792Sgshapiro sm_ldap_setopts(ld, lmap); 22790792Sgshapiro 22890792Sgshapiro# if USE_LDAP_INIT 22990792Sgshapiro /* 23090792Sgshapiro ** If using ldap_init(), the actual connection to the server 23190792Sgshapiro ** happens at ldap_bind_s() so we need the timeout here. 23290792Sgshapiro */ 23390792Sgshapiro 23490792Sgshapiro SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); 23590792Sgshapiro# endif /* USE_LDAP_INIT */ 23690792Sgshapiro 23790792Sgshapiro# ifdef LDAP_AUTH_KRBV4 23890792Sgshapiro if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 23990792Sgshapiro lmap->ldap_secret != NULL) 24090792Sgshapiro { 24190792Sgshapiro /* 24290792Sgshapiro ** Need to put ticket in environment here instead of 24390792Sgshapiro ** during parseargs as there may be different tickets 24490792Sgshapiro ** for different LDAP connections. 24590792Sgshapiro */ 24690792Sgshapiro 24790792Sgshapiro (void) putenv(lmap->ldap_secret); 24890792Sgshapiro } 24990792Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 25090792Sgshapiro 25190792Sgshapiro bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 25290792Sgshapiro lmap->ldap_secret, lmap->ldap_method); 25390792Sgshapiro 25490792Sgshapiro# if USE_LDAP_INIT 25590792Sgshapiro /* clear the event if it has not sprung */ 25690792Sgshapiro SM_LDAP_CLEARTIMEOUT(); 25790792Sgshapiro# endif /* USE_LDAP_INIT */ 25890792Sgshapiro 25990792Sgshapiro if (bind_result != LDAP_SUCCESS) 26090792Sgshapiro { 26190792Sgshapiro errno = bind_result + E_LDAPBASE; 26290792Sgshapiro return false; 26390792Sgshapiro } 26490792Sgshapiro 26590792Sgshapiro /* Save PID to make sure only this PID closes the LDAP connection */ 26690792Sgshapiro lmap->ldap_pid = getpid(); 26790792Sgshapiro lmap->ldap_ld = ld; 26890792Sgshapiro return true; 26990792Sgshapiro} 27090792Sgshapiro 27190792Sgshapiro/* ARGSUSED */ 27290792Sgshapirostatic void 27390792Sgshapiroldaptimeout(unused) 27490792Sgshapiro int unused; 27590792Sgshapiro{ 27690792Sgshapiro /* 27790792Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 27890792Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 27990792Sgshapiro ** DOING. 28090792Sgshapiro */ 28190792Sgshapiro 28290792Sgshapiro errno = ETIMEDOUT; 28390792Sgshapiro longjmp(LDAPTimeout, 1); 28490792Sgshapiro} 28590792Sgshapiro 28690792Sgshapiro/* 287168515Sgshapiro** SM_LDAP_SEARCH_M -- initiate multi-key LDAP search 28890792Sgshapiro** 28990792Sgshapiro** Initiate an LDAP search, return the msgid. 29090792Sgshapiro** The calling function must collect the results. 29190792Sgshapiro** 29290792Sgshapiro** Parameters: 29390792Sgshapiro** lmap -- LDAP map information 294168515Sgshapiro** argv -- key vector of substitutions in LDAP filter 295168515Sgshapiro** NOTE: argv must have SM_LDAP_ARGS elements to prevent 296168515Sgshapiro** out of bound array references 29790792Sgshapiro** 29890792Sgshapiro** Returns: 299168515Sgshapiro** <0 on failure (SM_LDAP_ERR*), msgid on success 30090792Sgshapiro** 30190792Sgshapiro*/ 30290792Sgshapiro 30390792Sgshapiroint 304168515Sgshapirosm_ldap_search_m(lmap, argv) 30590792Sgshapiro SM_LDAP_STRUCT *lmap; 306168515Sgshapiro char **argv; 30790792Sgshapiro{ 30890792Sgshapiro int msgid; 30990792Sgshapiro char *fp, *p, *q; 31090792Sgshapiro char filter[LDAPMAP_MAX_FILTER + 1]; 31190792Sgshapiro 312168515Sgshapiro SM_REQUIRE(lmap != NULL); 313168515Sgshapiro SM_REQUIRE(argv != NULL); 314168515Sgshapiro SM_REQUIRE(argv[0] != NULL); 315168515Sgshapiro 31690792Sgshapiro memset(filter, '\0', sizeof filter); 31790792Sgshapiro fp = filter; 31890792Sgshapiro p = lmap->ldap_filter; 31990792Sgshapiro while ((q = strchr(p, '%')) != NULL) 32090792Sgshapiro { 321168515Sgshapiro char *key; 322168515Sgshapiro 323168515Sgshapiro if (lmap->ldap_multi_args) 324168515Sgshapiro { 325168515Sgshapiro#if SM_LDAP_ARGS < 10 326168515Sgshapiro# ERROR _SM_LDAP_ARGS must be 10 327168515Sgshapiro#endif /* SM_LDAP_ARGS < 10 */ 328168515Sgshapiro if (q[1] == 's') 329168515Sgshapiro key = argv[0]; 330168515Sgshapiro else if (q[1] >= '0' && q[1] <= '9') 331168515Sgshapiro { 332168515Sgshapiro key = argv[q[1] - '0']; 333168515Sgshapiro if (key == NULL) 334168515Sgshapiro { 335168515Sgshapiro# if SM_LDAP_ERROR_ON_MISSING_ARGS 336168515Sgshapiro return SM_LDAP_ERR_ARG_MISS; 337168515Sgshapiro# else /* SM_LDAP_ERROR_ON_MISSING_ARGS */ 338168515Sgshapiro key = ""; 339168515Sgshapiro# endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */ 340168515Sgshapiro } 341168515Sgshapiro } 342168515Sgshapiro else 343168515Sgshapiro key = NULL; 344168515Sgshapiro } 345168515Sgshapiro else 346168515Sgshapiro key = argv[0]; 347168515Sgshapiro 34890792Sgshapiro if (q[1] == 's') 34990792Sgshapiro { 35090792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 35190792Sgshapiro "%.*s%s", (int) (q - p), p, key); 35290792Sgshapiro fp += strlen(fp); 35390792Sgshapiro p = q + 2; 35490792Sgshapiro } 355168515Sgshapiro else if (q[1] == '0' || 356168515Sgshapiro (lmap->ldap_multi_args && q[1] >= '0' && q[1] <= '9')) 35790792Sgshapiro { 35890792Sgshapiro char *k = key; 35990792Sgshapiro 36090792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 36190792Sgshapiro "%.*s", (int) (q - p), p); 36290792Sgshapiro fp += strlen(fp); 36390792Sgshapiro p = q + 2; 36490792Sgshapiro 36590792Sgshapiro /* Properly escape LDAP special characters */ 36690792Sgshapiro while (SPACELEFT(filter, fp) > 0 && 36790792Sgshapiro *k != '\0') 36890792Sgshapiro { 36990792Sgshapiro if (*k == '*' || *k == '(' || 37090792Sgshapiro *k == ')' || *k == '\\') 37190792Sgshapiro { 37290792Sgshapiro (void) sm_strlcat(fp, 37390792Sgshapiro (*k == '*' ? "\\2A" : 37490792Sgshapiro (*k == '(' ? "\\28" : 37590792Sgshapiro (*k == ')' ? "\\29" : 37690792Sgshapiro (*k == '\\' ? "\\5C" : 37790792Sgshapiro "\00")))), 37890792Sgshapiro SPACELEFT(filter, fp)); 37990792Sgshapiro fp += strlen(fp); 38090792Sgshapiro k++; 38190792Sgshapiro } 38290792Sgshapiro else 38390792Sgshapiro *fp++ = *k++; 38490792Sgshapiro } 38590792Sgshapiro } 38690792Sgshapiro else 38790792Sgshapiro { 38890792Sgshapiro (void) sm_snprintf(fp, SPACELEFT(filter, fp), 38990792Sgshapiro "%.*s", (int) (q - p + 1), p); 39090792Sgshapiro p = q + (q[1] == '%' ? 2 : 1); 39190792Sgshapiro fp += strlen(fp); 39290792Sgshapiro } 39390792Sgshapiro } 39490792Sgshapiro (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); 39590792Sgshapiro if (sm_debug_active(&SmLDAPTrace, 20)) 39690792Sgshapiro sm_dprintf("ldap search filter=%s\n", filter); 39790792Sgshapiro 39890792Sgshapiro lmap->ldap_res = NULL; 39994334Sgshapiro msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, 40094334Sgshapiro lmap->ldap_scope, filter, 40190792Sgshapiro (lmap->ldap_attr[0] == NULL ? NULL : 40290792Sgshapiro lmap->ldap_attr), 40390792Sgshapiro lmap->ldap_attrsonly); 40490792Sgshapiro return msgid; 40590792Sgshapiro} 40690792Sgshapiro 40790792Sgshapiro/* 408168515Sgshapiro** SM_LDAP_SEARCH -- initiate LDAP search 409168515Sgshapiro** 410168515Sgshapiro** Initiate an LDAP search, return the msgid. 411168515Sgshapiro** The calling function must collect the results. 412168515Sgshapiro** Note this is just a wrapper into sm_ldap_search_m() 413168515Sgshapiro** 414168515Sgshapiro** Parameters: 415168515Sgshapiro** lmap -- LDAP map information 416168515Sgshapiro** key -- key to substitute in LDAP filter 417168515Sgshapiro** 418168515Sgshapiro** Returns: 419168515Sgshapiro** <0 on failure, msgid on success 420168515Sgshapiro** 421168515Sgshapiro*/ 422168515Sgshapiro 423168515Sgshapiroint 424168515Sgshapirosm_ldap_search(lmap, key) 425168515Sgshapiro SM_LDAP_STRUCT *lmap; 426168515Sgshapiro char *key; 427168515Sgshapiro{ 428168515Sgshapiro char *argv[SM_LDAP_ARGS]; 429168515Sgshapiro 430168515Sgshapiro memset(argv, '\0', sizeof argv); 431168515Sgshapiro argv[0] = key; 432168515Sgshapiro return sm_ldap_search_m(lmap, argv); 433168515Sgshapiro} 434168515Sgshapiro 435168515Sgshapiro/* 43694334Sgshapiro** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a 43794334Sgshapiro** particular objectClass 43894334Sgshapiro** 43994334Sgshapiro** Parameters: 44094334Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 44194334Sgshapiro** entry -- current LDAP entry struct 44294334Sgshapiro** ocvalue -- particular objectclass in question. 44394334Sgshapiro** may be of form (fee|foo|fum) meaning 44494334Sgshapiro** any entry can be part of either fee, 44594334Sgshapiro** foo or fum objectclass 44694334Sgshapiro** 44794334Sgshapiro** Returns: 44894334Sgshapiro** true if item has that objectClass 44994334Sgshapiro*/ 45094334Sgshapiro 45194334Sgshapirostatic bool 45294334Sgshapirosm_ldap_has_objectclass(lmap, entry, ocvalue) 45394334Sgshapiro SM_LDAP_STRUCT *lmap; 45494334Sgshapiro LDAPMessage *entry; 45594334Sgshapiro char *ocvalue; 45694334Sgshapiro{ 45794334Sgshapiro char **vals = NULL; 45894334Sgshapiro int i; 45994334Sgshapiro 46094334Sgshapiro if (ocvalue == NULL) 46194334Sgshapiro return false; 46294334Sgshapiro 46394334Sgshapiro vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); 46494334Sgshapiro if (vals == NULL) 46594334Sgshapiro return false; 46694334Sgshapiro 46794334Sgshapiro for (i = 0; vals[i] != NULL; i++) 46894334Sgshapiro { 46994334Sgshapiro char *p; 47094334Sgshapiro char *q; 47194334Sgshapiro 47294334Sgshapiro p = q = ocvalue; 47394334Sgshapiro while (*p != '\0') 47494334Sgshapiro { 47594334Sgshapiro while (*p != '\0' && *p != '|') 47694334Sgshapiro p++; 47794334Sgshapiro 47894334Sgshapiro if ((p - q) == strlen(vals[i]) && 47994334Sgshapiro sm_strncasecmp(vals[i], q, p - q) == 0) 48094334Sgshapiro { 48194334Sgshapiro ldap_value_free(vals); 48294334Sgshapiro return true; 48394334Sgshapiro } 48494334Sgshapiro 48594334Sgshapiro while (*p == '|') 48694334Sgshapiro p++; 48794334Sgshapiro q = p; 48894334Sgshapiro } 48994334Sgshapiro } 49094334Sgshapiro 49194334Sgshapiro ldap_value_free(vals); 49294334Sgshapiro return false; 49394334Sgshapiro} 49494334Sgshapiro 49594334Sgshapiro/* 49690792Sgshapiro** SM_LDAP_RESULTS -- return results from an LDAP lookup in result 49790792Sgshapiro** 49890792Sgshapiro** Parameters: 49990792Sgshapiro** lmap -- pointer to SM_LDAP_STRUCT in use 50090792Sgshapiro** msgid -- msgid returned by sm_ldap_search() 50190792Sgshapiro** flags -- flags for the lookup 50290792Sgshapiro** delim -- delimiter for result concatenation 50390792Sgshapiro** rpool -- memory pool for storage 50490792Sgshapiro** result -- return string 50590792Sgshapiro** recurse -- recursion list 50690792Sgshapiro** 50790792Sgshapiro** Returns: 50890792Sgshapiro** status (sysexit) 50990792Sgshapiro*/ 51090792Sgshapiro 51194334Sgshapiro# define SM_LDAP_ERROR_CLEANUP() \ 51290792Sgshapiro{ \ 51390792Sgshapiro if (lmap->ldap_res != NULL) \ 51490792Sgshapiro { \ 51590792Sgshapiro ldap_msgfree(lmap->ldap_res); \ 51690792Sgshapiro lmap->ldap_res = NULL; \ 51790792Sgshapiro } \ 51890792Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); \ 51990792Sgshapiro} 52090792Sgshapiro 52194334Sgshapirostatic SM_LDAP_RECURSE_ENTRY * 52294334Sgshapirosm_ldap_add_recurse(top, item, type, rpool) 52390792Sgshapiro SM_LDAP_RECURSE_LIST **top; 52490792Sgshapiro char *item; 52590792Sgshapiro int type; 52690792Sgshapiro SM_RPOOL_T *rpool; 52790792Sgshapiro{ 52894334Sgshapiro int n; 52994334Sgshapiro int m; 53094334Sgshapiro int p; 53194334Sgshapiro int insertat; 53294334Sgshapiro int moveb; 53394334Sgshapiro int oldsizeb; 53494334Sgshapiro int rc; 53594334Sgshapiro SM_LDAP_RECURSE_ENTRY *newe; 53694334Sgshapiro SM_LDAP_RECURSE_ENTRY **olddata; 53790792Sgshapiro 53894334Sgshapiro /* 53994334Sgshapiro ** This code will maintain a list of 54094334Sgshapiro ** SM_LDAP_RECURSE_ENTRY structures 54194334Sgshapiro ** in ascending order. 54294334Sgshapiro */ 54394334Sgshapiro 54494334Sgshapiro if (*top == NULL) 54590792Sgshapiro { 54694334Sgshapiro /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ 54794334Sgshapiro *top = sm_rpool_malloc_x(rpool, sizeof **top); 548168515Sgshapiro (*top)->lrl_cnt = 0; 549168515Sgshapiro (*top)->lrl_size = 0; 550168515Sgshapiro (*top)->lrl_data = NULL; 55194334Sgshapiro } 55294334Sgshapiro 553168515Sgshapiro if ((*top)->lrl_cnt >= (*top)->lrl_size) 55494334Sgshapiro { 55594334Sgshapiro /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ 556168515Sgshapiro olddata = (*top)->lrl_data; 557168515Sgshapiro if ((*top)->lrl_size == 0) 55890792Sgshapiro { 55994334Sgshapiro oldsizeb = 0; 560168515Sgshapiro (*top)->lrl_size = 256; 56190792Sgshapiro } 56294334Sgshapiro else 56394334Sgshapiro { 564168515Sgshapiro oldsizeb = (*top)->lrl_size * sizeof *((*top)->lrl_data); 565168515Sgshapiro (*top)->lrl_size *= 2; 56694334Sgshapiro } 567168515Sgshapiro (*top)->lrl_data = sm_rpool_malloc_x(rpool, 568168515Sgshapiro (*top)->lrl_size * sizeof *((*top)->lrl_data)); 56994334Sgshapiro if (oldsizeb > 0) 570168515Sgshapiro memcpy((*top)->lrl_data, olddata, oldsizeb); 57190792Sgshapiro } 57290792Sgshapiro 57394334Sgshapiro /* 57494334Sgshapiro ** Binary search/insert item:type into list. 57594334Sgshapiro ** Return current entry pointer if already exists. 57694334Sgshapiro */ 57794334Sgshapiro 57894334Sgshapiro n = 0; 579168515Sgshapiro m = (*top)->lrl_cnt - 1; 58094334Sgshapiro if (m < 0) 58194334Sgshapiro insertat = 0; 58290792Sgshapiro else 58394334Sgshapiro insertat = -1; 58494334Sgshapiro 58594334Sgshapiro while (insertat == -1) 58694334Sgshapiro { 58794334Sgshapiro p = (m + n) / 2; 58894334Sgshapiro 589168515Sgshapiro rc = sm_strcasecmp(item, (*top)->lrl_data[p]->lr_search); 59094334Sgshapiro if (rc == 0) 591168515Sgshapiro rc = type - (*top)->lrl_data[p]->lr_type; 59294334Sgshapiro 59394334Sgshapiro if (rc < 0) 59494334Sgshapiro m = p - 1; 59594334Sgshapiro else if (rc > 0) 59694334Sgshapiro n = p + 1; 59794334Sgshapiro else 598168515Sgshapiro return (*top)->lrl_data[p]; 59994334Sgshapiro 60094334Sgshapiro if (m == -1) 60194334Sgshapiro insertat = 0; 602168515Sgshapiro else if (n >= (*top)->lrl_cnt) 603168515Sgshapiro insertat = (*top)->lrl_cnt; 60494334Sgshapiro else if (m < n) 60594334Sgshapiro insertat = m + 1; 60694334Sgshapiro } 60794334Sgshapiro 60894334Sgshapiro /* 60994334Sgshapiro ** Not found in list, make room 61094334Sgshapiro ** at insert point and add it. 61194334Sgshapiro */ 61294334Sgshapiro 61394334Sgshapiro newe = sm_rpool_malloc_x(rpool, sizeof *newe); 61494334Sgshapiro if (newe != NULL) 61594334Sgshapiro { 616168515Sgshapiro moveb = ((*top)->lrl_cnt - insertat) * sizeof *((*top)->lrl_data); 61794334Sgshapiro if (moveb > 0) 618168515Sgshapiro memmove(&((*top)->lrl_data[insertat + 1]), 619168515Sgshapiro &((*top)->lrl_data[insertat]), 62094334Sgshapiro moveb); 62194334Sgshapiro 62294334Sgshapiro newe->lr_search = sm_rpool_strdup_x(rpool, item); 62394334Sgshapiro newe->lr_type = type; 624132943Sgshapiro newe->lr_ludp = NULL; 625132943Sgshapiro newe->lr_attrs = NULL; 62694334Sgshapiro newe->lr_done = false; 62794334Sgshapiro 628168515Sgshapiro ((*top)->lrl_data)[insertat] = newe; 629168515Sgshapiro (*top)->lrl_cnt++; 63094334Sgshapiro } 63194334Sgshapiro return newe; 63290792Sgshapiro} 63390792Sgshapiro 63490792Sgshapiroint 63594334Sgshapirosm_ldap_results(lmap, msgid, flags, delim, rpool, result, 63694334Sgshapiro resultln, resultsz, recurse) 63790792Sgshapiro SM_LDAP_STRUCT *lmap; 63890792Sgshapiro int msgid; 63990792Sgshapiro int flags; 64094334Sgshapiro int delim; 64190792Sgshapiro SM_RPOOL_T *rpool; 64290792Sgshapiro char **result; 64394334Sgshapiro int *resultln; 64494334Sgshapiro int *resultsz; 64590792Sgshapiro SM_LDAP_RECURSE_LIST *recurse; 64690792Sgshapiro{ 64790792Sgshapiro bool toplevel; 64890792Sgshapiro int i; 64990792Sgshapiro int statp; 65090792Sgshapiro int vsize; 65190792Sgshapiro int ret; 65290792Sgshapiro int save_errno; 65390792Sgshapiro char *p; 65494334Sgshapiro SM_LDAP_RECURSE_ENTRY *rl; 65590792Sgshapiro 65690792Sgshapiro /* Are we the top top level of the search? */ 65790792Sgshapiro toplevel = (recurse == NULL); 65890792Sgshapiro 65990792Sgshapiro /* Get results */ 66090792Sgshapiro statp = EX_NOTFOUND; 66190792Sgshapiro while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, 66290792Sgshapiro (lmap->ldap_timeout.tv_sec == 0 ? NULL : 66390792Sgshapiro &(lmap->ldap_timeout)), 66490792Sgshapiro &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 66590792Sgshapiro { 66690792Sgshapiro LDAPMessage *entry; 66790792Sgshapiro 66890792Sgshapiro /* If we don't want multiple values and we have one, break */ 669147078Sgshapiro if ((char) delim == '\0' && 670147078Sgshapiro !bitset(SM_LDAP_SINGLEMATCH, flags) && 671147078Sgshapiro *result != NULL) 67290792Sgshapiro break; 67390792Sgshapiro 67490792Sgshapiro /* Cycle through all entries */ 67590792Sgshapiro for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 67690792Sgshapiro entry != NULL; 67790792Sgshapiro entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 67890792Sgshapiro { 67990792Sgshapiro BerElement *ber; 68090792Sgshapiro char *attr; 68190792Sgshapiro char **vals = NULL; 68290792Sgshapiro char *dn; 68390792Sgshapiro 68490792Sgshapiro /* 68590792Sgshapiro ** If matching only and found an entry, 68690792Sgshapiro ** no need to spin through attributes 68790792Sgshapiro */ 68890792Sgshapiro 689125820Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 690125820Sgshapiro { 691125820Sgshapiro statp = EX_OK; 69290792Sgshapiro continue; 693125820Sgshapiro } 69490792Sgshapiro 695157001Sgshapiro#if _FFR_LDAP_SINGLEDN 696157001Sgshapiro if (bitset(SM_LDAP_SINGLEDN, flags) && *result != NULL) 697157001Sgshapiro { 698157001Sgshapiro /* only wanted one match */ 699157001Sgshapiro SM_LDAP_ERROR_CLEANUP(); 700157001Sgshapiro errno = ENOENT; 701157001Sgshapiro return EX_NOTFOUND; 702157001Sgshapiro } 703157001Sgshapiro#endif /* _FFR_LDAP_SINGLEDN */ 704157001Sgshapiro 70590792Sgshapiro /* record completed DN's to prevent loops */ 70690792Sgshapiro dn = ldap_get_dn(lmap->ldap_ld, entry); 70790792Sgshapiro if (dn == NULL) 70890792Sgshapiro { 70990792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 71090792Sgshapiro save_errno += E_LDAPBASE; 71194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 71290792Sgshapiro errno = save_errno; 713120256Sgshapiro return EX_TEMPFAIL; 71490792Sgshapiro } 71590792Sgshapiro 71694334Sgshapiro rl = sm_ldap_add_recurse(&recurse, dn, 71794334Sgshapiro SM_LDAP_ATTR_DN, 71894334Sgshapiro rpool); 71994334Sgshapiro 72094334Sgshapiro if (rl == NULL) 72190792Sgshapiro { 72290792Sgshapiro ldap_memfree(dn); 72394334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 72490792Sgshapiro errno = ENOMEM; 72590792Sgshapiro return EX_OSERR; 72694334Sgshapiro } 72794334Sgshapiro else if (rl->lr_done) 72894334Sgshapiro { 72990792Sgshapiro /* already on list, skip it */ 73090792Sgshapiro ldap_memfree(dn); 73190792Sgshapiro continue; 73290792Sgshapiro } 73390792Sgshapiro ldap_memfree(dn); 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 for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 74690792Sgshapiro &ber); 74790792Sgshapiro attr != NULL; 74890792Sgshapiro attr = ldap_next_attribute(lmap->ldap_ld, entry, 74990792Sgshapiro ber)) 75090792Sgshapiro { 75190792Sgshapiro char *tmp, *vp_tmp; 75290792Sgshapiro int type; 75394334Sgshapiro char *needobjclass = NULL; 75490792Sgshapiro 75594334Sgshapiro type = SM_LDAP_ATTR_NONE; 75690792Sgshapiro for (i = 0; lmap->ldap_attr[i] != NULL; i++) 75790792Sgshapiro { 75890792Sgshapiro if (sm_strcasecmp(lmap->ldap_attr[i], 75990792Sgshapiro attr) == 0) 76090792Sgshapiro { 76190792Sgshapiro type = lmap->ldap_attr_type[i]; 76294334Sgshapiro needobjclass = lmap->ldap_attr_needobjclass[i]; 76390792Sgshapiro break; 76490792Sgshapiro } 76590792Sgshapiro } 76694334Sgshapiro 76794334Sgshapiro if (bitset(SM_LDAP_USE_ALLATTR, flags) && 76894334Sgshapiro type == SM_LDAP_ATTR_NONE) 76990792Sgshapiro { 77094334Sgshapiro /* URL lookups specify attrs to use */ 77194334Sgshapiro type = SM_LDAP_ATTR_NORMAL; 77294334Sgshapiro needobjclass = NULL; 77394334Sgshapiro } 77494334Sgshapiro 77594334Sgshapiro if (type == SM_LDAP_ATTR_NONE) 77694334Sgshapiro { 77790792Sgshapiro /* attribute not requested */ 77890792Sgshapiro ldap_memfree(attr); 77994334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 78090792Sgshapiro errno = EFAULT; 78190792Sgshapiro return EX_SOFTWARE; 78290792Sgshapiro } 78390792Sgshapiro 78494334Sgshapiro /* 78594334Sgshapiro ** For recursion on a particular attribute, 78694334Sgshapiro ** we may need to see if this entry is 78794334Sgshapiro ** part of a particular objectclass. 78894334Sgshapiro ** Also, ignore objectClass attribute. 78994334Sgshapiro ** Otherwise we just ignore this attribute. 79094334Sgshapiro */ 79194334Sgshapiro 79294334Sgshapiro if (type == SM_LDAP_ATTR_OBJCLASS || 79394334Sgshapiro (needobjclass != NULL && 79494334Sgshapiro !sm_ldap_has_objectclass(lmap, entry, 79594334Sgshapiro needobjclass))) 79694334Sgshapiro { 79794334Sgshapiro ldap_memfree(attr); 79894334Sgshapiro continue; 79994334Sgshapiro } 80094334Sgshapiro 80190792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 80290792Sgshapiro { 80390792Sgshapiro vals = ldap_get_values(lmap->ldap_ld, 80490792Sgshapiro entry, 80590792Sgshapiro attr); 80690792Sgshapiro if (vals == NULL) 80790792Sgshapiro { 80890792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 80990792Sgshapiro if (save_errno == LDAP_SUCCESS) 81090792Sgshapiro { 81190792Sgshapiro ldap_memfree(attr); 81290792Sgshapiro continue; 81390792Sgshapiro } 81490792Sgshapiro 81590792Sgshapiro /* Must be an error */ 81690792Sgshapiro save_errno += E_LDAPBASE; 81790792Sgshapiro ldap_memfree(attr); 81894334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 81990792Sgshapiro errno = save_errno; 82090792Sgshapiro return EX_TEMPFAIL; 82190792Sgshapiro } 82290792Sgshapiro } 82390792Sgshapiro 82490792Sgshapiro statp = EX_OK; 82590792Sgshapiro 82690792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 82790792Sgshapiro /* 82890792Sgshapiro ** Reset value to prevent lingering 82990792Sgshapiro ** LDAP_DECODING_ERROR due to 83090792Sgshapiro ** OpenLDAP 1.X's hack (see below) 83190792Sgshapiro */ 83290792Sgshapiro 83390792Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 83490792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 83590792Sgshapiro 83690792Sgshapiro /* 83790792Sgshapiro ** If matching only, 83890792Sgshapiro ** no need to spin through entries 83990792Sgshapiro */ 84090792Sgshapiro 84190792Sgshapiro if (bitset(SM_LDAP_MATCHONLY, flags)) 84290792Sgshapiro { 84390792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 84490792Sgshapiro ldap_value_free(vals); 84590792Sgshapiro ldap_memfree(attr); 84690792Sgshapiro continue; 84790792Sgshapiro } 84890792Sgshapiro 84990792Sgshapiro /* 85090792Sgshapiro ** If we don't want multiple values, 85190792Sgshapiro ** return first found. 85290792Sgshapiro */ 85390792Sgshapiro 85494334Sgshapiro if ((char) delim == '\0') 85590792Sgshapiro { 85694334Sgshapiro if (*result != NULL) 85794334Sgshapiro { 85894334Sgshapiro /* already have a value */ 859147078Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 860147078Sgshapiro flags)) 861147078Sgshapiro { 862147078Sgshapiro /* only wanted one match */ 863147078Sgshapiro SM_LDAP_ERROR_CLEANUP(); 864147078Sgshapiro errno = ENOENT; 865147078Sgshapiro return EX_NOTFOUND; 866147078Sgshapiro } 86794334Sgshapiro break; 86894334Sgshapiro } 86994334Sgshapiro 87090792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 87190792Sgshapiro { 87290792Sgshapiro *result = sm_rpool_strdup_x(rpool, 87390792Sgshapiro attr); 87490792Sgshapiro ldap_memfree(attr); 87590792Sgshapiro break; 87690792Sgshapiro } 87790792Sgshapiro 87890792Sgshapiro if (vals[0] == NULL) 87990792Sgshapiro { 88090792Sgshapiro ldap_value_free(vals); 88190792Sgshapiro ldap_memfree(attr); 88290792Sgshapiro continue; 88390792Sgshapiro } 88490792Sgshapiro 88590792Sgshapiro vsize = strlen(vals[0]) + 1; 88690792Sgshapiro if (lmap->ldap_attrsep != '\0') 88790792Sgshapiro vsize += strlen(attr) + 1; 88890792Sgshapiro *result = sm_rpool_malloc_x(rpool, 88990792Sgshapiro vsize); 89090792Sgshapiro if (lmap->ldap_attrsep != '\0') 89190792Sgshapiro sm_snprintf(*result, vsize, 89290792Sgshapiro "%s%c%s", 89390792Sgshapiro attr, 89490792Sgshapiro lmap->ldap_attrsep, 89590792Sgshapiro vals[0]); 89690792Sgshapiro else 89790792Sgshapiro sm_strlcpy(*result, vals[0], 89890792Sgshapiro vsize); 89990792Sgshapiro ldap_value_free(vals); 90090792Sgshapiro ldap_memfree(attr); 90190792Sgshapiro break; 90290792Sgshapiro } 90390792Sgshapiro 90490792Sgshapiro /* attributes only */ 90590792Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 90690792Sgshapiro { 90790792Sgshapiro if (*result == NULL) 90890792Sgshapiro *result = sm_rpool_strdup_x(rpool, 90990792Sgshapiro attr); 91090792Sgshapiro else 91190792Sgshapiro { 91294334Sgshapiro if (bitset(SM_LDAP_SINGLEMATCH, 91394334Sgshapiro flags) && 91494334Sgshapiro *result != NULL) 91594334Sgshapiro { 91694334Sgshapiro /* only wanted one match */ 91794334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 91894334Sgshapiro errno = ENOENT; 91994334Sgshapiro return EX_NOTFOUND; 92094334Sgshapiro } 92194334Sgshapiro 92290792Sgshapiro vsize = strlen(*result) + 92390792Sgshapiro strlen(attr) + 2; 92490792Sgshapiro tmp = sm_rpool_malloc_x(rpool, 92590792Sgshapiro vsize); 92690792Sgshapiro (void) sm_snprintf(tmp, 92790792Sgshapiro vsize, "%s%c%s", 92894334Sgshapiro *result, (char) delim, 92990792Sgshapiro attr); 93090792Sgshapiro *result = tmp; 93190792Sgshapiro } 93290792Sgshapiro ldap_memfree(attr); 93390792Sgshapiro continue; 93490792Sgshapiro } 93590792Sgshapiro 93690792Sgshapiro /* 93794334Sgshapiro ** If there is more than one, munge then 93894334Sgshapiro ** into a map_coldelim separated string. 93994334Sgshapiro ** If we are recursing we may have an entry 94094334Sgshapiro ** with no 'normal' values to put in the 94194334Sgshapiro ** string. 94294334Sgshapiro ** This is not an error. 94390792Sgshapiro */ 94490792Sgshapiro 94594334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && 94694334Sgshapiro bitset(SM_LDAP_SINGLEMATCH, flags) && 94794334Sgshapiro *result != NULL) 94894334Sgshapiro { 94994334Sgshapiro /* only wanted one match */ 95094334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 95194334Sgshapiro errno = ENOENT; 95294334Sgshapiro return EX_NOTFOUND; 95394334Sgshapiro } 95494334Sgshapiro 95590792Sgshapiro vsize = 0; 95690792Sgshapiro for (i = 0; vals[i] != NULL; i++) 95790792Sgshapiro { 95894334Sgshapiro if (type == SM_LDAP_ATTR_DN || 95994334Sgshapiro type == SM_LDAP_ATTR_FILTER || 96094334Sgshapiro type == SM_LDAP_ATTR_URL) 96190792Sgshapiro { 96294334Sgshapiro /* add to recursion */ 96394334Sgshapiro if (sm_ldap_add_recurse(&recurse, 96490792Sgshapiro vals[i], 96594334Sgshapiro type, 96694334Sgshapiro rpool) == NULL) 96790792Sgshapiro { 96894334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 96990792Sgshapiro errno = ENOMEM; 97090792Sgshapiro return EX_OSERR; 97190792Sgshapiro } 97290792Sgshapiro continue; 97390792Sgshapiro } 97494334Sgshapiro 97590792Sgshapiro vsize += strlen(vals[i]) + 1; 97690792Sgshapiro if (lmap->ldap_attrsep != '\0') 97790792Sgshapiro vsize += strlen(attr) + 1; 97890792Sgshapiro } 97990792Sgshapiro 98094334Sgshapiro /* 98194334Sgshapiro ** Create/Append to string any normal 98294334Sgshapiro ** attribute values. Otherwise, just free 98394334Sgshapiro ** memory and move on to the next 98494334Sgshapiro ** attribute in this entry. 98594334Sgshapiro */ 98694334Sgshapiro 98794334Sgshapiro if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) 98890792Sgshapiro { 98994334Sgshapiro char *pe; 99094334Sgshapiro 99194334Sgshapiro /* Grow result string if needed */ 99294334Sgshapiro if ((*resultln + vsize) >= *resultsz) 99390792Sgshapiro { 99494334Sgshapiro while ((*resultln + vsize) >= *resultsz) 99594334Sgshapiro { 99694334Sgshapiro if (*resultsz == 0) 99794334Sgshapiro *resultsz = 1024; 99894334Sgshapiro else 99994334Sgshapiro *resultsz *= 2; 100094334Sgshapiro } 100194334Sgshapiro 100294334Sgshapiro vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); 100394334Sgshapiro *vp_tmp = '\0'; 100494334Sgshapiro 100594334Sgshapiro if (*result != NULL) 100694334Sgshapiro sm_strlcpy(vp_tmp, 100794334Sgshapiro *result, 100894334Sgshapiro *resultsz); 100994334Sgshapiro *result = vp_tmp; 101090792Sgshapiro } 101194334Sgshapiro 101294334Sgshapiro p = *result + *resultln; 101394334Sgshapiro pe = *result + *resultsz; 101494334Sgshapiro 101594334Sgshapiro for (i = 0; vals[i] != NULL; i++) 101690792Sgshapiro { 1017102528Sgshapiro if (*resultln > 0 && 1018102528Sgshapiro p < pe) 101994334Sgshapiro *p++ = (char) delim; 102094334Sgshapiro 102194334Sgshapiro if (lmap->ldap_attrsep != '\0') 102294334Sgshapiro { 102394334Sgshapiro p += sm_strlcpy(p, attr, 102494334Sgshapiro pe - p); 102594334Sgshapiro if (p < pe) 102694334Sgshapiro *p++ = lmap->ldap_attrsep; 102794334Sgshapiro } 102894334Sgshapiro 102994334Sgshapiro p += sm_strlcpy(p, vals[i], 103094334Sgshapiro pe - p); 103194334Sgshapiro *resultln = p - (*result); 103294334Sgshapiro if (p >= pe) 103394334Sgshapiro { 103494334Sgshapiro /* Internal error: buffer too small for LDAP values */ 103594334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 103694334Sgshapiro errno = ENOMEM; 103794334Sgshapiro return EX_OSERR; 103894334Sgshapiro } 103990792Sgshapiro } 104090792Sgshapiro } 104190792Sgshapiro 104290792Sgshapiro ldap_value_free(vals); 104390792Sgshapiro ldap_memfree(attr); 104490792Sgshapiro } 104590792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 104690792Sgshapiro 104790792Sgshapiro /* 104890792Sgshapiro ** We check save_errno != LDAP_DECODING_ERROR since 104990792Sgshapiro ** OpenLDAP 1.X has a very ugly *undocumented* 105090792Sgshapiro ** hack of returning this error code from 105190792Sgshapiro ** ldap_next_attribute() if the library freed the 105290792Sgshapiro ** ber attribute. See: 105390792Sgshapiro ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 105490792Sgshapiro */ 105590792Sgshapiro 105690792Sgshapiro if (save_errno != LDAP_SUCCESS && 105790792Sgshapiro save_errno != LDAP_DECODING_ERROR) 105890792Sgshapiro { 105990792Sgshapiro /* Must be an error */ 106090792Sgshapiro save_errno += E_LDAPBASE; 106194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 106290792Sgshapiro errno = save_errno; 106390792Sgshapiro return EX_TEMPFAIL; 106490792Sgshapiro } 106590792Sgshapiro 106694334Sgshapiro /* mark this DN as done */ 106794334Sgshapiro rl->lr_done = true; 1068132943Sgshapiro if (rl->lr_ludp != NULL) 1069132943Sgshapiro { 1070132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 1071132943Sgshapiro rl->lr_ludp = NULL; 1072132943Sgshapiro } 1073132943Sgshapiro if (rl->lr_attrs != NULL) 1074132943Sgshapiro { 1075132943Sgshapiro free(rl->lr_attrs); 1076132943Sgshapiro rl->lr_attrs = NULL; 1077132943Sgshapiro } 107894334Sgshapiro 107990792Sgshapiro /* We don't want multiple values and we have one */ 1080147078Sgshapiro if ((char) delim == '\0' && 1081147078Sgshapiro !bitset(SM_LDAP_SINGLEMATCH, flags) && 1082147078Sgshapiro *result != NULL) 108390792Sgshapiro break; 108490792Sgshapiro } 108590792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 108690792Sgshapiro if (save_errno != LDAP_SUCCESS && 108790792Sgshapiro save_errno != LDAP_DECODING_ERROR) 108890792Sgshapiro { 108990792Sgshapiro /* Must be an error */ 109090792Sgshapiro save_errno += E_LDAPBASE; 109194334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 109290792Sgshapiro errno = save_errno; 109390792Sgshapiro return EX_TEMPFAIL; 109490792Sgshapiro } 109590792Sgshapiro ldap_msgfree(lmap->ldap_res); 109690792Sgshapiro lmap->ldap_res = NULL; 109790792Sgshapiro } 109890792Sgshapiro 109990792Sgshapiro if (ret == 0) 110090792Sgshapiro save_errno = ETIMEDOUT; 1101223067Sgshapiro else if (ret == LDAP_RES_SEARCH_RESULT) 1102203004Sgshapiro { 1103203004Sgshapiro /* 1104203004Sgshapiro ** We may have gotten an LDAP_RES_SEARCH_RESULT response 1105203004Sgshapiro ** with an error inside it, so we have to extract that 1106203004Sgshapiro ** with ldap_parse_result(). This can happen when talking 1107203004Sgshapiro ** to an LDAP proxy whose backend has gone down. 1108203004Sgshapiro */ 1109203004Sgshapiro 1110223067Sgshapiro if (lmap->ldap_res == NULL) 1111223067Sgshapiro save_errno = LDAP_UNAVAILABLE; 1112223067Sgshapiro else 1113223067Sgshapiro { 1114223067Sgshapiro int rc; 1115223067Sgshapiro 1116223067Sgshapiro save_errno = ldap_parse_result(lmap->ldap_ld, 1117223067Sgshapiro lmap->ldap_res, &rc, NULL, NULL, 1118223067Sgshapiro NULL, NULL, 0); 1119223067Sgshapiro if (save_errno == LDAP_SUCCESS) 1120223067Sgshapiro save_errno = rc; 1121223067Sgshapiro } 1122203004Sgshapiro } 1123223067Sgshapiro else 1124223067Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 112590792Sgshapiro if (save_errno != LDAP_SUCCESS) 112690792Sgshapiro { 112790792Sgshapiro statp = EX_TEMPFAIL; 1128173340Sgshapiro switch (save_errno) 112990792Sgshapiro { 113090792Sgshapiro#ifdef LDAP_SERVER_DOWN 1131173340Sgshapiro case LDAP_SERVER_DOWN: 113290792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 1133173340Sgshapiro case LDAP_TIMEOUT: 1134173340Sgshapiro case ETIMEDOUT: 1135173340Sgshapiro case LDAP_UNAVAILABLE: 113694334Sgshapiro 1137173340Sgshapiro /* 1138173340Sgshapiro ** server disappeared, 1139173340Sgshapiro ** try reopen on next search 1140173340Sgshapiro */ 114194334Sgshapiro 1142173340Sgshapiro statp = EX_RESTART; 1143173340Sgshapiro break; 1144173340Sgshapiro } 1145173340Sgshapiro if (ret != 0) 114690792Sgshapiro save_errno += E_LDAPBASE; 114794334Sgshapiro SM_LDAP_ERROR_CLEANUP(); 114890792Sgshapiro errno = save_errno; 114990792Sgshapiro return statp; 115090792Sgshapiro } 115190792Sgshapiro 115290792Sgshapiro if (lmap->ldap_res != NULL) 115390792Sgshapiro { 115490792Sgshapiro ldap_msgfree(lmap->ldap_res); 115590792Sgshapiro lmap->ldap_res = NULL; 115690792Sgshapiro } 115790792Sgshapiro 115890792Sgshapiro if (toplevel) 115990792Sgshapiro { 116094334Sgshapiro int rlidx; 116190792Sgshapiro 116290792Sgshapiro /* 116390792Sgshapiro ** Spin through the built-up recurse list at the top 116490792Sgshapiro ** of the recursion. Since new items are added at the 116590792Sgshapiro ** end of the shared list, we actually only ever get 116690792Sgshapiro ** one level of recursion before things pop back to the 116790792Sgshapiro ** top. Any items added to the list during that recursion 116890792Sgshapiro ** will be expanded by the top level. 116990792Sgshapiro */ 117090792Sgshapiro 1171168515Sgshapiro for (rlidx = 0; recurse != NULL && rlidx < recurse->lrl_cnt; 1172168515Sgshapiro rlidx++) 117390792Sgshapiro { 117494334Sgshapiro int newflags; 117590792Sgshapiro int sid; 117690792Sgshapiro int status; 117790792Sgshapiro 1178168515Sgshapiro rl = recurse->lrl_data[rlidx]; 117994334Sgshapiro 118094334Sgshapiro newflags = flags; 118194334Sgshapiro if (rl->lr_done) 118290792Sgshapiro { 118390792Sgshapiro /* already expanded */ 118490792Sgshapiro continue; 118590792Sgshapiro } 118694334Sgshapiro 118794334Sgshapiro if (rl->lr_type == SM_LDAP_ATTR_DN) 118890792Sgshapiro { 118990792Sgshapiro /* do DN search */ 119090792Sgshapiro sid = ldap_search(lmap->ldap_ld, 119190792Sgshapiro rl->lr_search, 119290792Sgshapiro lmap->ldap_scope, 119390792Sgshapiro "(objectClass=*)", 119494334Sgshapiro (lmap->ldap_attr[0] == NULL ? 119594334Sgshapiro NULL : lmap->ldap_attr), 119690792Sgshapiro lmap->ldap_attrsonly); 119790792Sgshapiro } 119894334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_FILTER) 119990792Sgshapiro { 120090792Sgshapiro /* do new search */ 120190792Sgshapiro sid = ldap_search(lmap->ldap_ld, 120290792Sgshapiro lmap->ldap_base, 120390792Sgshapiro lmap->ldap_scope, 120490792Sgshapiro rl->lr_search, 120594334Sgshapiro (lmap->ldap_attr[0] == NULL ? 120694334Sgshapiro NULL : lmap->ldap_attr), 120790792Sgshapiro lmap->ldap_attrsonly); 120890792Sgshapiro } 120994334Sgshapiro else if (rl->lr_type == SM_LDAP_ATTR_URL) 121090792Sgshapiro { 1211132943Sgshapiro /* Parse URL */ 1212132943Sgshapiro sid = ldap_url_parse(rl->lr_search, 1213132943Sgshapiro &rl->lr_ludp); 1214132943Sgshapiro 1215132943Sgshapiro if (sid != 0) 1216132943Sgshapiro { 1217132943Sgshapiro errno = sid + E_LDAPURLBASE; 1218132943Sgshapiro return EX_TEMPFAIL; 1219132943Sgshapiro } 1220132943Sgshapiro 1221132943Sgshapiro /* We need to add objectClass */ 1222132943Sgshapiro if (rl->lr_ludp->lud_attrs != NULL) 1223132943Sgshapiro { 1224132943Sgshapiro int attrnum = 0; 1225132943Sgshapiro 1226132943Sgshapiro while (rl->lr_ludp->lud_attrs[attrnum] != NULL) 1227132943Sgshapiro { 1228132943Sgshapiro if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum], 1229132943Sgshapiro "objectClass") == 0) 1230132943Sgshapiro { 1231132943Sgshapiro /* already requested */ 1232132943Sgshapiro attrnum = -1; 1233132943Sgshapiro break; 1234132943Sgshapiro } 1235132943Sgshapiro attrnum++; 1236132943Sgshapiro } 1237132943Sgshapiro 1238132943Sgshapiro if (attrnum >= 0) 1239132943Sgshapiro { 1240132943Sgshapiro int i; 1241132943Sgshapiro 1242132943Sgshapiro rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2)); 1243132943Sgshapiro if (rl->lr_attrs == NULL) 1244132943Sgshapiro { 1245132943Sgshapiro save_errno = errno; 1246132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 1247132943Sgshapiro errno = save_errno; 1248132943Sgshapiro return EX_TEMPFAIL; 1249132943Sgshapiro } 1250132943Sgshapiro for (i = 0 ; i < attrnum; i++) 1251132943Sgshapiro { 1252132943Sgshapiro rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i]; 1253132943Sgshapiro } 1254132943Sgshapiro rl->lr_attrs[i++] = "objectClass"; 1255132943Sgshapiro rl->lr_attrs[i++] = NULL; 1256132943Sgshapiro } 1257132943Sgshapiro } 1258132943Sgshapiro 1259132943Sgshapiro /* 1260132943Sgshapiro ** Use the existing connection 1261132943Sgshapiro ** for this search. It really 1262132943Sgshapiro ** should use lud_scheme://lud_host:lud_port/ 1263132943Sgshapiro ** instead but that would require 1264132943Sgshapiro ** opening a new connection. 1265132943Sgshapiro ** This should be fixed ASAP. 1266132943Sgshapiro */ 1267132943Sgshapiro 1268132943Sgshapiro sid = ldap_search(lmap->ldap_ld, 1269132943Sgshapiro rl->lr_ludp->lud_dn, 1270132943Sgshapiro rl->lr_ludp->lud_scope, 1271132943Sgshapiro rl->lr_ludp->lud_filter, 1272132943Sgshapiro rl->lr_attrs, 1273132943Sgshapiro lmap->ldap_attrsonly); 1274132943Sgshapiro 1275132943Sgshapiro /* Use the attributes specified by URL */ 127694334Sgshapiro newflags |= SM_LDAP_USE_ALLATTR; 127790792Sgshapiro } 127890792Sgshapiro else 127990792Sgshapiro { 128090792Sgshapiro /* unknown or illegal attribute type */ 128190792Sgshapiro errno = EFAULT; 128290792Sgshapiro return EX_SOFTWARE; 128390792Sgshapiro } 128490792Sgshapiro 128590792Sgshapiro /* Collect results */ 128690792Sgshapiro if (sid == -1) 128790792Sgshapiro { 128890792Sgshapiro save_errno = sm_ldap_geterrno(lmap->ldap_ld); 128990792Sgshapiro statp = EX_TEMPFAIL; 129090792Sgshapiro switch (save_errno) 129190792Sgshapiro { 129290792Sgshapiro#ifdef LDAP_SERVER_DOWN 129390792Sgshapiro case LDAP_SERVER_DOWN: 129490792Sgshapiro#endif /* LDAP_SERVER_DOWN */ 129590792Sgshapiro case LDAP_TIMEOUT: 1296173340Sgshapiro case ETIMEDOUT: 129790792Sgshapiro case LDAP_UNAVAILABLE: 129894334Sgshapiro 129994334Sgshapiro /* 130094334Sgshapiro ** server disappeared, 130194334Sgshapiro ** try reopen on next search 130294334Sgshapiro */ 130394334Sgshapiro 130490792Sgshapiro statp = EX_RESTART; 130590792Sgshapiro break; 130690792Sgshapiro } 130790792Sgshapiro errno = save_errno + E_LDAPBASE; 130890792Sgshapiro return statp; 130990792Sgshapiro } 131090792Sgshapiro 131194334Sgshapiro status = sm_ldap_results(lmap, sid, newflags, delim, 131294334Sgshapiro rpool, result, resultln, 131394334Sgshapiro resultsz, recurse); 131490792Sgshapiro save_errno = errno; 131590792Sgshapiro if (status != EX_OK && status != EX_NOTFOUND) 131690792Sgshapiro { 131790792Sgshapiro errno = save_errno; 131890792Sgshapiro return status; 131990792Sgshapiro } 132090792Sgshapiro 132190792Sgshapiro /* Mark as done */ 132294334Sgshapiro rl->lr_done = true; 1323132943Sgshapiro if (rl->lr_ludp != NULL) 1324132943Sgshapiro { 1325132943Sgshapiro ldap_free_urldesc(rl->lr_ludp); 1326132943Sgshapiro rl->lr_ludp = NULL; 1327132943Sgshapiro } 1328132943Sgshapiro if (rl->lr_attrs != NULL) 1329132943Sgshapiro { 1330132943Sgshapiro free(rl->lr_attrs); 1331132943Sgshapiro rl->lr_attrs = NULL; 1332132943Sgshapiro } 133394334Sgshapiro 133494334Sgshapiro /* Reset rlidx as new items may have been added */ 133594334Sgshapiro rlidx = -1; 133690792Sgshapiro } 133790792Sgshapiro } 133890792Sgshapiro return statp; 133990792Sgshapiro} 134090792Sgshapiro 134190792Sgshapiro/* 134290792Sgshapiro** SM_LDAP_CLOSE -- close LDAP connection 134390792Sgshapiro** 134490792Sgshapiro** Parameters: 134590792Sgshapiro** lmap -- LDAP map information 134690792Sgshapiro** 134790792Sgshapiro** Returns: 134890792Sgshapiro** None. 134990792Sgshapiro** 135090792Sgshapiro*/ 135190792Sgshapiro 135290792Sgshapirovoid 135390792Sgshapirosm_ldap_close(lmap) 135490792Sgshapiro SM_LDAP_STRUCT *lmap; 135590792Sgshapiro{ 135690792Sgshapiro if (lmap->ldap_ld == NULL) 135790792Sgshapiro return; 135890792Sgshapiro 135990792Sgshapiro if (lmap->ldap_pid == getpid()) 136090792Sgshapiro ldap_unbind(lmap->ldap_ld); 136190792Sgshapiro lmap->ldap_ld = NULL; 136290792Sgshapiro lmap->ldap_pid = 0; 136390792Sgshapiro} 136490792Sgshapiro 136590792Sgshapiro/* 136690792Sgshapiro** SM_LDAP_SETOPTS -- set LDAP options 136790792Sgshapiro** 136890792Sgshapiro** Parameters: 136990792Sgshapiro** ld -- LDAP session handle 137090792Sgshapiro** lmap -- LDAP map information 137190792Sgshapiro** 137290792Sgshapiro** Returns: 137390792Sgshapiro** None. 137490792Sgshapiro** 137590792Sgshapiro*/ 137690792Sgshapiro 137790792Sgshapirovoid 137890792Sgshapirosm_ldap_setopts(ld, lmap) 137990792Sgshapiro LDAP *ld; 138090792Sgshapiro SM_LDAP_STRUCT *lmap; 138190792Sgshapiro{ 138290792Sgshapiro# if USE_LDAP_SET_OPTION 138394334Sgshapiro if (lmap->ldap_version != 0) 138494334Sgshapiro { 138594334Sgshapiro ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 138694334Sgshapiro &lmap->ldap_version); 138794334Sgshapiro } 138890792Sgshapiro ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 138990792Sgshapiro if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 139090792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 139190792Sgshapiro else 139290792Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 139390792Sgshapiro ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 139490792Sgshapiro ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 1395203004Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT) 1396203004Sgshapiro if (lmap->ldap_networktmo > 0) 1397203004Sgshapiro { 1398203004Sgshapiro struct timeval tmo; 1399203004Sgshapiro 1400203004Sgshapiro tmo.tv_sec = lmap->ldap_networktmo; 1401203004Sgshapiro tmo.tv_usec = 0; 1402203004Sgshapiro ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tmo); 1403203004Sgshapiro } 1404203004Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT) */ 1405102528Sgshapiro# ifdef LDAP_OPT_RESTART 1406102528Sgshapiro ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1407102528Sgshapiro# endif /* LDAP_OPT_RESTART */ 140890792Sgshapiro# else /* USE_LDAP_SET_OPTION */ 140990792Sgshapiro /* From here on in we can use ldap internal timelimits */ 141090792Sgshapiro ld->ld_deref = lmap->ldap_deref; 141190792Sgshapiro ld->ld_options = lmap->ldap_options; 141290792Sgshapiro ld->ld_sizelimit = lmap->ldap_sizelimit; 141390792Sgshapiro ld->ld_timelimit = lmap->ldap_timelimit; 141490792Sgshapiro# endif /* USE_LDAP_SET_OPTION */ 141590792Sgshapiro} 141690792Sgshapiro 141790792Sgshapiro/* 141890792Sgshapiro** SM_LDAP_GETERRNO -- get ldap errno value 141990792Sgshapiro** 142090792Sgshapiro** Parameters: 142190792Sgshapiro** ld -- LDAP session handle 142290792Sgshapiro** 142390792Sgshapiro** Returns: 142490792Sgshapiro** LDAP errno. 142590792Sgshapiro** 142690792Sgshapiro*/ 142790792Sgshapiro 142890792Sgshapiroint 142990792Sgshapirosm_ldap_geterrno(ld) 143090792Sgshapiro LDAP *ld; 143190792Sgshapiro{ 143290792Sgshapiro int err = LDAP_SUCCESS; 143390792Sgshapiro 143490792Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 143590792Sgshapiro (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 143690792Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 143790792Sgshapiro# ifdef LDAP_OPT_SIZELIMIT 143890792Sgshapiro err = ldap_get_lderrno(ld, NULL, NULL); 143990792Sgshapiro# else /* LDAP_OPT_SIZELIMIT */ 144090792Sgshapiro err = ld->ld_errno; 144190792Sgshapiro 144290792Sgshapiro /* 144390792Sgshapiro ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 144490792Sgshapiro ** OpenLDAP 1.X's hack (see above) 144590792Sgshapiro */ 144690792Sgshapiro 144790792Sgshapiro ld->ld_errno = LDAP_SUCCESS; 144890792Sgshapiro# endif /* LDAP_OPT_SIZELIMIT */ 144990792Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 145090792Sgshapiro return err; 145190792Sgshapiro} 145290792Sgshapiro# endif /* LDAPMAP */ 1453