2 * Copyright (c) 2001-2005 Sendmail, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
11 SM_RCSID("@(#)$Id: ldap.c,v 1.62 2005/02/24 00:30:01 ca Exp $")
14 # include <sys/types.h>
20 # include <sm/bitops.h>
21 # include <sm/clock.h>
23 # include <sm/debug.h>
24 # include <sm/errstring.h>
26 # include <sm/string.h>
28 # undef EX_OK /* for SVr4.2 SMP */
30 # include <sm/sysexits.h>
32 SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
33 "@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
35 static void ldaptimeout __P((int));
36 static bool sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *));
37 static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *));
40 ** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
43 ** lmap -- pointer to SM_LDAP_STRUCT to clear
57 lmap->ldap_host = NULL;
58 lmap->ldap_port = LDAP_PORT;
59 lmap->ldap_uri = NULL;
60 lmap->ldap_version = 0;
61 lmap->ldap_deref = LDAP_DEREF_NEVER;
62 lmap->ldap_timelimit = LDAP_NO_LIMIT;
63 lmap->ldap_sizelimit = LDAP_NO_LIMIT;
64 # ifdef LDAP_REFERRALS
65 lmap->ldap_options = LDAP_OPT_REFERRALS;
66 # else /* LDAP_REFERRALS */
67 lmap->ldap_options = 0;
68 # endif /* LDAP_REFERRALS */
69 lmap->ldap_attrsep = '\0';
70 lmap->ldap_binddn = NULL;
71 lmap->ldap_secret = NULL;
72 lmap->ldap_method = LDAP_AUTH_SIMPLE;
73 lmap->ldap_base = NULL;
74 lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
75 lmap->ldap_attrsonly = LDAPMAP_FALSE;
76 lmap->ldap_timeout.tv_sec = 0;
77 lmap->ldap_timeout.tv_usec = 0;
79 lmap->ldap_filter = NULL;
80 lmap->ldap_attr[0] = NULL;
81 lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
82 lmap->ldap_attr_needobjclass[0] = NULL;
83 lmap->ldap_res = NULL;
84 lmap->ldap_next = NULL;
89 ** SM_LDAP_START -- actually connect to an LDAP server
92 ** name -- name of map for debug output.
93 ** lmap -- the LDAP map being opened.
96 ** true if connection is successful, false otherwise.
99 ** Populates lmap->ldap_ld.
102 static jmp_buf LDAPTimeout;
104 #define SM_LDAP_SETTIMEOUT(to) \
109 if (setjmp(LDAPTimeout) != 0) \
114 ev = sm_setevent(to, ldaptimeout, 0); \
118 #define SM_LDAP_CLEARTIMEOUT() \
126 sm_ldap_start(name, lmap)
128 SM_LDAP_STRUCT *lmap;
136 if (sm_debug_active(&SmLDAPTrace, 2))
137 sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
139 if (lmap->ldap_host != NULL)
140 id = lmap->ldap_host;
141 else if (lmap->ldap_uri != NULL)
146 if (sm_debug_active(&SmLDAPTrace, 9))
148 /* Don't print a port number for LDAP URIs */
149 if (lmap->ldap_uri != NULL)
150 sm_dprintf("ldapmap_start(%s)\n", id);
152 sm_dprintf("ldapmap_start(%s, %d)\n", id,
156 if (lmap->ldap_uri != NULL)
158 #if SM_CONF_LDAP_INITIALIZE
159 /* LDAP server supports URIs so use them directly */
160 save_errno = ldap_initialize(&ld, lmap->ldap_uri);
161 #else /* SM_CONF_LDAP_INITIALIZE */
163 LDAPURLDesc *ludp = NULL;
165 /* Blast apart URL and use the ldap_init/ldap_open below */
166 err = ldap_url_parse(lmap->ldap_uri, &ludp);
169 errno = err + E_LDAPURLBASE;
172 lmap->ldap_host = sm_strdup_x(ludp->lud_host);
173 if (lmap->ldap_host == NULL)
176 ldap_free_urldesc(ludp);
180 lmap->ldap_port = ludp->lud_port;
181 ldap_free_urldesc(ludp);
182 #endif /* SM_CONF_LDAP_INITIALIZE */
188 ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
190 # else /* USE_LDAP_INIT */
192 ** If using ldap_open(), the actual connection to the server
193 ** happens now so we need the timeout here. For ldap_init(),
194 ** the connection happens at bind time.
197 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
198 ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
201 /* clear the event if it has not sprung */
202 SM_LDAP_CLEARTIMEOUT();
203 # endif /* USE_LDAP_INIT */
210 sm_ldap_setopts(ld, lmap);
214 ** If using ldap_init(), the actual connection to the server
215 ** happens at ldap_bind_s() so we need the timeout here.
218 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
219 # endif /* USE_LDAP_INIT */
221 # ifdef LDAP_AUTH_KRBV4
222 if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
223 lmap->ldap_secret != NULL)
226 ** Need to put ticket in environment here instead of
227 ** during parseargs as there may be different tickets
228 ** for different LDAP connections.
231 (void) putenv(lmap->ldap_secret);
233 # endif /* LDAP_AUTH_KRBV4 */
235 bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
236 lmap->ldap_secret, lmap->ldap_method);
239 /* clear the event if it has not sprung */
240 SM_LDAP_CLEARTIMEOUT();
241 # endif /* USE_LDAP_INIT */
243 if (bind_result != LDAP_SUCCESS)
245 errno = bind_result + E_LDAPBASE;
249 /* Save PID to make sure only this PID closes the LDAP connection */
250 lmap->ldap_pid = getpid();
261 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
262 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
267 longjmp(LDAPTimeout, 1);
271 ** SM_LDAP_SEARCH -- initiate LDAP search
273 ** Initiate an LDAP search, return the msgid.
274 ** The calling function must collect the results.
277 ** lmap -- LDAP map information
278 ** key -- key to substitute in LDAP filter
281 ** -1 on failure, msgid on success
286 sm_ldap_search(lmap, key)
287 SM_LDAP_STRUCT *lmap;
292 char filter[LDAPMAP_MAX_FILTER + 1];
294 /* substitute key into filter, perhaps multiple times */
295 memset(filter, '\0', sizeof filter);
297 p = lmap->ldap_filter;
298 while ((q = strchr(p, '%')) != NULL)
302 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
303 "%.*s%s", (int) (q - p), p, key);
307 else if (q[1] == '0')
311 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
312 "%.*s", (int) (q - p), p);
316 /* Properly escape LDAP special characters */
317 while (SPACELEFT(filter, fp) > 0 &&
320 if (*k == '*' || *k == '(' ||
321 *k == ')' || *k == '\\')
323 (void) sm_strlcat(fp,
324 (*k == '*' ? "\\2A" :
325 (*k == '(' ? "\\28" :
326 (*k == ')' ? "\\29" :
327 (*k == '\\' ? "\\5C" :
329 SPACELEFT(filter, fp));
339 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
340 "%.*s", (int) (q - p + 1), p);
341 p = q + (q[1] == '%' ? 2 : 1);
345 (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
346 if (sm_debug_active(&SmLDAPTrace, 20))
347 sm_dprintf("ldap search filter=%s\n", filter);
349 lmap->ldap_res = NULL;
350 msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
351 lmap->ldap_scope, filter,
352 (lmap->ldap_attr[0] == NULL ? NULL :
354 lmap->ldap_attrsonly);
359 ** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
360 ** particular objectClass
363 ** lmap -- pointer to SM_LDAP_STRUCT in use
364 ** entry -- current LDAP entry struct
365 ** ocvalue -- particular objectclass in question.
366 ** may be of form (fee|foo|fum) meaning
367 ** any entry can be part of either fee,
368 ** foo or fum objectclass
371 ** true if item has that objectClass
375 sm_ldap_has_objectclass(lmap, entry, ocvalue)
376 SM_LDAP_STRUCT *lmap;
386 vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
390 for (i = 0; vals[i] != NULL; i++)
398 while (*p != '\0' && *p != '|')
401 if ((p - q) == strlen(vals[i]) &&
402 sm_strncasecmp(vals[i], q, p - q) == 0)
404 ldap_value_free(vals);
414 ldap_value_free(vals);
419 ** SM_LDAP_RESULTS -- return results from an LDAP lookup in result
422 ** lmap -- pointer to SM_LDAP_STRUCT in use
423 ** msgid -- msgid returned by sm_ldap_search()
424 ** flags -- flags for the lookup
425 ** delim -- delimiter for result concatenation
426 ** rpool -- memory pool for storage
427 ** result -- return string
428 ** recurse -- recursion list
434 # define SM_LDAP_ERROR_CLEANUP() \
436 if (lmap->ldap_res != NULL) \
438 ldap_msgfree(lmap->ldap_res); \
439 lmap->ldap_res = NULL; \
441 (void) ldap_abandon(lmap->ldap_ld, msgid); \
444 static SM_LDAP_RECURSE_ENTRY *
445 sm_ldap_add_recurse(top, item, type, rpool)
446 SM_LDAP_RECURSE_LIST **top;
458 SM_LDAP_RECURSE_ENTRY *newe;
459 SM_LDAP_RECURSE_ENTRY **olddata;
462 ** This code will maintain a list of
463 ** SM_LDAP_RECURSE_ENTRY structures
464 ** in ascending order.
469 /* Allocate an initial SM_LDAP_RECURSE_LIST struct */
470 *top = sm_rpool_malloc_x(rpool, sizeof **top);
473 (*top)->lr_data = NULL;
476 if ((*top)->lr_cnt >= (*top)->lr_size)
478 /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
479 olddata = (*top)->lr_data;
480 if ((*top)->lr_size == 0)
483 (*top)->lr_size = 256;
487 oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data);
488 (*top)->lr_size *= 2;
490 (*top)->lr_data = sm_rpool_malloc_x(rpool,
491 (*top)->lr_size * sizeof *((*top)->lr_data));
493 memcpy((*top)->lr_data, olddata, oldsizeb);
497 ** Binary search/insert item:type into list.
498 ** Return current entry pointer if already exists.
502 m = (*top)->lr_cnt - 1;
508 while (insertat == -1)
512 rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search);
514 rc = type - (*top)->lr_data[p]->lr_type;
521 return (*top)->lr_data[p];
525 else if (n >= (*top)->lr_cnt)
526 insertat = (*top)->lr_cnt;
532 ** Not found in list, make room
533 ** at insert point and add it.
536 newe = sm_rpool_malloc_x(rpool, sizeof *newe);
539 moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data);
541 memmove(&((*top)->lr_data[insertat + 1]),
542 &((*top)->lr_data[insertat]),
545 newe->lr_search = sm_rpool_strdup_x(rpool, item);
546 newe->lr_type = type;
547 newe->lr_ludp = NULL;
548 newe->lr_attrs = NULL;
549 newe->lr_done = false;
551 ((*top)->lr_data)[insertat] = newe;
558 sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
559 resultln, resultsz, recurse)
560 SM_LDAP_STRUCT *lmap;
568 SM_LDAP_RECURSE_LIST *recurse;
577 SM_LDAP_RECURSE_ENTRY *rl;
579 /* Are we the top top level of the search? */
580 toplevel = (recurse == NULL);
584 while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
585 (lmap->ldap_timeout.tv_sec == 0 ? NULL :
586 &(lmap->ldap_timeout)),
587 &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
591 /* If we don't want multiple values and we have one, break */
592 if ((char) delim == '\0' &&
593 !bitset(SM_LDAP_SINGLEMATCH, flags) &&
597 /* Cycle through all entries */
598 for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
600 entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
608 ** If matching only and found an entry,
609 ** no need to spin through attributes
612 if (bitset(SM_LDAP_MATCHONLY, flags))
618 /* record completed DN's to prevent loops */
619 dn = ldap_get_dn(lmap->ldap_ld, entry);
622 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
623 save_errno += E_LDAPBASE;
624 SM_LDAP_ERROR_CLEANUP();
629 rl = sm_ldap_add_recurse(&recurse, dn,
636 SM_LDAP_ERROR_CLEANUP();
640 else if (rl->lr_done)
642 /* already on list, skip it */
648 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
650 ** Reset value to prevent lingering
651 ** LDAP_DECODING_ERROR due to
652 ** OpenLDAP 1.X's hack (see below)
655 lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
656 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
658 for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
661 attr = ldap_next_attribute(lmap->ldap_ld, entry,
666 char *needobjclass = NULL;
668 type = SM_LDAP_ATTR_NONE;
669 for (i = 0; lmap->ldap_attr[i] != NULL; i++)
671 if (sm_strcasecmp(lmap->ldap_attr[i],
674 type = lmap->ldap_attr_type[i];
675 needobjclass = lmap->ldap_attr_needobjclass[i];
680 if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
681 type == SM_LDAP_ATTR_NONE)
683 /* URL lookups specify attrs to use */
684 type = SM_LDAP_ATTR_NORMAL;
688 if (type == SM_LDAP_ATTR_NONE)
690 /* attribute not requested */
692 SM_LDAP_ERROR_CLEANUP();
698 ** For recursion on a particular attribute,
699 ** we may need to see if this entry is
700 ** part of a particular objectclass.
701 ** Also, ignore objectClass attribute.
702 ** Otherwise we just ignore this attribute.
705 if (type == SM_LDAP_ATTR_OBJCLASS ||
706 (needobjclass != NULL &&
707 !sm_ldap_has_objectclass(lmap, entry,
714 if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
716 vals = ldap_get_values(lmap->ldap_ld,
721 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
722 if (save_errno == LDAP_SUCCESS)
728 /* Must be an error */
729 save_errno += E_LDAPBASE;
731 SM_LDAP_ERROR_CLEANUP();
739 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
741 ** Reset value to prevent lingering
742 ** LDAP_DECODING_ERROR due to
743 ** OpenLDAP 1.X's hack (see below)
746 lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
747 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
751 ** no need to spin through entries
754 if (bitset(SM_LDAP_MATCHONLY, flags))
756 if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
757 ldap_value_free(vals);
763 ** If we don't want multiple values,
764 ** return first found.
767 if ((char) delim == '\0')
771 /* already have a value */
772 if (bitset(SM_LDAP_SINGLEMATCH,
775 /* only wanted one match */
776 SM_LDAP_ERROR_CLEANUP();
783 if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
785 *result = sm_rpool_strdup_x(rpool,
793 ldap_value_free(vals);
798 vsize = strlen(vals[0]) + 1;
799 if (lmap->ldap_attrsep != '\0')
800 vsize += strlen(attr) + 1;
801 *result = sm_rpool_malloc_x(rpool,
803 if (lmap->ldap_attrsep != '\0')
804 sm_snprintf(*result, vsize,
810 sm_strlcpy(*result, vals[0],
812 ldap_value_free(vals);
817 /* attributes only */
818 if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
821 *result = sm_rpool_strdup_x(rpool,
825 if (bitset(SM_LDAP_SINGLEMATCH,
829 /* only wanted one match */
830 SM_LDAP_ERROR_CLEANUP();
835 vsize = strlen(*result) +
837 tmp = sm_rpool_malloc_x(rpool,
839 (void) sm_snprintf(tmp,
841 *result, (char) delim,
850 ** If there is more than one, munge then
851 ** into a map_coldelim separated string.
852 ** If we are recursing we may have an entry
853 ** with no 'normal' values to put in the
855 ** This is not an error.
858 if (type == SM_LDAP_ATTR_NORMAL &&
859 bitset(SM_LDAP_SINGLEMATCH, flags) &&
862 /* only wanted one match */
863 SM_LDAP_ERROR_CLEANUP();
869 for (i = 0; vals[i] != NULL; i++)
871 if (type == SM_LDAP_ATTR_DN ||
872 type == SM_LDAP_ATTR_FILTER ||
873 type == SM_LDAP_ATTR_URL)
875 /* add to recursion */
876 if (sm_ldap_add_recurse(&recurse,
881 SM_LDAP_ERROR_CLEANUP();
888 vsize += strlen(vals[i]) + 1;
889 if (lmap->ldap_attrsep != '\0')
890 vsize += strlen(attr) + 1;
894 ** Create/Append to string any normal
895 ** attribute values. Otherwise, just free
896 ** memory and move on to the next
897 ** attribute in this entry.
900 if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
904 /* Grow result string if needed */
905 if ((*resultln + vsize) >= *resultsz)
907 while ((*resultln + vsize) >= *resultsz)
915 vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
925 p = *result + *resultln;
926 pe = *result + *resultsz;
928 for (i = 0; vals[i] != NULL; i++)
934 if (lmap->ldap_attrsep != '\0')
936 p += sm_strlcpy(p, attr,
939 *p++ = lmap->ldap_attrsep;
942 p += sm_strlcpy(p, vals[i],
944 *resultln = p - (*result);
947 /* Internal error: buffer too small for LDAP values */
948 SM_LDAP_ERROR_CLEANUP();
955 ldap_value_free(vals);
958 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
961 ** We check save_errno != LDAP_DECODING_ERROR since
962 ** OpenLDAP 1.X has a very ugly *undocumented*
963 ** hack of returning this error code from
964 ** ldap_next_attribute() if the library freed the
965 ** ber attribute. See:
966 ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
969 if (save_errno != LDAP_SUCCESS &&
970 save_errno != LDAP_DECODING_ERROR)
972 /* Must be an error */
973 save_errno += E_LDAPBASE;
974 SM_LDAP_ERROR_CLEANUP();
979 /* mark this DN as done */
981 if (rl->lr_ludp != NULL)
983 ldap_free_urldesc(rl->lr_ludp);
986 if (rl->lr_attrs != NULL)
992 /* We don't want multiple values and we have one */
993 if ((char) delim == '\0' &&
994 !bitset(SM_LDAP_SINGLEMATCH, flags) &&
998 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
999 if (save_errno != LDAP_SUCCESS &&
1000 save_errno != LDAP_DECODING_ERROR)
1002 /* Must be an error */
1003 save_errno += E_LDAPBASE;
1004 SM_LDAP_ERROR_CLEANUP();
1008 ldap_msgfree(lmap->ldap_res);
1009 lmap->ldap_res = NULL;
1013 save_errno = ETIMEDOUT;
1015 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1016 if (save_errno != LDAP_SUCCESS)
1018 statp = EX_TEMPFAIL;
1023 #ifdef LDAP_SERVER_DOWN
1024 case LDAP_SERVER_DOWN:
1025 #endif /* LDAP_SERVER_DOWN */
1027 case LDAP_UNAVAILABLE:
1030 ** server disappeared,
1031 ** try reopen on next search
1037 save_errno += E_LDAPBASE;
1039 SM_LDAP_ERROR_CLEANUP();
1044 if (lmap->ldap_res != NULL)
1046 ldap_msgfree(lmap->ldap_res);
1047 lmap->ldap_res = NULL;
1055 ** Spin through the built-up recurse list at the top
1056 ** of the recursion. Since new items are added at the
1057 ** end of the shared list, we actually only ever get
1058 ** one level of recursion before things pop back to the
1059 ** top. Any items added to the list during that recursion
1060 ** will be expanded by the top level.
1063 for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)
1069 rl = recurse->lr_data[rlidx];
1074 /* already expanded */
1078 if (rl->lr_type == SM_LDAP_ATTR_DN)
1081 sid = ldap_search(lmap->ldap_ld,
1085 (lmap->ldap_attr[0] == NULL ?
1086 NULL : lmap->ldap_attr),
1087 lmap->ldap_attrsonly);
1089 else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
1092 sid = ldap_search(lmap->ldap_ld,
1096 (lmap->ldap_attr[0] == NULL ?
1097 NULL : lmap->ldap_attr),
1098 lmap->ldap_attrsonly);
1100 else if (rl->lr_type == SM_LDAP_ATTR_URL)
1103 sid = ldap_url_parse(rl->lr_search,
1108 errno = sid + E_LDAPURLBASE;
1112 /* We need to add objectClass */
1113 if (rl->lr_ludp->lud_attrs != NULL)
1117 while (rl->lr_ludp->lud_attrs[attrnum] != NULL)
1119 if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum],
1120 "objectClass") == 0)
1122 /* already requested */
1133 rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2));
1134 if (rl->lr_attrs == NULL)
1137 ldap_free_urldesc(rl->lr_ludp);
1141 for (i = 0 ; i < attrnum; i++)
1143 rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i];
1145 rl->lr_attrs[i++] = "objectClass";
1146 rl->lr_attrs[i++] = NULL;
1151 ** Use the existing connection
1152 ** for this search. It really
1153 ** should use lud_scheme://lud_host:lud_port/
1154 ** instead but that would require
1155 ** opening a new connection.
1156 ** This should be fixed ASAP.
1159 sid = ldap_search(lmap->ldap_ld,
1160 rl->lr_ludp->lud_dn,
1161 rl->lr_ludp->lud_scope,
1162 rl->lr_ludp->lud_filter,
1164 lmap->ldap_attrsonly);
1166 /* Use the attributes specified by URL */
1167 newflags |= SM_LDAP_USE_ALLATTR;
1171 /* unknown or illegal attribute type */
1176 /* Collect results */
1179 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1180 statp = EX_TEMPFAIL;
1183 #ifdef LDAP_SERVER_DOWN
1184 case LDAP_SERVER_DOWN:
1185 #endif /* LDAP_SERVER_DOWN */
1187 case LDAP_UNAVAILABLE:
1190 ** server disappeared,
1191 ** try reopen on next search
1197 errno = save_errno + E_LDAPBASE;
1201 status = sm_ldap_results(lmap, sid, newflags, delim,
1202 rpool, result, resultln,
1205 if (status != EX_OK && status != EX_NOTFOUND)
1213 if (rl->lr_ludp != NULL)
1215 ldap_free_urldesc(rl->lr_ludp);
1218 if (rl->lr_attrs != NULL)
1221 rl->lr_attrs = NULL;
1224 /* Reset rlidx as new items may have been added */
1232 ** SM_LDAP_CLOSE -- close LDAP connection
1235 ** lmap -- LDAP map information
1244 SM_LDAP_STRUCT *lmap;
1246 if (lmap->ldap_ld == NULL)
1249 if (lmap->ldap_pid == getpid())
1250 ldap_unbind(lmap->ldap_ld);
1251 lmap->ldap_ld = NULL;
1256 ** SM_LDAP_SETOPTS -- set LDAP options
1259 ** ld -- LDAP session handle
1260 ** lmap -- LDAP map information
1268 sm_ldap_setopts(ld, lmap)
1270 SM_LDAP_STRUCT *lmap;
1272 # if USE_LDAP_SET_OPTION
1273 if (lmap->ldap_version != 0)
1275 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
1276 &lmap->ldap_version);
1278 ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
1279 if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
1280 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1282 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1283 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
1284 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
1285 # ifdef LDAP_OPT_RESTART
1286 ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1287 # endif /* LDAP_OPT_RESTART */
1288 # else /* USE_LDAP_SET_OPTION */
1289 /* From here on in we can use ldap internal timelimits */
1290 ld->ld_deref = lmap->ldap_deref;
1291 ld->ld_options = lmap->ldap_options;
1292 ld->ld_sizelimit = lmap->ldap_sizelimit;
1293 ld->ld_timelimit = lmap->ldap_timelimit;
1294 # endif /* USE_LDAP_SET_OPTION */
1298 ** SM_LDAP_GETERRNO -- get ldap errno value
1301 ** ld -- LDAP session handle
1309 sm_ldap_geterrno(ld)
1312 int err = LDAP_SUCCESS;
1314 # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
1315 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
1316 # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1317 # ifdef LDAP_OPT_SIZELIMIT
1318 err = ldap_get_lderrno(ld, NULL, NULL);
1319 # else /* LDAP_OPT_SIZELIMIT */
1323 ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
1324 ** OpenLDAP 1.X's hack (see above)
1327 ld->ld_errno = LDAP_SUCCESS;
1328 # endif /* LDAP_OPT_SIZELIMIT */
1329 # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1332 # endif /* LDAPMAP */