diff options
Diffstat (limited to 'contrib/sendmail/libsm/ldap.c')
-rw-r--r-- | contrib/sendmail/libsm/ldap.c | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c deleted file mode 100644 index 3af7ffab01cd..000000000000 --- a/contrib/sendmail/libsm/ldap.c +++ /dev/null @@ -1,1332 +0,0 @@ -/* - * Copyright (c) 2001-2005 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.62 2005/02/24 00:30:01 ca 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> -# ifdef EX_OK -# undef EX_OK /* for SVr4.2 SMP */ -# endif /* EX_OK */ -# 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)); -static bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *)); -static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *)); - -/* -** 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_uri = NULL; - lmap->ldap_version = 0; - 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; - lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; - lmap->ldap_attr_needobjclass[0] = NULL; - 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 = 0; - char *id; - SM_EVENT *ev = NULL; - LDAP *ld = NULL; - - if (sm_debug_active(&SmLDAPTrace, 2)) - sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name); - - if (lmap->ldap_host != NULL) - id = lmap->ldap_host; - else if (lmap->ldap_uri != NULL) - id = lmap->ldap_uri; - else - id = "localhost"; - - if (sm_debug_active(&SmLDAPTrace, 9)) - { - /* Don't print a port number for LDAP URIs */ - if (lmap->ldap_uri != NULL) - sm_dprintf("ldapmap_start(%s)\n", id); - else - sm_dprintf("ldapmap_start(%s, %d)\n", id, - lmap->ldap_port); - } - - if (lmap->ldap_uri != NULL) - { -#if SM_CONF_LDAP_INITIALIZE - /* LDAP server supports URIs so use them directly */ - save_errno = ldap_initialize(&ld, lmap->ldap_uri); -#else /* SM_CONF_LDAP_INITIALIZE */ - int err; - LDAPURLDesc *ludp = NULL; - - /* Blast apart URL and use the ldap_init/ldap_open below */ - err = ldap_url_parse(lmap->ldap_uri, &ludp); - if (err != 0) - { - errno = err + E_LDAPURLBASE; - return false; - } - lmap->ldap_host = sm_strdup_x(ludp->lud_host); - if (lmap->ldap_host == NULL) - { - save_errno = errno; - ldap_free_urldesc(ludp); - errno = save_errno; - return false; - } - lmap->ldap_port = ludp->lud_port; - ldap_free_urldesc(ludp); -#endif /* SM_CONF_LDAP_INITIALIZE */ - } - - if (ld == NULL) - { -# 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 -- initiate 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; -} - -/* -** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a -** particular objectClass -** -** Parameters: -** lmap -- pointer to SM_LDAP_STRUCT in use -** entry -- current LDAP entry struct -** ocvalue -- particular objectclass in question. -** may be of form (fee|foo|fum) meaning -** any entry can be part of either fee, -** foo or fum objectclass -** -** Returns: -** true if item has that objectClass -*/ - -static bool -sm_ldap_has_objectclass(lmap, entry, ocvalue) - SM_LDAP_STRUCT *lmap; - LDAPMessage *entry; - char *ocvalue; -{ - char **vals = NULL; - int i; - - if (ocvalue == NULL) - return false; - - vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); - if (vals == NULL) - return false; - - for (i = 0; vals[i] != NULL; i++) - { - char *p; - char *q; - - p = q = ocvalue; - while (*p != '\0') - { - while (*p != '\0' && *p != '|') - p++; - - if ((p - q) == strlen(vals[i]) && - sm_strncasecmp(vals[i], q, p - q) == 0) - { - ldap_value_free(vals); - return true; - } - - while (*p == '|') - p++; - q = p; - } - } - - ldap_value_free(vals); - return false; -} - -/* -** 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 SM_LDAP_ERROR_CLEANUP() \ -{ \ - if (lmap->ldap_res != NULL) \ - { \ - ldap_msgfree(lmap->ldap_res); \ - lmap->ldap_res = NULL; \ - } \ - (void) ldap_abandon(lmap->ldap_ld, msgid); \ -} - -static SM_LDAP_RECURSE_ENTRY * -sm_ldap_add_recurse(top, item, type, rpool) - SM_LDAP_RECURSE_LIST **top; - char *item; - int type; - SM_RPOOL_T *rpool; -{ - int n; - int m; - int p; - int insertat; - int moveb; - int oldsizeb; - int rc; - SM_LDAP_RECURSE_ENTRY *newe; - SM_LDAP_RECURSE_ENTRY **olddata; - - /* - ** This code will maintain a list of - ** SM_LDAP_RECURSE_ENTRY structures - ** in ascending order. - */ - - if (*top == NULL) - { - /* Allocate an initial SM_LDAP_RECURSE_LIST struct */ - *top = sm_rpool_malloc_x(rpool, sizeof **top); - (*top)->lr_cnt = 0; - (*top)->lr_size = 0; - (*top)->lr_data = NULL; - } - - if ((*top)->lr_cnt >= (*top)->lr_size) - { - /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ - olddata = (*top)->lr_data; - if ((*top)->lr_size == 0) - { - oldsizeb = 0; - (*top)->lr_size = 256; - } - else - { - oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); - (*top)->lr_size *= 2; - } - (*top)->lr_data = sm_rpool_malloc_x(rpool, - (*top)->lr_size * sizeof *((*top)->lr_data)); - if (oldsizeb > 0) - memcpy((*top)->lr_data, olddata, oldsizeb); - } - - /* - ** Binary search/insert item:type into list. - ** Return current entry pointer if already exists. - */ - - n = 0; - m = (*top)->lr_cnt - 1; - if (m < 0) - insertat = 0; - else - insertat = -1; - - while (insertat == -1) - { - p = (m + n) / 2; - - rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); - if (rc == 0) - rc = type - (*top)->lr_data[p]->lr_type; - - if (rc < 0) - m = p - 1; - else if (rc > 0) - n = p + 1; - else - return (*top)->lr_data[p]; - - if (m == -1) - insertat = 0; - else if (n >= (*top)->lr_cnt) - insertat = (*top)->lr_cnt; - else if (m < n) - insertat = m + 1; - } - - /* - ** Not found in list, make room - ** at insert point and add it. - */ - - newe = sm_rpool_malloc_x(rpool, sizeof *newe); - if (newe != NULL) - { - moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); - if (moveb > 0) - memmove(&((*top)->lr_data[insertat + 1]), - &((*top)->lr_data[insertat]), - moveb); - - newe->lr_search = sm_rpool_strdup_x(rpool, item); - newe->lr_type = type; - newe->lr_ludp = NULL; - newe->lr_attrs = NULL; - newe->lr_done = false; - - ((*top)->lr_data)[insertat] = newe; - (*top)->lr_cnt++; - } - return newe; -} - -int -sm_ldap_results(lmap, msgid, flags, delim, rpool, result, - resultln, resultsz, recurse) - SM_LDAP_STRUCT *lmap; - int msgid; - int flags; - int delim; - SM_RPOOL_T *rpool; - char **result; - int *resultln; - int *resultsz; - SM_LDAP_RECURSE_LIST *recurse; -{ - bool toplevel; - int i; - int statp; - int vsize; - int ret; - int save_errno; - char *p; - SM_LDAP_RECURSE_ENTRY *rl; - - /* 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 we don't want multiple values and we have one, break */ - if ((char) delim == '\0' && - !bitset(SM_LDAP_SINGLEMATCH, flags) && - *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 (bitset(SM_LDAP_MATCHONLY, flags)) - { - statp = EX_OK; - 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; - SM_LDAP_ERROR_CLEANUP(); - errno = save_errno; - return EX_TEMPFAIL; - } - - rl = sm_ldap_add_recurse(&recurse, dn, - SM_LDAP_ATTR_DN, - rpool); - - if (rl == NULL) - { - ldap_memfree(dn); - SM_LDAP_ERROR_CLEANUP(); - errno = ENOMEM; - return EX_OSERR; - } - else if (rl->lr_done) - { - /* 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; - char *needobjclass = NULL; - - type = SM_LDAP_ATTR_NONE; - for (i = 0; lmap->ldap_attr[i] != NULL; i++) - { - if (sm_strcasecmp(lmap->ldap_attr[i], - attr) == 0) - { - type = lmap->ldap_attr_type[i]; - needobjclass = lmap->ldap_attr_needobjclass[i]; - break; - } - } - - if (bitset(SM_LDAP_USE_ALLATTR, flags) && - type == SM_LDAP_ATTR_NONE) - { - /* URL lookups specify attrs to use */ - type = SM_LDAP_ATTR_NORMAL; - needobjclass = NULL; - } - - if (type == SM_LDAP_ATTR_NONE) - { - /* attribute not requested */ - ldap_memfree(attr); - SM_LDAP_ERROR_CLEANUP(); - errno = EFAULT; - return EX_SOFTWARE; - } - - /* - ** For recursion on a particular attribute, - ** we may need to see if this entry is - ** part of a particular objectclass. - ** Also, ignore objectClass attribute. - ** Otherwise we just ignore this attribute. - */ - - if (type == SM_LDAP_ATTR_OBJCLASS || - (needobjclass != NULL && - !sm_ldap_has_objectclass(lmap, entry, - needobjclass))) - { - ldap_memfree(attr); - continue; - } - - 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) - { - ldap_memfree(attr); - continue; - } - - /* Must be an error */ - save_errno += E_LDAPBASE; - ldap_memfree(attr); - SM_LDAP_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); - ldap_memfree(attr); - continue; - } - - /* - ** If we don't want multiple values, - ** return first found. - */ - - if ((char) delim == '\0') - { - if (*result != NULL) - { - /* already have a value */ - if (bitset(SM_LDAP_SINGLEMATCH, - flags)) - { - /* only wanted one match */ - SM_LDAP_ERROR_CLEANUP(); - errno = ENOENT; - return EX_NOTFOUND; - } - break; - } - - if (lmap->ldap_attrsonly == LDAPMAP_TRUE) - { - *result = sm_rpool_strdup_x(rpool, - attr); - ldap_memfree(attr); - break; - } - - if (vals[0] == NULL) - { - ldap_value_free(vals); - ldap_memfree(attr); - 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); - ldap_memfree(attr); - break; - } - - /* attributes only */ - if (lmap->ldap_attrsonly == LDAPMAP_TRUE) - { - if (*result == NULL) - *result = sm_rpool_strdup_x(rpool, - attr); - else - { - if (bitset(SM_LDAP_SINGLEMATCH, - flags) && - *result != NULL) - { - /* only wanted one match */ - SM_LDAP_ERROR_CLEANUP(); - errno = ENOENT; - return EX_NOTFOUND; - } - - vsize = strlen(*result) + - strlen(attr) + 2; - tmp = sm_rpool_malloc_x(rpool, - vsize); - (void) sm_snprintf(tmp, - vsize, "%s%c%s", - *result, (char) delim, - attr); - *result = tmp; - } - ldap_memfree(attr); - continue; - } - - /* - ** If there is more than one, munge then - ** into a map_coldelim separated string. - ** If we are recursing we may have an entry - ** with no 'normal' values to put in the - ** string. - ** This is not an error. - */ - - if (type == SM_LDAP_ATTR_NORMAL && - bitset(SM_LDAP_SINGLEMATCH, flags) && - *result != NULL) - { - /* only wanted one match */ - SM_LDAP_ERROR_CLEANUP(); - errno = ENOENT; - return EX_NOTFOUND; - } - - vsize = 0; - for (i = 0; vals[i] != NULL; i++) - { - if (type == SM_LDAP_ATTR_DN || - type == SM_LDAP_ATTR_FILTER || - type == SM_LDAP_ATTR_URL) - { - /* add to recursion */ - if (sm_ldap_add_recurse(&recurse, - vals[i], - type, - rpool) == NULL) - { - SM_LDAP_ERROR_CLEANUP(); - errno = ENOMEM; - return EX_OSERR; - } - continue; - } - - vsize += strlen(vals[i]) + 1; - if (lmap->ldap_attrsep != '\0') - vsize += strlen(attr) + 1; - } - - /* - ** Create/Append to string any normal - ** attribute values. Otherwise, just free - ** memory and move on to the next - ** attribute in this entry. - */ - - if (type == SM_LDAP_ATTR_NORMAL && vsize > 0) - { - char *pe; - - /* Grow result string if needed */ - if ((*resultln + vsize) >= *resultsz) - { - while ((*resultln + vsize) >= *resultsz) - { - if (*resultsz == 0) - *resultsz = 1024; - else - *resultsz *= 2; - } - - vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); - *vp_tmp = '\0'; - - if (*result != NULL) - sm_strlcpy(vp_tmp, - *result, - *resultsz); - *result = vp_tmp; - } - - p = *result + *resultln; - pe = *result + *resultsz; - - for (i = 0; vals[i] != NULL; i++) - { - if (*resultln > 0 && - p < pe) - *p++ = (char) delim; - - if (lmap->ldap_attrsep != '\0') - { - p += sm_strlcpy(p, attr, - pe - p); - if (p < pe) - *p++ = lmap->ldap_attrsep; - } - - p += sm_strlcpy(p, vals[i], - pe - p); - *resultln = p - (*result); - if (p >= pe) - { - /* Internal error: buffer too small for LDAP values */ - SM_LDAP_ERROR_CLEANUP(); - errno = ENOMEM; - return EX_OSERR; - } - } - } - - ldap_value_free(vals); - ldap_memfree(attr); - } - 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; - SM_LDAP_ERROR_CLEANUP(); - errno = save_errno; - return EX_TEMPFAIL; - } - - /* mark this DN as done */ - rl->lr_done = true; - if (rl->lr_ludp != NULL) - { - ldap_free_urldesc(rl->lr_ludp); - rl->lr_ludp = NULL; - } - if (rl->lr_attrs != NULL) - { - free(rl->lr_attrs); - rl->lr_attrs = NULL; - } - - /* We don't want multiple values and we have one */ - if ((char) delim == '\0' && - !bitset(SM_LDAP_SINGLEMATCH, flags) && - *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; - SM_LDAP_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; - } - SM_LDAP_ERROR_CLEANUP(); - errno = save_errno; - return statp; - } - - if (lmap->ldap_res != NULL) - { - ldap_msgfree(lmap->ldap_res); - lmap->ldap_res = NULL; - } - - if (toplevel) - { - int rlidx; - - /* - ** 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 (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++) - { - int newflags; - int sid; - int status; - - rl = recurse->lr_data[rlidx]; - - newflags = flags; - if (rl->lr_done) - { - /* already expanded */ - continue; - } - - if (rl->lr_type == SM_LDAP_ATTR_DN) - { - /* do DN search */ - sid = ldap_search(lmap->ldap_ld, - rl->lr_search, - lmap->ldap_scope, - "(objectClass=*)", - (lmap->ldap_attr[0] == NULL ? - NULL : lmap->ldap_attr), - lmap->ldap_attrsonly); - } - else if (rl->lr_type == SM_LDAP_ATTR_FILTER) - { - /* do new search */ - sid = ldap_search(lmap->ldap_ld, - lmap->ldap_base, - lmap->ldap_scope, - rl->lr_search, - (lmap->ldap_attr[0] == NULL ? - NULL : lmap->ldap_attr), - lmap->ldap_attrsonly); - } - else if (rl->lr_type == SM_LDAP_ATTR_URL) - { - /* Parse URL */ - sid = ldap_url_parse(rl->lr_search, - &rl->lr_ludp); - - if (sid != 0) - { - errno = sid + E_LDAPURLBASE; - return EX_TEMPFAIL; - } - - /* We need to add objectClass */ - if (rl->lr_ludp->lud_attrs != NULL) - { - int attrnum = 0; - - while (rl->lr_ludp->lud_attrs[attrnum] != NULL) - { - if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum], - "objectClass") == 0) - { - /* already requested */ - attrnum = -1; - break; - } - attrnum++; - } - - if (attrnum >= 0) - { - int i; - - rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2)); - if (rl->lr_attrs == NULL) - { - save_errno = errno; - ldap_free_urldesc(rl->lr_ludp); - errno = save_errno; - return EX_TEMPFAIL; - } - for (i = 0 ; i < attrnum; i++) - { - rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i]; - } - rl->lr_attrs[i++] = "objectClass"; - rl->lr_attrs[i++] = NULL; - } - } - - /* - ** Use the existing connection - ** for this search. It really - ** should use lud_scheme://lud_host:lud_port/ - ** instead but that would require - ** opening a new connection. - ** This should be fixed ASAP. - */ - - sid = ldap_search(lmap->ldap_ld, - rl->lr_ludp->lud_dn, - rl->lr_ludp->lud_scope, - rl->lr_ludp->lud_filter, - rl->lr_attrs, - lmap->ldap_attrsonly); - - /* Use the attributes specified by URL */ - newflags |= SM_LDAP_USE_ALLATTR; - } - 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, newflags, delim, - rpool, result, resultln, - resultsz, recurse); - save_errno = errno; - if (status != EX_OK && status != EX_NOTFOUND) - { - errno = save_errno; - return status; - } - - /* Mark as done */ - rl->lr_done = true; - if (rl->lr_ludp != NULL) - { - ldap_free_urldesc(rl->lr_ludp); - rl->lr_ludp = NULL; - } - if (rl->lr_attrs != NULL) - { - free(rl->lr_attrs); - rl->lr_attrs = NULL; - } - - /* Reset rlidx as new items may have been added */ - rlidx = -1; - } - } - return statp; -} - -/* -** 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 - if (lmap->ldap_version != 0) - { - ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, - &lmap->ldap_version); - } - 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); -# ifdef LDAP_OPT_RESTART - ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); -# endif /* LDAP_OPT_RESTART */ -# 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 */ |