1N/A/*
1N/A * Copyright (c) 2001-2009 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A */
1N/A
1N/A/* some "deprecated" calls are used, e.g., ldap_get_values() */
1N/A#define LDAP_DEPRECATED 1
1N/A
1N/A#include <sm/gen.h>
1N/ASM_RCSID("@(#)$Id: ldap.c,v 1.85 2011/04/18 22:20:20 ca Exp $")
1N/A
1N/A#if LDAPMAP
1N/A# include <sys/types.h>
1N/A# include <errno.h>
1N/A# include <setjmp.h>
1N/A# include <stdlib.h>
1N/A# include <unistd.h>
1N/A
1N/A# include <sm/bitops.h>
1N/A# include <sm/clock.h>
1N/A# include <sm/conf.h>
1N/A# include <sm/debug.h>
1N/A# include <sm/errstring.h>
1N/A# include <sm/ldap.h>
1N/A# include <sm/string.h>
1N/A# ifdef EX_OK
1N/A# undef EX_OK /* for SVr4.2 SMP */
1N/A# endif /* EX_OK */
1N/A# include <sm/sysexits.h>
1N/A
1N/ASM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
1N/A "@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
1N/A
1N/Astatic void ldaptimeout __P((int));
1N/Astatic bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *));
1N/Astatic SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *));
1N/A
1N/A/*
1N/A** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
1N/A**
1N/A** Parameters:
1N/A** lmap -- pointer to SM_LDAP_STRUCT to clear
1N/A**
1N/A** Returns:
1N/A** None.
1N/A**
1N/A*/
1N/A
1N/A#if _FFR_LDAP_VERSION
1N/A# if defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX
1N/A ERROR FFR_LDAP_VERSION > _LDAP_VERSION_MAX
1N/A# endif /* defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX */
1N/A# if defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN
1N/A ERROR FFR_LDAP_VERSION < _LDAP_VERSION_MIN
1N/A# endif /* defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN */
1N/A# define SM_LDAP_VERSION_DEFAULT _FFR_LDAP_VERSION
1N/A#else /* _FFR_LDAP_VERSION */
1N/A# define SM_LDAP_VERSION_DEFAULT 0
1N/A#endif /* _FFR_LDAP_VERSION */
1N/A
1N/Avoid
1N/Asm_ldap_clear(lmap)
1N/A SM_LDAP_STRUCT *lmap;
1N/A{
1N/A if (lmap == NULL)
1N/A return;
1N/A
1N/A lmap->ldap_host = NULL;
1N/A lmap->ldap_port = LDAP_PORT;
1N/A lmap->ldap_uri = NULL;
1N/A lmap->ldap_version = SM_LDAP_VERSION_DEFAULT;
1N/A lmap->ldap_deref = LDAP_DEREF_NEVER;
1N/A lmap->ldap_timelimit = LDAP_NO_LIMIT;
1N/A lmap->ldap_sizelimit = LDAP_NO_LIMIT;
1N/A# ifdef LDAP_REFERRALS
1N/A lmap->ldap_options = LDAP_OPT_REFERRALS;
1N/A# else /* LDAP_REFERRALS */
1N/A lmap->ldap_options = 0;
1N/A# endif /* LDAP_REFERRALS */
1N/A lmap->ldap_attrsep = '\0';
1N/A lmap->ldap_binddn = NULL;
1N/A lmap->ldap_secret = NULL;
1N/A lmap->ldap_method = LDAP_AUTH_SIMPLE;
1N/A lmap->ldap_base = NULL;
1N/A lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
1N/A lmap->ldap_attrsonly = LDAPMAP_FALSE;
1N/A lmap->ldap_timeout.tv_sec = 0;
1N/A lmap->ldap_timeout.tv_usec = 0;
1N/A lmap->ldap_ld = NULL;
1N/A lmap->ldap_filter = NULL;
1N/A lmap->ldap_attr[0] = NULL;
1N/A lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
1N/A lmap->ldap_attr_needobjclass[0] = NULL;
1N/A lmap->ldap_res = NULL;
1N/A lmap->ldap_next = NULL;
1N/A lmap->ldap_pid = 0;
1N/A lmap->ldap_multi_args = false;
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_START -- actually connect to an LDAP server
1N/A**
1N/A** Parameters:
1N/A** name -- name of map for debug output.
1N/A** lmap -- the LDAP map being opened.
1N/A**
1N/A** Returns:
1N/A** true if connection is successful, false otherwise.
1N/A**
1N/A** Side Effects:
1N/A** Populates lmap->ldap_ld.
1N/A*/
1N/A
1N/Astatic jmp_buf LDAPTimeout;
1N/A
1N/A#define SM_LDAP_SETTIMEOUT(to) \
1N/Ado \
1N/A{ \
1N/A if (to != 0) \
1N/A { \
1N/A if (setjmp(LDAPTimeout) != 0) \
1N/A { \
1N/A errno = ETIMEDOUT; \
1N/A return false; \
1N/A } \
1N/A ev = sm_setevent(to, ldaptimeout, 0); \
1N/A } \
1N/A} while (0)
1N/A
1N/A#define SM_LDAP_CLEARTIMEOUT() \
1N/Ado \
1N/A{ \
1N/A if (ev != NULL) \
1N/A sm_clrevent(ev); \
1N/A} while (0)
1N/A
1N/Abool
1N/Asm_ldap_start(name, lmap)
1N/A char *name;
1N/A SM_LDAP_STRUCT *lmap;
1N/A{
1N/A int bind_result;
1N/A int save_errno = 0;
1N/A char *id;
1N/A SM_EVENT *ev = NULL;
1N/A LDAP *ld = NULL;
1N/A
1N/A if (sm_debug_active(&SmLDAPTrace, 2))
1N/A sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
1N/A
1N/A if (lmap->ldap_host != NULL)
1N/A id = lmap->ldap_host;
1N/A else if (lmap->ldap_uri != NULL)
1N/A id = lmap->ldap_uri;
1N/A else
1N/A id = "localhost";
1N/A
1N/A if (sm_debug_active(&SmLDAPTrace, 9))
1N/A {
1N/A /* Don't print a port number for LDAP URIs */
1N/A if (lmap->ldap_uri != NULL)
1N/A sm_dprintf("ldapmap_start(%s)\n", id);
1N/A else
1N/A sm_dprintf("ldapmap_start(%s, %d)\n", id,
1N/A lmap->ldap_port);
1N/A }
1N/A
1N/A if (lmap->ldap_uri != NULL)
1N/A {
1N/A#if SM_CONF_LDAP_INITIALIZE
1N/A /* LDAP server supports URIs so use them directly */
1N/A save_errno = ldap_initialize(&ld, lmap->ldap_uri);
1N/A#else /* SM_CONF_LDAP_INITIALIZE */
1N/A int err;
1N/A LDAPURLDesc *ludp = NULL;
1N/A
1N/A /* Blast apart URL and use the ldap_init/ldap_open below */
1N/A err = ldap_url_parse(lmap->ldap_uri, &ludp);
1N/A if (err != 0)
1N/A {
1N/A errno = err + E_LDAPURLBASE;
1N/A return false;
1N/A }
1N/A lmap->ldap_host = sm_strdup_x(ludp->lud_host);
1N/A if (lmap->ldap_host == NULL)
1N/A {
1N/A save_errno = errno;
1N/A ldap_free_urldesc(ludp);
1N/A errno = save_errno;
1N/A return false;
1N/A }
1N/A lmap->ldap_port = ludp->lud_port;
1N/A ldap_free_urldesc(ludp);
1N/A#endif /* SM_CONF_LDAP_INITIALIZE */
1N/A }
1N/A
1N/A if (ld == NULL)
1N/A {
1N/A# if USE_LDAP_INIT
1N/A ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
1N/A save_errno = errno;
1N/A# else /* USE_LDAP_INIT */
1N/A /*
1N/A ** If using ldap_open(), the actual connection to the server
1N/A ** happens now so we need the timeout here. For ldap_init(),
1N/A ** the connection happens at bind time.
1N/A */
1N/A
1N/A SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
1N/A ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
1N/A save_errno = errno;
1N/A
1N/A /* clear the event if it has not sprung */
1N/A SM_LDAP_CLEARTIMEOUT();
1N/A# endif /* USE_LDAP_INIT */
1N/A }
1N/A
1N/A errno = save_errno;
1N/A if (ld == NULL)
1N/A return false;
1N/A
1N/A sm_ldap_setopts(ld, lmap);
1N/A
1N/A# if USE_LDAP_INIT
1N/A /*
1N/A ** If using ldap_init(), the actual connection to the server
1N/A ** happens at ldap_bind_s() so we need the timeout here.
1N/A */
1N/A
1N/A SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
1N/A# endif /* USE_LDAP_INIT */
1N/A
1N/A# ifdef LDAP_AUTH_KRBV4
1N/A if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
1N/A lmap->ldap_secret != NULL)
1N/A {
1N/A /*
1N/A ** Need to put ticket in environment here instead of
1N/A ** during parseargs as there may be different tickets
1N/A ** for different LDAP connections.
1N/A */
1N/A
1N/A (void) putenv(lmap->ldap_secret);
1N/A }
1N/A# endif /* LDAP_AUTH_KRBV4 */
1N/A
1N/A bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
1N/A lmap->ldap_secret, lmap->ldap_method);
1N/A
1N/A# if USE_LDAP_INIT
1N/A /* clear the event if it has not sprung */
1N/A SM_LDAP_CLEARTIMEOUT();
1N/A# endif /* USE_LDAP_INIT */
1N/A
1N/A if (bind_result != LDAP_SUCCESS)
1N/A {
1N/A errno = bind_result + E_LDAPBASE;
1N/A return false;
1N/A }
1N/A
1N/A /* Save PID to make sure only this PID closes the LDAP connection */
1N/A lmap->ldap_pid = getpid();
1N/A lmap->ldap_ld = ld;
1N/A return true;
1N/A}
1N/A
1N/A/* ARGSUSED */
1N/Astatic void
1N/Aldaptimeout(unused)
1N/A int unused;
1N/A{
1N/A /*
1N/A ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
1N/A ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1N/A ** DOING.
1N/A */
1N/A
1N/A errno = ETIMEDOUT;
1N/A longjmp(LDAPTimeout, 1);
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_SEARCH_M -- initiate multi-key LDAP search
1N/A**
1N/A** Initiate an LDAP search, return the msgid.
1N/A** The calling function must collect the results.
1N/A**
1N/A** Parameters:
1N/A** lmap -- LDAP map information
1N/A** argv -- key vector of substitutions in LDAP filter
1N/A** NOTE: argv must have SM_LDAP_ARGS elements to prevent
1N/A** out of bound array references
1N/A**
1N/A** Returns:
1N/A** <0 on failure (SM_LDAP_ERR*), msgid on success
1N/A**
1N/A*/
1N/A
1N/Aint
1N/Asm_ldap_search_m(lmap, argv)
1N/A SM_LDAP_STRUCT *lmap;
1N/A char **argv;
1N/A{
1N/A int msgid;
1N/A char *fp, *p, *q;
1N/A char filter[LDAPMAP_MAX_FILTER + 1];
1N/A
1N/A SM_REQUIRE(lmap != NULL);
1N/A SM_REQUIRE(argv != NULL);
1N/A SM_REQUIRE(argv[0] != NULL);
1N/A
1N/A memset(filter, '\0', sizeof filter);
1N/A fp = filter;
1N/A p = lmap->ldap_filter;
1N/A while ((q = strchr(p, '%')) != NULL)
1N/A {
1N/A char *key;
1N/A
1N/A if (lmap->ldap_multi_args)
1N/A {
1N/A#if SM_LDAP_ARGS < 10
1N/A# ERROR _SM_LDAP_ARGS must be 10
1N/A#endif /* SM_LDAP_ARGS < 10 */
1N/A if (q[1] == 's')
1N/A key = argv[0];
1N/A else if (q[1] >= '0' && q[1] <= '9')
1N/A {
1N/A key = argv[q[1] - '0'];
1N/A if (key == NULL)
1N/A {
1N/A# if SM_LDAP_ERROR_ON_MISSING_ARGS
1N/A return SM_LDAP_ERR_ARG_MISS;
1N/A# else /* SM_LDAP_ERROR_ON_MISSING_ARGS */
1N/A key = "";
1N/A# endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
1N/A }
1N/A }
1N/A else
1N/A key = NULL;
1N/A }
1N/A else
1N/A key = argv[0];
1N/A
1N/A if (q[1] == 's')
1N/A {
1N/A (void) sm_snprintf(fp, SPACELEFT(filter, fp),
1N/A "%.*s%s", (int) (q - p), p, key);
1N/A fp += strlen(fp);
1N/A p = q + 2;
1N/A }
1N/A else if (q[1] == '0' ||
1N/A (lmap->ldap_multi_args && q[1] >= '0' && q[1] <= '9'))
1N/A {
1N/A char *k = key;
1N/A
1N/A (void) sm_snprintf(fp, SPACELEFT(filter, fp),
1N/A "%.*s", (int) (q - p), p);
1N/A fp += strlen(fp);
1N/A p = q + 2;
1N/A
1N/A /* Properly escape LDAP special characters */
1N/A while (SPACELEFT(filter, fp) > 0 &&
1N/A *k != '\0')
1N/A {
1N/A if (*k == '*' || *k == '(' ||
1N/A *k == ')' || *k == '\\')
1N/A {
1N/A (void) sm_strlcat(fp,
1N/A (*k == '*' ? "\\2A" :
1N/A (*k == '(' ? "\\28" :
1N/A (*k == ')' ? "\\29" :
1N/A (*k == '\\' ? "\\5C" :
1N/A "\00")))),
1N/A SPACELEFT(filter, fp));
1N/A fp += strlen(fp);
1N/A k++;
1N/A }
1N/A else
1N/A *fp++ = *k++;
1N/A }
1N/A }
1N/A else
1N/A {
1N/A (void) sm_snprintf(fp, SPACELEFT(filter, fp),
1N/A "%.*s", (int) (q - p + 1), p);
1N/A p = q + (q[1] == '%' ? 2 : 1);
1N/A fp += strlen(fp);
1N/A }
1N/A }
1N/A (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
1N/A if (sm_debug_active(&SmLDAPTrace, 20))
1N/A sm_dprintf("ldap search filter=%s\n", filter);
1N/A
1N/A lmap->ldap_res = NULL;
1N/A msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
1N/A lmap->ldap_scope, filter,
1N/A (lmap->ldap_attr[0] == NULL ? NULL :
1N/A lmap->ldap_attr),
1N/A lmap->ldap_attrsonly);
1N/A return msgid;
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_SEARCH -- initiate LDAP search
1N/A**
1N/A** Initiate an LDAP search, return the msgid.
1N/A** The calling function must collect the results.
1N/A** Note this is just a wrapper into sm_ldap_search_m()
1N/A**
1N/A** Parameters:
1N/A** lmap -- LDAP map information
1N/A** key -- key to substitute in LDAP filter
1N/A**
1N/A** Returns:
1N/A** <0 on failure, msgid on success
1N/A**
1N/A*/
1N/A
1N/Aint
1N/Asm_ldap_search(lmap, key)
1N/A SM_LDAP_STRUCT *lmap;
1N/A char *key;
1N/A{
1N/A char *argv[SM_LDAP_ARGS];
1N/A
1N/A memset(argv, '\0', sizeof argv);
1N/A argv[0] = key;
1N/A return sm_ldap_search_m(lmap, argv);
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
1N/A** particular objectClass
1N/A**
1N/A** Parameters:
1N/A** lmap -- pointer to SM_LDAP_STRUCT in use
1N/A** entry -- current LDAP entry struct
1N/A** ocvalue -- particular objectclass in question.
1N/A** may be of form (fee|foo|fum) meaning
1N/A** any entry can be part of either fee,
1N/A** foo or fum objectclass
1N/A**
1N/A** Returns:
1N/A** true if item has that objectClass
1N/A*/
1N/A
1N/Astatic bool
1N/Asm_ldap_has_objectclass(lmap, entry, ocvalue)
1N/A SM_LDAP_STRUCT *lmap;
1N/A LDAPMessage *entry;
1N/A char *ocvalue;
1N/A{
1N/A char **vals = NULL;
1N/A int i;
1N/A
1N/A if (ocvalue == NULL)
1N/A return false;
1N/A
1N/A vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
1N/A if (vals == NULL)
1N/A return false;
1N/A
1N/A for (i = 0; vals[i] != NULL; i++)
1N/A {
1N/A char *p;
1N/A char *q;
1N/A
1N/A p = q = ocvalue;
1N/A while (*p != '\0')
1N/A {
1N/A while (*p != '\0' && *p != '|')
1N/A p++;
1N/A
1N/A if ((p - q) == strlen(vals[i]) &&
1N/A sm_strncasecmp(vals[i], q, p - q) == 0)
1N/A {
1N/A ldap_value_free(vals);
1N/A return true;
1N/A }
1N/A
1N/A while (*p == '|')
1N/A p++;
1N/A q = p;
1N/A }
1N/A }
1N/A
1N/A ldap_value_free(vals);
1N/A return false;
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_RESULTS -- return results from an LDAP lookup in result
1N/A**
1N/A** Parameters:
1N/A** lmap -- pointer to SM_LDAP_STRUCT in use
1N/A** msgid -- msgid returned by sm_ldap_search()
1N/A** flags -- flags for the lookup
1N/A** delim -- delimiter for result concatenation
1N/A** rpool -- memory pool for storage
1N/A** result -- return string
1N/A** recurse -- recursion list
1N/A**
1N/A** Returns:
1N/A** status (sysexit)
1N/A*/
1N/A
1N/A# define SM_LDAP_ERROR_CLEANUP() \
1N/A{ \
1N/A if (lmap->ldap_res != NULL) \
1N/A { \
1N/A ldap_msgfree(lmap->ldap_res); \
1N/A lmap->ldap_res = NULL; \
1N/A } \
1N/A (void) ldap_abandon(lmap->ldap_ld, msgid); \
1N/A}
1N/A
1N/Astatic SM_LDAP_RECURSE_ENTRY *
1N/Asm_ldap_add_recurse(top, item, type, rpool)
1N/A SM_LDAP_RECURSE_LIST **top;
1N/A char *item;
1N/A int type;
1N/A SM_RPOOL_T *rpool;
1N/A{
1N/A int n;
1N/A int m;
1N/A int p;
1N/A int insertat;
1N/A int moveb;
1N/A int oldsizeb;
1N/A int rc;
1N/A SM_LDAP_RECURSE_ENTRY *newe;
1N/A SM_LDAP_RECURSE_ENTRY **olddata;
1N/A
1N/A /*
1N/A ** This code will maintain a list of
1N/A ** SM_LDAP_RECURSE_ENTRY structures
1N/A ** in ascending order.
1N/A */
1N/A
1N/A if (*top == NULL)
1N/A {
1N/A /* Allocate an initial SM_LDAP_RECURSE_LIST struct */
1N/A *top = sm_rpool_malloc_x(rpool, sizeof **top);
1N/A (*top)->lrl_cnt = 0;
1N/A (*top)->lrl_size = 0;
1N/A (*top)->lrl_data = NULL;
1N/A }
1N/A
1N/A if ((*top)->lrl_cnt >= (*top)->lrl_size)
1N/A {
1N/A /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
1N/A olddata = (*top)->lrl_data;
1N/A if ((*top)->lrl_size == 0)
1N/A {
1N/A oldsizeb = 0;
1N/A (*top)->lrl_size = 256;
1N/A }
1N/A else
1N/A {
1N/A oldsizeb = (*top)->lrl_size * sizeof *((*top)->lrl_data);
1N/A (*top)->lrl_size *= 2;
1N/A }
1N/A (*top)->lrl_data = sm_rpool_malloc_x(rpool,
1N/A (*top)->lrl_size * sizeof *((*top)->lrl_data));
1N/A if (oldsizeb > 0)
1N/A memcpy((*top)->lrl_data, olddata, oldsizeb);
1N/A }
1N/A
1N/A /*
1N/A ** Binary search/insert item:type into list.
1N/A ** Return current entry pointer if already exists.
1N/A */
1N/A
1N/A n = 0;
1N/A m = (*top)->lrl_cnt - 1;
1N/A if (m < 0)
1N/A insertat = 0;
1N/A else
1N/A insertat = -1;
1N/A
1N/A while (insertat == -1)
1N/A {
1N/A p = (m + n) / 2;
1N/A
1N/A rc = sm_strcasecmp(item, (*top)->lrl_data[p]->lr_search);
1N/A if (rc == 0)
1N/A rc = type - (*top)->lrl_data[p]->lr_type;
1N/A
1N/A if (rc < 0)
1N/A m = p - 1;
1N/A else if (rc > 0)
1N/A n = p + 1;
1N/A else
1N/A return (*top)->lrl_data[p];
1N/A
1N/A if (m == -1)
1N/A insertat = 0;
1N/A else if (n >= (*top)->lrl_cnt)
1N/A insertat = (*top)->lrl_cnt;
1N/A else if (m < n)
1N/A insertat = m + 1;
1N/A }
1N/A
1N/A /*
1N/A ** Not found in list, make room
1N/A ** at insert point and add it.
1N/A */
1N/A
1N/A newe = sm_rpool_malloc_x(rpool, sizeof *newe);
1N/A if (newe != NULL)
1N/A {
1N/A moveb = ((*top)->lrl_cnt - insertat) * sizeof *((*top)->lrl_data);
1N/A if (moveb > 0)
1N/A memmove(&((*top)->lrl_data[insertat + 1]),
1N/A &((*top)->lrl_data[insertat]),
1N/A moveb);
1N/A
1N/A newe->lr_search = sm_rpool_strdup_x(rpool, item);
1N/A newe->lr_type = type;
1N/A newe->lr_ludp = NULL;
1N/A newe->lr_attrs = NULL;
1N/A newe->lr_done = false;
1N/A
1N/A ((*top)->lrl_data)[insertat] = newe;
1N/A (*top)->lrl_cnt++;
1N/A }
1N/A return newe;
1N/A}
1N/A
1N/Aint
1N/Asm_ldap_results(lmap, msgid, flags, delim, rpool, result,
1N/A resultln, resultsz, recurse)
1N/A SM_LDAP_STRUCT *lmap;
1N/A int msgid;
1N/A int flags;
1N/A int delim;
1N/A SM_RPOOL_T *rpool;
1N/A char **result;
1N/A int *resultln;
1N/A int *resultsz;
1N/A SM_LDAP_RECURSE_LIST *recurse;
1N/A{
1N/A bool toplevel;
1N/A int i;
1N/A int statp;
1N/A int vsize;
1N/A int ret;
1N/A int save_errno;
1N/A char *p;
1N/A SM_LDAP_RECURSE_ENTRY *rl;
1N/A
1N/A /* Are we the top top level of the search? */
1N/A toplevel = (recurse == NULL);
1N/A
1N/A /* Get results */
1N/A statp = EX_NOTFOUND;
1N/A while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
1N/A (lmap->ldap_timeout.tv_sec == 0 ? NULL :
1N/A &(lmap->ldap_timeout)),
1N/A &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
1N/A {
1N/A LDAPMessage *entry;
1N/A
1N/A /* If we don't want multiple values and we have one, break */
1N/A if ((char) delim == '\0' &&
1N/A !bitset(SM_LDAP_SINGLEMATCH, flags) &&
1N/A *result != NULL)
1N/A break;
1N/A
1N/A /* Cycle through all entries */
1N/A for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
1N/A entry != NULL;
1N/A entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
1N/A {
1N/A BerElement *ber;
1N/A char *attr;
1N/A char **vals = NULL;
1N/A char *dn;
1N/A
1N/A /*
1N/A ** If matching only and found an entry,
1N/A ** no need to spin through attributes
1N/A */
1N/A
1N/A if (bitset(SM_LDAP_MATCHONLY, flags))
1N/A {
1N/A statp = EX_OK;
1N/A continue;
1N/A }
1N/A
1N/A#if _FFR_LDAP_SINGLEDN
1N/A if (bitset(SM_LDAP_SINGLEDN, flags) && *result != NULL)
1N/A {
1N/A /* only wanted one match */
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOENT;
1N/A return EX_NOTFOUND;
1N/A }
1N/A#endif /* _FFR_LDAP_SINGLEDN */
1N/A
1N/A /* record completed DN's to prevent loops */
1N/A dn = ldap_get_dn(lmap->ldap_ld, entry);
1N/A if (dn == NULL)
1N/A {
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A save_errno += E_LDAPBASE;
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = save_errno;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A
1N/A rl = sm_ldap_add_recurse(&recurse, dn,
1N/A SM_LDAP_ATTR_DN,
1N/A rpool);
1N/A
1N/A if (rl == NULL)
1N/A {
1N/A ldap_memfree(dn);
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOMEM;
1N/A return EX_OSERR;
1N/A }
1N/A else if (rl->lr_done)
1N/A {
1N/A /* already on list, skip it */
1N/A ldap_memfree(dn);
1N/A continue;
1N/A }
1N/A ldap_memfree(dn);
1N/A
1N/A# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
1N/A /*
1N/A ** Reset value to prevent lingering
1N/A ** LDAP_DECODING_ERROR due to
1N/A ** OpenLDAP 1.X's hack (see below)
1N/A */
1N/A
1N/A lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
1N/A# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
1N/A
1N/A for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
1N/A &ber);
1N/A attr != NULL;
1N/A attr = ldap_next_attribute(lmap->ldap_ld, entry,
1N/A ber))
1N/A {
1N/A char *tmp, *vp_tmp;
1N/A int type;
1N/A char *needobjclass = NULL;
1N/A
1N/A type = SM_LDAP_ATTR_NONE;
1N/A for (i = 0; lmap->ldap_attr[i] != NULL; i++)
1N/A {
1N/A if (sm_strcasecmp(lmap->ldap_attr[i],
1N/A attr) == 0)
1N/A {
1N/A type = lmap->ldap_attr_type[i];
1N/A needobjclass = lmap->ldap_attr_needobjclass[i];
1N/A break;
1N/A }
1N/A }
1N/A
1N/A if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
1N/A type == SM_LDAP_ATTR_NONE)
1N/A {
1N/A /* URL lookups specify attrs to use */
1N/A type = SM_LDAP_ATTR_NORMAL;
1N/A needobjclass = NULL;
1N/A }
1N/A
1N/A if (type == SM_LDAP_ATTR_NONE)
1N/A {
1N/A /* attribute not requested */
1N/A ldap_memfree(attr);
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = EFAULT;
1N/A return EX_SOFTWARE;
1N/A }
1N/A
1N/A /*
1N/A ** For recursion on a particular attribute,
1N/A ** we may need to see if this entry is
1N/A ** part of a particular objectclass.
1N/A ** Also, ignore objectClass attribute.
1N/A ** Otherwise we just ignore this attribute.
1N/A */
1N/A
1N/A if (type == SM_LDAP_ATTR_OBJCLASS ||
1N/A (needobjclass != NULL &&
1N/A !sm_ldap_has_objectclass(lmap, entry,
1N/A needobjclass)))
1N/A {
1N/A ldap_memfree(attr);
1N/A continue;
1N/A }
1N/A
1N/A if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
1N/A {
1N/A vals = ldap_get_values(lmap->ldap_ld,
1N/A entry,
1N/A attr);
1N/A if (vals == NULL)
1N/A {
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A if (save_errno == LDAP_SUCCESS)
1N/A {
1N/A ldap_memfree(attr);
1N/A continue;
1N/A }
1N/A
1N/A /* Must be an error */
1N/A save_errno += E_LDAPBASE;
1N/A ldap_memfree(attr);
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = save_errno;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A }
1N/A
1N/A statp = EX_OK;
1N/A
1N/A# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
1N/A /*
1N/A ** Reset value to prevent lingering
1N/A ** LDAP_DECODING_ERROR due to
1N/A ** OpenLDAP 1.X's hack (see below)
1N/A */
1N/A
1N/A lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
1N/A# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
1N/A
1N/A /*
1N/A ** If matching only,
1N/A ** no need to spin through entries
1N/A */
1N/A
1N/A if (bitset(SM_LDAP_MATCHONLY, flags))
1N/A {
1N/A if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
1N/A ldap_value_free(vals);
1N/A ldap_memfree(attr);
1N/A continue;
1N/A }
1N/A
1N/A /*
1N/A ** If we don't want multiple values,
1N/A ** return first found.
1N/A */
1N/A
1N/A if ((char) delim == '\0')
1N/A {
1N/A if (*result != NULL)
1N/A {
1N/A /* already have a value */
1N/A if (bitset(SM_LDAP_SINGLEMATCH,
1N/A flags))
1N/A {
1N/A /* only wanted one match */
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOENT;
1N/A return EX_NOTFOUND;
1N/A }
1N/A break;
1N/A }
1N/A
1N/A if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
1N/A {
1N/A *result = sm_rpool_strdup_x(rpool,
1N/A attr);
1N/A ldap_memfree(attr);
1N/A break;
1N/A }
1N/A
1N/A if (vals[0] == NULL)
1N/A {
1N/A ldap_value_free(vals);
1N/A ldap_memfree(attr);
1N/A continue;
1N/A }
1N/A
1N/A vsize = strlen(vals[0]) + 1;
1N/A if (lmap->ldap_attrsep != '\0')
1N/A vsize += strlen(attr) + 1;
1N/A *result = sm_rpool_malloc_x(rpool,
1N/A vsize);
1N/A if (lmap->ldap_attrsep != '\0')
1N/A sm_snprintf(*result, vsize,
1N/A "%s%c%s",
1N/A attr,
1N/A lmap->ldap_attrsep,
1N/A vals[0]);
1N/A else
1N/A sm_strlcpy(*result, vals[0],
1N/A vsize);
1N/A ldap_value_free(vals);
1N/A ldap_memfree(attr);
1N/A break;
1N/A }
1N/A
1N/A /* attributes only */
1N/A if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
1N/A {
1N/A if (*result == NULL)
1N/A *result = sm_rpool_strdup_x(rpool,
1N/A attr);
1N/A else
1N/A {
1N/A if (bitset(SM_LDAP_SINGLEMATCH,
1N/A flags) &&
1N/A *result != NULL)
1N/A {
1N/A /* only wanted one match */
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOENT;
1N/A return EX_NOTFOUND;
1N/A }
1N/A
1N/A vsize = strlen(*result) +
1N/A strlen(attr) + 2;
1N/A tmp = sm_rpool_malloc_x(rpool,
1N/A vsize);
1N/A (void) sm_snprintf(tmp,
1N/A vsize, "%s%c%s",
1N/A *result, (char) delim,
1N/A attr);
1N/A *result = tmp;
1N/A }
1N/A ldap_memfree(attr);
1N/A continue;
1N/A }
1N/A
1N/A /*
1N/A ** If there is more than one, munge then
1N/A ** into a map_coldelim separated string.
1N/A ** If we are recursing we may have an entry
1N/A ** with no 'normal' values to put in the
1N/A ** string.
1N/A ** This is not an error.
1N/A */
1N/A
1N/A if (type == SM_LDAP_ATTR_NORMAL &&
1N/A bitset(SM_LDAP_SINGLEMATCH, flags) &&
1N/A *result != NULL)
1N/A {
1N/A /* only wanted one match */
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOENT;
1N/A return EX_NOTFOUND;
1N/A }
1N/A
1N/A vsize = 0;
1N/A for (i = 0; vals[i] != NULL; i++)
1N/A {
1N/A if (type == SM_LDAP_ATTR_DN ||
1N/A type == SM_LDAP_ATTR_FILTER ||
1N/A type == SM_LDAP_ATTR_URL)
1N/A {
1N/A /* add to recursion */
1N/A if (sm_ldap_add_recurse(&recurse,
1N/A vals[i],
1N/A type,
1N/A rpool) == NULL)
1N/A {
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOMEM;
1N/A return EX_OSERR;
1N/A }
1N/A continue;
1N/A }
1N/A
1N/A vsize += strlen(vals[i]) + 1;
1N/A if (lmap->ldap_attrsep != '\0')
1N/A vsize += strlen(attr) + 1;
1N/A }
1N/A
1N/A /*
1N/A ** Create/Append to string any normal
1N/A ** attribute values. Otherwise, just free
1N/A ** memory and move on to the next
1N/A ** attribute in this entry.
1N/A */
1N/A
1N/A if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
1N/A {
1N/A char *pe;
1N/A
1N/A /* Grow result string if needed */
1N/A if ((*resultln + vsize) >= *resultsz)
1N/A {
1N/A while ((*resultln + vsize) >= *resultsz)
1N/A {
1N/A if (*resultsz == 0)
1N/A *resultsz = 1024;
1N/A else
1N/A *resultsz *= 2;
1N/A }
1N/A
1N/A vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
1N/A *vp_tmp = '\0';
1N/A
1N/A if (*result != NULL)
1N/A sm_strlcpy(vp_tmp,
1N/A *result,
1N/A *resultsz);
1N/A *result = vp_tmp;
1N/A }
1N/A
1N/A p = *result + *resultln;
1N/A pe = *result + *resultsz;
1N/A
1N/A for (i = 0; vals[i] != NULL; i++)
1N/A {
1N/A if (*resultln > 0 &&
1N/A p < pe)
1N/A *p++ = (char) delim;
1N/A
1N/A if (lmap->ldap_attrsep != '\0')
1N/A {
1N/A p += sm_strlcpy(p, attr,
1N/A pe - p);
1N/A if (p < pe)
1N/A *p++ = lmap->ldap_attrsep;
1N/A }
1N/A
1N/A p += sm_strlcpy(p, vals[i],
1N/A pe - p);
1N/A *resultln = p - (*result);
1N/A if (p >= pe)
1N/A {
1N/A /* Internal error: buffer too small for LDAP values */
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = ENOMEM;
1N/A return EX_OSERR;
1N/A }
1N/A }
1N/A }
1N/A
1N/A ldap_value_free(vals);
1N/A ldap_memfree(attr);
1N/A }
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A
1N/A /*
1N/A ** We check save_errno != LDAP_DECODING_ERROR since
1N/A ** OpenLDAP 1.X has a very ugly *undocumented*
1N/A ** hack of returning this error code from
1N/A ** ldap_next_attribute() if the library freed the
1N/A ** ber attribute. See:
1N/A ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
1N/A */
1N/A
1N/A if (save_errno != LDAP_SUCCESS &&
1N/A save_errno != LDAP_DECODING_ERROR)
1N/A {
1N/A /* Must be an error */
1N/A save_errno += E_LDAPBASE;
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = save_errno;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A
1N/A /* mark this DN as done */
1N/A rl->lr_done = true;
1N/A if (rl->lr_ludp != NULL)
1N/A {
1N/A ldap_free_urldesc(rl->lr_ludp);
1N/A rl->lr_ludp = NULL;
1N/A }
1N/A if (rl->lr_attrs != NULL)
1N/A {
1N/A free(rl->lr_attrs);
1N/A rl->lr_attrs = NULL;
1N/A }
1N/A
1N/A /* We don't want multiple values and we have one */
1N/A if ((char) delim == '\0' &&
1N/A !bitset(SM_LDAP_SINGLEMATCH, flags) &&
1N/A *result != NULL)
1N/A break;
1N/A }
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A if (save_errno != LDAP_SUCCESS &&
1N/A save_errno != LDAP_DECODING_ERROR)
1N/A {
1N/A /* Must be an error */
1N/A save_errno += E_LDAPBASE;
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = save_errno;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A ldap_msgfree(lmap->ldap_res);
1N/A lmap->ldap_res = NULL;
1N/A }
1N/A
1N/A if (ret == 0)
1N/A save_errno = ETIMEDOUT;
1N/A else if (ret == LDAP_RES_SEARCH_RESULT)
1N/A {
1N/A /*
1N/A ** We may have gotten an LDAP_RES_SEARCH_RESULT response
1N/A ** with an error inside it, so we have to extract that
1N/A ** with ldap_parse_result(). This can happen when talking
1N/A ** to an LDAP proxy whose backend has gone down.
1N/A */
1N/A
1N/A if (lmap->ldap_res == NULL)
1N/A save_errno = LDAP_UNAVAILABLE;
1N/A else
1N/A {
1N/A int rc;
1N/A
1N/A save_errno = ldap_parse_result(lmap->ldap_ld,
1N/A lmap->ldap_res, &rc, NULL, NULL,
1N/A NULL, NULL, 0);
1N/A if (save_errno == LDAP_SUCCESS)
1N/A save_errno = rc;
1N/A }
1N/A }
1N/A else
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A if (save_errno != LDAP_SUCCESS)
1N/A {
1N/A statp = EX_TEMPFAIL;
1N/A switch (save_errno)
1N/A {
1N/A#ifdef LDAP_SERVER_DOWN
1N/A case LDAP_SERVER_DOWN:
1N/A#endif /* LDAP_SERVER_DOWN */
1N/A case LDAP_TIMEOUT:
1N/A case ETIMEDOUT:
1N/A case LDAP_UNAVAILABLE:
1N/A
1N/A /*
1N/A ** server disappeared,
1N/A ** try reopen on next search
1N/A */
1N/A
1N/A statp = EX_RESTART;
1N/A break;
1N/A }
1N/A if (ret != 0)
1N/A save_errno += E_LDAPBASE;
1N/A SM_LDAP_ERROR_CLEANUP();
1N/A errno = save_errno;
1N/A return statp;
1N/A }
1N/A
1N/A if (lmap->ldap_res != NULL)
1N/A {
1N/A ldap_msgfree(lmap->ldap_res);
1N/A lmap->ldap_res = NULL;
1N/A }
1N/A
1N/A if (toplevel)
1N/A {
1N/A int rlidx;
1N/A
1N/A /*
1N/A ** Spin through the built-up recurse list at the top
1N/A ** of the recursion. Since new items are added at the
1N/A ** end of the shared list, we actually only ever get
1N/A ** one level of recursion before things pop back to the
1N/A ** top. Any items added to the list during that recursion
1N/A ** will be expanded by the top level.
1N/A */
1N/A
1N/A for (rlidx = 0; recurse != NULL && rlidx < recurse->lrl_cnt;
1N/A rlidx++)
1N/A {
1N/A int newflags;
1N/A int sid;
1N/A int status;
1N/A
1N/A rl = recurse->lrl_data[rlidx];
1N/A
1N/A newflags = flags;
1N/A if (rl->lr_done)
1N/A {
1N/A /* already expanded */
1N/A continue;
1N/A }
1N/A
1N/A if (rl->lr_type == SM_LDAP_ATTR_DN)
1N/A {
1N/A /* do DN search */
1N/A sid = ldap_search(lmap->ldap_ld,
1N/A rl->lr_search,
1N/A lmap->ldap_scope,
1N/A "(objectClass=*)",
1N/A (lmap->ldap_attr[0] == NULL ?
1N/A NULL : lmap->ldap_attr),
1N/A lmap->ldap_attrsonly);
1N/A }
1N/A else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
1N/A {
1N/A /* do new search */
1N/A sid = ldap_search(lmap->ldap_ld,
1N/A lmap->ldap_base,
1N/A lmap->ldap_scope,
1N/A rl->lr_search,
1N/A (lmap->ldap_attr[0] == NULL ?
1N/A NULL : lmap->ldap_attr),
1N/A lmap->ldap_attrsonly);
1N/A }
1N/A else if (rl->lr_type == SM_LDAP_ATTR_URL)
1N/A {
1N/A /* Parse URL */
1N/A sid = ldap_url_parse(rl->lr_search,
1N/A &rl->lr_ludp);
1N/A
1N/A if (sid != 0)
1N/A {
1N/A errno = sid + E_LDAPURLBASE;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A
1N/A /* We need to add objectClass */
1N/A if (rl->lr_ludp->lud_attrs != NULL)
1N/A {
1N/A int attrnum = 0;
1N/A
1N/A while (rl->lr_ludp->lud_attrs[attrnum] != NULL)
1N/A {
1N/A if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum],
1N/A "objectClass") == 0)
1N/A {
1N/A /* already requested */
1N/A attrnum = -1;
1N/A break;
1N/A }
1N/A attrnum++;
1N/A }
1N/A
1N/A if (attrnum >= 0)
1N/A {
1N/A int i;
1N/A
1N/A rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2));
1N/A if (rl->lr_attrs == NULL)
1N/A {
1N/A save_errno = errno;
1N/A ldap_free_urldesc(rl->lr_ludp);
1N/A errno = save_errno;
1N/A return EX_TEMPFAIL;
1N/A }
1N/A for (i = 0 ; i < attrnum; i++)
1N/A {
1N/A rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i];
1N/A }
1N/A rl->lr_attrs[i++] = "objectClass";
1N/A rl->lr_attrs[i++] = NULL;
1N/A }
1N/A }
1N/A
1N/A /*
1N/A ** Use the existing connection
1N/A ** for this search. It really
1N/A ** should use lud_scheme://lud_host:lud_port/
1N/A ** instead but that would require
1N/A ** opening a new connection.
1N/A ** This should be fixed ASAP.
1N/A */
1N/A
1N/A sid = ldap_search(lmap->ldap_ld,
1N/A rl->lr_ludp->lud_dn,
1N/A rl->lr_ludp->lud_scope,
1N/A rl->lr_ludp->lud_filter,
1N/A rl->lr_attrs,
1N/A lmap->ldap_attrsonly);
1N/A
1N/A /* Use the attributes specified by URL */
1N/A newflags |= SM_LDAP_USE_ALLATTR;
1N/A }
1N/A else
1N/A {
1N/A /* unknown or illegal attribute type */
1N/A errno = EFAULT;
1N/A return EX_SOFTWARE;
1N/A }
1N/A
1N/A /* Collect results */
1N/A if (sid == -1)
1N/A {
1N/A save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1N/A statp = EX_TEMPFAIL;
1N/A switch (save_errno)
1N/A {
1N/A#ifdef LDAP_SERVER_DOWN
1N/A case LDAP_SERVER_DOWN:
1N/A#endif /* LDAP_SERVER_DOWN */
1N/A case LDAP_TIMEOUT:
1N/A case ETIMEDOUT:
1N/A case LDAP_UNAVAILABLE:
1N/A
1N/A /*
1N/A ** server disappeared,
1N/A ** try reopen on next search
1N/A */
1N/A
1N/A statp = EX_RESTART;
1N/A break;
1N/A }
1N/A errno = save_errno + E_LDAPBASE;
1N/A return statp;
1N/A }
1N/A
1N/A status = sm_ldap_results(lmap, sid, newflags, delim,
1N/A rpool, result, resultln,
1N/A resultsz, recurse);
1N/A save_errno = errno;
1N/A if (status != EX_OK && status != EX_NOTFOUND)
1N/A {
1N/A errno = save_errno;
1N/A return status;
1N/A }
1N/A
1N/A /* Mark as done */
1N/A rl->lr_done = true;
1N/A if (rl->lr_ludp != NULL)
1N/A {
1N/A ldap_free_urldesc(rl->lr_ludp);
1N/A rl->lr_ludp = NULL;
1N/A }
1N/A if (rl->lr_attrs != NULL)
1N/A {
1N/A free(rl->lr_attrs);
1N/A rl->lr_attrs = NULL;
1N/A }
1N/A
1N/A /* Reset rlidx as new items may have been added */
1N/A rlidx = -1;
1N/A }
1N/A }
1N/A return statp;
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_CLOSE -- close LDAP connection
1N/A**
1N/A** Parameters:
1N/A** lmap -- LDAP map information
1N/A**
1N/A** Returns:
1N/A** None.
1N/A**
1N/A*/
1N/A
1N/Avoid
1N/Asm_ldap_close(lmap)
1N/A SM_LDAP_STRUCT *lmap;
1N/A{
1N/A if (lmap->ldap_ld == NULL)
1N/A return;
1N/A
1N/A if (lmap->ldap_pid == getpid())
1N/A ldap_unbind(lmap->ldap_ld);
1N/A lmap->ldap_ld = NULL;
1N/A lmap->ldap_pid = 0;
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_SETOPTS -- set LDAP options
1N/A**
1N/A** Parameters:
1N/A** ld -- LDAP session handle
1N/A** lmap -- LDAP map information
1N/A**
1N/A** Returns:
1N/A** None.
1N/A**
1N/A*/
1N/A
1N/Avoid
1N/Asm_ldap_setopts(ld, lmap)
1N/A LDAP *ld;
1N/A SM_LDAP_STRUCT *lmap;
1N/A{
1N/A# if USE_LDAP_SET_OPTION
1N/A if (lmap->ldap_version != 0)
1N/A {
1N/A ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
1N/A &lmap->ldap_version);
1N/A }
1N/A ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
1N/A if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
1N/A ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1N/A else
1N/A ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1N/A ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
1N/A ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
1N/A# if _FFR_LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT)
1N/A if (lmap->ldap_networktmo > 0)
1N/A {
1N/A struct timeval tmo;
1N/A
1N/A tmo.tv_sec = lmap->ldap_networktmo;
1N/A tmo.tv_usec = 0;
1N/A ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tmo);
1N/A }
1N/A# endif /* _FFR_LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT) */
1N/A# ifdef LDAP_OPT_RESTART
1N/A ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1N/A# endif /* LDAP_OPT_RESTART */
1N/A# else /* USE_LDAP_SET_OPTION */
1N/A /* From here on in we can use ldap internal timelimits */
1N/A ld->ld_deref = lmap->ldap_deref;
1N/A ld->ld_options = lmap->ldap_options;
1N/A ld->ld_sizelimit = lmap->ldap_sizelimit;
1N/A ld->ld_timelimit = lmap->ldap_timelimit;
1N/A# endif /* USE_LDAP_SET_OPTION */
1N/A}
1N/A
1N/A/*
1N/A** SM_LDAP_GETERRNO -- get ldap errno value
1N/A**
1N/A** Parameters:
1N/A** ld -- LDAP session handle
1N/A**
1N/A** Returns:
1N/A** LDAP errno.
1N/A**
1N/A*/
1N/A
1N/Aint
1N/Asm_ldap_geterrno(ld)
1N/A LDAP *ld;
1N/A{
1N/A int err = LDAP_SUCCESS;
1N/A
1N/A# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
1N/A (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
1N/A# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1N/A# ifdef LDAP_OPT_SIZELIMIT
1N/A err = ldap_get_lderrno(ld, NULL, NULL);
1N/A# else /* LDAP_OPT_SIZELIMIT */
1N/A err = ld->ld_errno;
1N/A
1N/A /*
1N/A ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
1N/A ** OpenLDAP 1.X's hack (see above)
1N/A */
1N/A
1N/A ld->ld_errno = LDAP_SUCCESS;
1N/A# endif /* LDAP_OPT_SIZELIMIT */
1N/A# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1N/A return err;
1N/A}
1N/A# endif /* LDAPMAP */