diff options
Diffstat (limited to 'contrib/sendmail/libsm/ldap.c')
-rw-r--r-- | contrib/sendmail/libsm/ldap.c | 961 |
1 files changed, 961 insertions, 0 deletions
diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c new file mode 100644 index 0000000..a431511 --- /dev/null +++ b/contrib/sendmail/libsm/ldap.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $") + +#if LDAPMAP +# include <sys/types.h> +# include <errno.h> +# include <setjmp.h> +# include <stdlib.h> +# include <unistd.h> + +# include <sm/bitops.h> +# include <sm/clock.h> +# include <sm/conf.h> +# include <sm/debug.h> +# include <sm/errstring.h> +# include <sm/ldap.h> +# include <sm/string.h> +# include <sm/sysexits.h> + +SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", + "@(#)$Debug: sm_trace_ldap - trace LDAP operations $"); + +static void ldaptimeout __P((int)); + +/* +** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT +** +** Parameters: +** lmap -- pointer to SM_LDAP_STRUCT to clear +** +** Returns: +** None. +** +*/ + +void +sm_ldap_clear(lmap) + SM_LDAP_STRUCT *lmap; +{ + if (lmap == NULL) + return; + + lmap->ldap_host = NULL; + lmap->ldap_port = LDAP_PORT; + lmap->ldap_deref = LDAP_DEREF_NEVER; + lmap->ldap_timelimit = LDAP_NO_LIMIT; + lmap->ldap_sizelimit = LDAP_NO_LIMIT; +# ifdef LDAP_REFERRALS + lmap->ldap_options = LDAP_OPT_REFERRALS; +# else /* LDAP_REFERRALS */ + lmap->ldap_options = 0; +# endif /* LDAP_REFERRALS */ + lmap->ldap_attrsep = '\0'; + lmap->ldap_binddn = NULL; + lmap->ldap_secret = NULL; + lmap->ldap_method = LDAP_AUTH_SIMPLE; + lmap->ldap_base = NULL; + lmap->ldap_scope = LDAP_SCOPE_SUBTREE; + lmap->ldap_attrsonly = LDAPMAP_FALSE; + lmap->ldap_timeout.tv_sec = 0; + lmap->ldap_timeout.tv_usec = 0; + lmap->ldap_ld = NULL; + lmap->ldap_filter = NULL; + lmap->ldap_attr[0] = NULL; +#if _FFR_LDAP_RECURSION + lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL; + lmap->ldap_attr_final[0] = NULL; +#endif /* _FFR_LDAP_RECURSION */ + lmap->ldap_res = NULL; + lmap->ldap_next = NULL; + lmap->ldap_pid = 0; +} + +/* +** SM_LDAP_START -- actually connect to an LDAP server +** +** Parameters: +** name -- name of map for debug output. +** lmap -- the LDAP map being opened. +** +** Returns: +** true if connection is successful, false otherwise. +** +** Side Effects: +** Populates lmap->ldap_ld. +*/ + +static jmp_buf LDAPTimeout; + +#define SM_LDAP_SETTIMEOUT(to) \ +do \ +{ \ + if (to != 0) \ + { \ + if (setjmp(LDAPTimeout) != 0) \ + { \ + errno = ETIMEDOUT; \ + return false; \ + } \ + ev = sm_setevent(to, ldaptimeout, 0); \ + } \ +} while (0) + +#define SM_LDAP_CLEARTIMEOUT() \ +do \ +{ \ + if (ev != NULL) \ + sm_clrevent(ev); \ +} while (0) + +bool +sm_ldap_start(name, lmap) + char *name; + SM_LDAP_STRUCT *lmap; +{ + int bind_result; + int save_errno; + SM_EVENT *ev = NULL; + LDAP *ld; + + if (sm_debug_active(&SmLDAPTrace, 2)) + sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); + + if (sm_debug_active(&SmLDAPTrace, 9)) + sm_dprintf("ldapmap_start(%s, %d)\n", + lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host, + lmap->ldap_port); + +# if USE_LDAP_INIT + ld = ldap_init(lmap->ldap_host, lmap->ldap_port); + save_errno = errno; +# else /* USE_LDAP_INIT */ + /* + ** If using ldap_open(), the actual connection to the server + ** happens now so we need the timeout here. For ldap_init(), + ** the connection happens at bind time. + */ + + SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); + ld = ldap_open(lmap->ldap_host, lmap->ldap_port); + save_errno = errno; + + /* clear the event if it has not sprung */ + SM_LDAP_CLEARTIMEOUT(); +# endif /* USE_LDAP_INIT */ + + errno = save_errno; + if (ld == NULL) + return false; + + sm_ldap_setopts(ld, lmap); + +# if USE_LDAP_INIT + /* + ** If using ldap_init(), the actual connection to the server + ** happens at ldap_bind_s() so we need the timeout here. + */ + + SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); +# endif /* USE_LDAP_INIT */ + +# ifdef LDAP_AUTH_KRBV4 + if (lmap->ldap_method == LDAP_AUTH_KRBV4 && + lmap->ldap_secret != NULL) + { + /* + ** Need to put ticket in environment here instead of + ** during parseargs as there may be different tickets + ** for different LDAP connections. + */ + + (void) putenv(lmap->ldap_secret); + } +# endif /* LDAP_AUTH_KRBV4 */ + + bind_result = ldap_bind_s(ld, lmap->ldap_binddn, + lmap->ldap_secret, lmap->ldap_method); + +# if USE_LDAP_INIT + /* clear the event if it has not sprung */ + SM_LDAP_CLEARTIMEOUT(); +# endif /* USE_LDAP_INIT */ + + if (bind_result != LDAP_SUCCESS) + { + errno = bind_result + E_LDAPBASE; + return false; + } + + /* Save PID to make sure only this PID closes the LDAP connection */ + lmap->ldap_pid = getpid(); + lmap->ldap_ld = ld; + return true; +} + +/* ARGSUSED */ +static void +ldaptimeout(unused) + int unused; +{ + /* + ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD + ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE + ** DOING. + */ + + errno = ETIMEDOUT; + longjmp(LDAPTimeout, 1); +} + +/* +** SM_LDAP_SEARCH -- iniate LDAP search +** +** Initiate an LDAP search, return the msgid. +** The calling function must collect the results. +** +** Parameters: +** lmap -- LDAP map information +** key -- key to substitute in LDAP filter +** +** Returns: +** -1 on failure, msgid on success +** +*/ + +int +sm_ldap_search(lmap, key) + SM_LDAP_STRUCT *lmap; + char *key; +{ + int msgid; + char *fp, *p, *q; + char filter[LDAPMAP_MAX_FILTER + 1]; + + /* substitute key into filter, perhaps multiple times */ + memset(filter, '\0', sizeof filter); + fp = filter; + p = lmap->ldap_filter; + while ((q = strchr(p, '%')) != NULL) + { + if (q[1] == 's') + { + (void) sm_snprintf(fp, SPACELEFT(filter, fp), + "%.*s%s", (int) (q - p), p, key); + fp += strlen(fp); + p = q + 2; + } + else if (q[1] == '0') + { + char *k = key; + + (void) sm_snprintf(fp, SPACELEFT(filter, fp), + "%.*s", (int) (q - p), p); + fp += strlen(fp); + p = q + 2; + + /* Properly escape LDAP special characters */ + while (SPACELEFT(filter, fp) > 0 && + *k != '\0') + { + if (*k == '*' || *k == '(' || + *k == ')' || *k == '\\') + { + (void) sm_strlcat(fp, + (*k == '*' ? "\\2A" : + (*k == '(' ? "\\28" : + (*k == ')' ? "\\29" : + (*k == '\\' ? "\\5C" : + "\00")))), + SPACELEFT(filter, fp)); + fp += strlen(fp); + k++; + } + else + *fp++ = *k++; + } + } + else + { + (void) sm_snprintf(fp, SPACELEFT(filter, fp), + "%.*s", (int) (q - p + 1), p); + p = q + (q[1] == '%' ? 2 : 1); + fp += strlen(fp); + } + } + (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp)); + if (sm_debug_active(&SmLDAPTrace, 20)) + sm_dprintf("ldap search filter=%s\n", filter); + + lmap->ldap_res = NULL; + msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope, + filter, + (lmap->ldap_attr[0] == NULL ? NULL : + lmap->ldap_attr), + lmap->ldap_attrsonly); + return msgid; +} + +# if _FFR_LDAP_RECURSION +/* +** SM_LDAP_RESULTS -- return results from an LDAP lookup in result +** +** Parameters: +** lmap -- pointer to SM_LDAP_STRUCT in use +** msgid -- msgid returned by sm_ldap_search() +** flags -- flags for the lookup +** delim -- delimiter for result concatenation +** rpool -- memory pool for storage +** result -- return string +** recurse -- recursion list +** +** Returns: +** status (sysexit) +*/ + +# define LDAPMAP_ERROR_CLEANUP() \ +{ \ + if (lmap->ldap_res != NULL) \ + { \ + ldap_msgfree(lmap->ldap_res); \ + lmap->ldap_res = NULL; \ + } \ + (void) ldap_abandon(lmap->ldap_ld, msgid); \ +} + +static int +ldapmap_add_recurse(top, item, type, rpool) + SM_LDAP_RECURSE_LIST **top; + char *item; + int type; + SM_RPOOL_T *rpool; +{ + SM_LDAP_RECURSE_LIST *p; + SM_LDAP_RECURSE_LIST *last; + + last = NULL; + for (p = *top; p != NULL; p = p->lr_next) + { + if (strcasecmp(item, p->lr_search) == 0 && + type == p->lr_type) + { + /* already on list */ + return 1; + } + last = p; + } + + /* not on list, add it */ + p = sm_rpool_malloc_x(rpool, sizeof *p); + p->lr_search = sm_rpool_strdup_x(rpool, item); + p->lr_type = type; + p->lr_next = NULL; + if (last == NULL) + *top = p; + else + last->lr_next = p; + return 0; +} + +int +sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse) + SM_LDAP_STRUCT *lmap; + int msgid; + int flags; + char delim; + SM_RPOOL_T *rpool; + char **result; + SM_LDAP_RECURSE_LIST *recurse; +{ + bool toplevel; + int i; + int entries = 0; + int statp; + int vsize; + int ret; + int save_errno; + char *p; + + /* Are we the top top level of the search? */ + toplevel = (recurse == NULL); + + /* Get results */ + statp = EX_NOTFOUND; + while ((ret = ldap_result(lmap->ldap_ld, msgid, 0, + (lmap->ldap_timeout.tv_sec == 0 ? NULL : + &(lmap->ldap_timeout)), + &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) + { + LDAPMessage *entry; + + if (bitset(SM_LDAP_SINGLEMATCH, flags)) + { + entries += ldap_count_entries(lmap->ldap_ld, + lmap->ldap_res); + if (entries > 1) + { + LDAPMAP_ERROR_CLEANUP(); + errno = ENOENT; + return EX_NOTFOUND; + } + } + + /* If we don't want multiple values and we have one, break */ + if (delim == '\0' && *result != NULL) + break; + + /* Cycle through all entries */ + for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); + entry != NULL; + entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) + { + BerElement *ber; + char *attr; + char **vals = NULL; + char *dn; + + /* + ** If matching only and found an entry, + ** no need to spin through attributes + */ + + if (statp == EX_OK && + bitset(SM_LDAP_MATCHONLY, flags)) + continue; + + /* record completed DN's to prevent loops */ + dn = ldap_get_dn(lmap->ldap_ld, entry); + if (dn == NULL) + { + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + save_errno += E_LDAPBASE; + LDAPMAP_ERROR_CLEANUP(); + errno = save_errno; + return EX_OSERR; + } + + switch (ldapmap_add_recurse(&recurse, dn, + LDAPMAP_ATTR_NORMAL, + rpool)) + { + case -1: + /* error adding */ + ldap_memfree(dn); + LDAPMAP_ERROR_CLEANUP(); + errno = ENOMEM; + return EX_OSERR; + + case 1: + /* already on list, skip it */ + ldap_memfree(dn); + continue; + } + ldap_memfree(dn); + +# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) + /* + ** Reset value to prevent lingering + ** LDAP_DECODING_ERROR due to + ** OpenLDAP 1.X's hack (see below) + */ + + lmap->ldap_ld->ld_errno = LDAP_SUCCESS; +# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ + + for (attr = ldap_first_attribute(lmap->ldap_ld, entry, + &ber); + attr != NULL; + attr = ldap_next_attribute(lmap->ldap_ld, entry, + ber)) + { + char *tmp, *vp_tmp; + int type; + + for (i = 0; lmap->ldap_attr[i] != NULL; i++) + { + if (sm_strcasecmp(lmap->ldap_attr[i], + attr) == 0) + { + type = lmap->ldap_attr_type[i]; + break; + } + } + if (lmap->ldap_attr[i] == NULL) + { + /* attribute not requested */ +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + LDAPMAP_ERROR_CLEANUP(); + errno = EFAULT; + return EX_SOFTWARE; + } + + if (lmap->ldap_attrsonly == LDAPMAP_FALSE) + { + vals = ldap_get_values(lmap->ldap_ld, + entry, + attr); + if (vals == NULL) + { + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + if (save_errno == LDAP_SUCCESS) + { +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + continue; + } + + /* Must be an error */ + save_errno += E_LDAPBASE; +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + LDAPMAP_ERROR_CLEANUP(); + errno = save_errno; + return EX_TEMPFAIL; + } + } + + statp = EX_OK; + +# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) + /* + ** Reset value to prevent lingering + ** LDAP_DECODING_ERROR due to + ** OpenLDAP 1.X's hack (see below) + */ + + lmap->ldap_ld->ld_errno = LDAP_SUCCESS; +# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ + + /* + ** If matching only, + ** no need to spin through entries + */ + + if (bitset(SM_LDAP_MATCHONLY, flags)) + { + if (lmap->ldap_attrsonly == LDAPMAP_FALSE) + ldap_value_free(vals); + +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + continue; + } + + /* + ** If we don't want multiple values, + ** return first found. + */ + + if (delim == '\0') + { + if (lmap->ldap_attrsonly == LDAPMAP_TRUE) + { + *result = sm_rpool_strdup_x(rpool, + attr); +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + break; + } + + if (vals[0] == NULL) + { + ldap_value_free(vals); +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + continue; + } + + vsize = strlen(vals[0]) + 1; + if (lmap->ldap_attrsep != '\0') + vsize += strlen(attr) + 1; + *result = sm_rpool_malloc_x(rpool, + vsize); + if (lmap->ldap_attrsep != '\0') + sm_snprintf(*result, vsize, + "%s%c%s", + attr, + lmap->ldap_attrsep, + vals[0]); + else + sm_strlcpy(*result, vals[0], + vsize); + ldap_value_free(vals); +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + break; + } + + /* attributes only */ + if (lmap->ldap_attrsonly == LDAPMAP_TRUE) + { + if (*result == NULL) + *result = sm_rpool_strdup_x(rpool, + attr); + else + { + vsize = strlen(*result) + + strlen(attr) + 2; + tmp = sm_rpool_malloc_x(rpool, + vsize); + (void) sm_snprintf(tmp, + vsize, "%s%c%s", + *result, delim, + attr); + *result = tmp; + } +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + continue; + } + + /* + ** If there is more than one, + ** munge then into a map_coldelim + ** separated string + */ + + vsize = 0; + for (i = 0; vals[i] != NULL; i++) + { + if (type == LDAPMAP_ATTR_DN || + type == LDAPMAP_ATTR_FILTER || + type == LDAPMAP_ATTR_URL) + { + if (ldapmap_add_recurse(&recurse, + vals[i], + type) < 0) + { + LDAPMAP_ERROR_CLEANUP(); + errno = ENOMEM; + return EX_OSERR; + } + } + if (type != LDAPMAP_ATTR_NORMAL) + { +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + continue; + } + vsize += strlen(vals[i]) + 1; + if (lmap->ldap_attrsep != '\0') + vsize += strlen(attr) + 1; + } + vp_tmp = sm_rpool_malloc_x(rpool, vsize); + *vp_tmp = '\0'; + + p = vp_tmp; + for (i = 0; vals[i] != NULL; i++) + { + if (lmap->ldap_attrsep != '\0') + { + p += sm_strlcpy(p, attr, + vsize - (p - vp_tmp)); + *p++ = lmap->ldap_attrsep; + } + p += sm_strlcpy(p, vals[i], + vsize - (p - vp_tmp)); + if (p >= vp_tmp + vsize) + { + /* Internal error: buffer too small for LDAP values */ + LDAPMAP_ERROR_CLEANUP(); + errno = ENOMEM; + return EX_OSERR; + } + if (vals[i + 1] != NULL) + *p++ = delim; + } + + ldap_value_free(vals); +# if USING_NETSCAPE_LDAP + ldap_memfree(attr); +# endif /* USING_NETSCAPE_LDAP */ + if (*result == NULL) + { + *result = vp_tmp; + continue; + } + vsize = strlen(*result) + strlen(vp_tmp) + 2; + tmp = sm_rpool_malloc_x(rpool, vsize); + (void) sm_snprintf(tmp, vsize, "%s%c%s", + *result, delim, vp_tmp); + *result = tmp; + } + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + + /* + ** We check save_errno != LDAP_DECODING_ERROR since + ** OpenLDAP 1.X has a very ugly *undocumented* + ** hack of returning this error code from + ** ldap_next_attribute() if the library freed the + ** ber attribute. See: + ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html + */ + + if (save_errno != LDAP_SUCCESS && + save_errno != LDAP_DECODING_ERROR) + { + /* Must be an error */ + save_errno += E_LDAPBASE; + LDAPMAP_ERROR_CLEANUP(); + errno = save_errno; + return EX_TEMPFAIL; + } + + /* We don't want multiple values and we have one */ + if (delim == '\0' && *result != NULL) + break; + } + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + if (save_errno != LDAP_SUCCESS && + save_errno != LDAP_DECODING_ERROR) + { + /* Must be an error */ + save_errno += E_LDAPBASE; + LDAPMAP_ERROR_CLEANUP(); + errno = save_errno; + return EX_TEMPFAIL; + } + ldap_msgfree(lmap->ldap_res); + lmap->ldap_res = NULL; + } + + if (ret == 0) + save_errno = ETIMEDOUT; + else + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + if (save_errno != LDAP_SUCCESS) + { + statp = EX_TEMPFAIL; + if (ret != 0) + { + switch (save_errno) + { +#ifdef LDAP_SERVER_DOWN + case LDAP_SERVER_DOWN: +#endif /* LDAP_SERVER_DOWN */ + case LDAP_TIMEOUT: + case LDAP_UNAVAILABLE: + /* server disappeared, try reopen on next search */ + statp = EX_RESTART; + break; + } + save_errno += E_LDAPBASE; + } + LDAPMAP_ERROR_CLEANUP(); + errno = save_errno; + return statp; + } + + if (lmap->ldap_res != NULL) + { + ldap_msgfree(lmap->ldap_res); + lmap->ldap_res = NULL; + } + + if (toplevel) + { + SM_LDAP_RECURSE_LIST *rl; + + /* + ** Spin through the built-up recurse list at the top + ** of the recursion. Since new items are added at the + ** end of the shared list, we actually only ever get + ** one level of recursion before things pop back to the + ** top. Any items added to the list during that recursion + ** will be expanded by the top level. + */ + + for (rl = recurse; rl != NULL; rl = rl->lr_next) + { + int sid; + int status; + + if (rl->lr_type == LDAPMAP_ATTR_NORMAL) + { + /* already expanded */ + continue; + } + else if (rl->lr_type == LDAPMAP_ATTR_DN) + { + /* do DN search */ + sid = ldap_search(lmap->ldap_ld, + rl->lr_search, + lmap->ldap_scope, + "(objectClass=*)", + lmap->ldap_attr_final, + lmap->ldap_attrsonly); + } + else if (rl->lr_type == LDAPMAP_ATTR_FILTER) + { + /* do new search */ + sid = ldap_search(lmap->ldap_ld, + lmap->ldap_base, + lmap->ldap_scope, + rl->lr_search, + lmap->ldap_attr_final, + lmap->ldap_attrsonly); + } + else if (rl->lr_type == LDAPMAP_ATTR_URL) + { + /* do new URL search */ + sid = ldap_url_search(lmap->ldap_ld, + rl->lr_search, + lmap->ldap_attrsonly); + } + else + { + /* unknown or illegal attribute type */ + errno = EFAULT; + return EX_SOFTWARE; + } + + /* Collect results */ + if (sid == -1) + { + save_errno = sm_ldap_geterrno(lmap->ldap_ld); + statp = EX_TEMPFAIL; + switch (save_errno) + { +#ifdef LDAP_SERVER_DOWN + case LDAP_SERVER_DOWN: +#endif /* LDAP_SERVER_DOWN */ + case LDAP_TIMEOUT: + case LDAP_UNAVAILABLE: + /* server disappeared, try reopen on next search */ + statp = EX_RESTART; + break; + } + errno = save_errno + E_LDAPBASE; + return statp; + } + + status = sm_ldap_results(lmap, sid, flags, delim, + rpool, result, recurse); + save_errno = errno; + if (status != EX_OK && status != EX_NOTFOUND) + { + errno = save_errno; + return status; + } + + /* Mark as done */ + rl->lr_type = LDAPMAP_ATTR_NORMAL; + } + } + return statp; +} +#endif /* _FFR_LDAP_RECURSION */ + +/* +** SM_LDAP_CLOSE -- close LDAP connection +** +** Parameters: +** lmap -- LDAP map information +** +** Returns: +** None. +** +*/ + +void +sm_ldap_close(lmap) + SM_LDAP_STRUCT *lmap; +{ + if (lmap->ldap_ld == NULL) + return; + + if (lmap->ldap_pid == getpid()) + ldap_unbind(lmap->ldap_ld); + lmap->ldap_ld = NULL; + lmap->ldap_pid = 0; +} + +/* +** SM_LDAP_SETOPTS -- set LDAP options +** +** Parameters: +** ld -- LDAP session handle +** lmap -- LDAP map information +** +** Returns: +** None. +** +*/ + +void +sm_ldap_setopts(ld, lmap) + LDAP *ld; + SM_LDAP_STRUCT *lmap; +{ +# if USE_LDAP_SET_OPTION + ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); + if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) + ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); + else + ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); + ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); + ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); +# else /* USE_LDAP_SET_OPTION */ + /* From here on in we can use ldap internal timelimits */ + ld->ld_deref = lmap->ldap_deref; + ld->ld_options = lmap->ldap_options; + ld->ld_sizelimit = lmap->ldap_sizelimit; + ld->ld_timelimit = lmap->ldap_timelimit; +# endif /* USE_LDAP_SET_OPTION */ +} + +/* +** SM_LDAP_GETERRNO -- get ldap errno value +** +** Parameters: +** ld -- LDAP session handle +** +** Returns: +** LDAP errno. +** +*/ + +int +sm_ldap_geterrno(ld) + LDAP *ld; +{ + int err = LDAP_SUCCESS; + +# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 + (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); +# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ +# ifdef LDAP_OPT_SIZELIMIT + err = ldap_get_lderrno(ld, NULL, NULL); +# else /* LDAP_OPT_SIZELIMIT */ + err = ld->ld_errno; + + /* + ** Reset value to prevent lingering LDAP_DECODING_ERROR due to + ** OpenLDAP 1.X's hack (see above) + */ + + ld->ld_errno = LDAP_SUCCESS; +# endif /* LDAP_OPT_SIZELIMIT */ +# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ + return err; +} +# endif /* LDAPMAP */ |