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.67 2005/12/14 00:08:03 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
51 # if defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX
52 ERROR FFR_LDAP_VERSION > _LDAP_VERSION_MAX
53 # endif /* defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX */
54 # if defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN
55 ERROR FFR_LDAP_VERSION < _LDAP_VERSION_MIN
56 # endif /* defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN */
57 # define SM_LDAP_VERSION_DEFAULT _FFR_LDAP_VERSION
58 #else /* _FFR_LDAP_VERSION */
59 # define SM_LDAP_VERSION_DEFAULT 0
60 #endif /* _FFR_LDAP_VERSION */
69 lmap->ldap_host = NULL;
70 lmap->ldap_port = LDAP_PORT;
71 lmap->ldap_uri = NULL;
72 lmap->ldap_version = SM_LDAP_VERSION_DEFAULT;
73 lmap->ldap_deref = LDAP_DEREF_NEVER;
74 lmap->ldap_timelimit = LDAP_NO_LIMIT;
75 lmap->ldap_sizelimit = LDAP_NO_LIMIT;
76 # ifdef LDAP_REFERRALS
77 lmap->ldap_options = LDAP_OPT_REFERRALS;
78 # else /* LDAP_REFERRALS */
79 lmap->ldap_options = 0;
80 # endif /* LDAP_REFERRALS */
81 lmap->ldap_attrsep = '\0';
82 lmap->ldap_binddn = NULL;
83 lmap->ldap_secret = NULL;
84 lmap->ldap_method = LDAP_AUTH_SIMPLE;
85 lmap->ldap_base = NULL;
86 lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
87 lmap->ldap_attrsonly = LDAPMAP_FALSE;
88 lmap->ldap_timeout.tv_sec = 0;
89 lmap->ldap_timeout.tv_usec = 0;
91 lmap->ldap_filter = NULL;
92 lmap->ldap_attr[0] = NULL;
93 lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
94 lmap->ldap_attr_needobjclass[0] = NULL;
95 lmap->ldap_res = NULL;
96 lmap->ldap_next = NULL;
101 ** SM_LDAP_START -- actually connect to an LDAP server
104 ** name -- name of map for debug output.
105 ** lmap -- the LDAP map being opened.
108 ** true if connection is successful, false otherwise.
111 ** Populates lmap->ldap_ld.
114 static jmp_buf LDAPTimeout;
116 #define SM_LDAP_SETTIMEOUT(to) \
121 if (setjmp(LDAPTimeout) != 0) \
126 ev = sm_setevent(to, ldaptimeout, 0); \
130 #define SM_LDAP_CLEARTIMEOUT() \
138 sm_ldap_start(name, lmap)
140 SM_LDAP_STRUCT *lmap;
148 if (sm_debug_active(&SmLDAPTrace, 2))
149 sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
151 if (lmap->ldap_host != NULL)
152 id = lmap->ldap_host;
153 else if (lmap->ldap_uri != NULL)
158 if (sm_debug_active(&SmLDAPTrace, 9))
160 /* Don't print a port number for LDAP URIs */
161 if (lmap->ldap_uri != NULL)
162 sm_dprintf("ldapmap_start(%s)\n", id);
164 sm_dprintf("ldapmap_start(%s, %d)\n", id,
168 if (lmap->ldap_uri != NULL)
170 #if SM_CONF_LDAP_INITIALIZE
171 /* LDAP server supports URIs so use them directly */
172 save_errno = ldap_initialize(&ld, lmap->ldap_uri);
173 #else /* SM_CONF_LDAP_INITIALIZE */
175 LDAPURLDesc *ludp = NULL;
177 /* Blast apart URL and use the ldap_init/ldap_open below */
178 err = ldap_url_parse(lmap->ldap_uri, &ludp);
181 errno = err + E_LDAPURLBASE;
184 lmap->ldap_host = sm_strdup_x(ludp->lud_host);
185 if (lmap->ldap_host == NULL)
188 ldap_free_urldesc(ludp);
192 lmap->ldap_port = ludp->lud_port;
193 ldap_free_urldesc(ludp);
194 #endif /* SM_CONF_LDAP_INITIALIZE */
200 ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
202 # else /* USE_LDAP_INIT */
204 ** If using ldap_open(), the actual connection to the server
205 ** happens now so we need the timeout here. For ldap_init(),
206 ** the connection happens at bind time.
209 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
210 ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
213 /* clear the event if it has not sprung */
214 SM_LDAP_CLEARTIMEOUT();
215 # endif /* USE_LDAP_INIT */
222 sm_ldap_setopts(ld, lmap);
226 ** If using ldap_init(), the actual connection to the server
227 ** happens at ldap_bind_s() so we need the timeout here.
230 SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
231 # endif /* USE_LDAP_INIT */
233 # ifdef LDAP_AUTH_KRBV4
234 if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
235 lmap->ldap_secret != NULL)
238 ** Need to put ticket in environment here instead of
239 ** during parseargs as there may be different tickets
240 ** for different LDAP connections.
243 (void) putenv(lmap->ldap_secret);
245 # endif /* LDAP_AUTH_KRBV4 */
247 bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
248 lmap->ldap_secret, lmap->ldap_method);
251 /* clear the event if it has not sprung */
252 SM_LDAP_CLEARTIMEOUT();
253 # endif /* USE_LDAP_INIT */
255 if (bind_result != LDAP_SUCCESS)
257 errno = bind_result + E_LDAPBASE;
261 /* Save PID to make sure only this PID closes the LDAP connection */
262 lmap->ldap_pid = getpid();
273 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
274 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
279 longjmp(LDAPTimeout, 1);
283 ** SM_LDAP_SEARCH -- initiate LDAP search
285 ** Initiate an LDAP search, return the msgid.
286 ** The calling function must collect the results.
289 ** lmap -- LDAP map information
290 ** key -- key to substitute in LDAP filter
293 ** -1 on failure, msgid on success
298 sm_ldap_search(lmap, key)
299 SM_LDAP_STRUCT *lmap;
304 char filter[LDAPMAP_MAX_FILTER + 1];
306 /* substitute key into filter, perhaps multiple times */
307 memset(filter, '\0', sizeof filter);
309 p = lmap->ldap_filter;
310 while ((q = strchr(p, '%')) != NULL)
314 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
315 "%.*s%s", (int) (q - p), p, key);
319 else if (q[1] == '0')
323 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
324 "%.*s", (int) (q - p), p);
328 /* Properly escape LDAP special characters */
329 while (SPACELEFT(filter, fp) > 0 &&
332 if (*k == '*' || *k == '(' ||
333 *k == ')' || *k == '\\')
335 (void) sm_strlcat(fp,
336 (*k == '*' ? "\\2A" :
337 (*k == '(' ? "\\28" :
338 (*k == ')' ? "\\29" :
339 (*k == '\\' ? "\\5C" :
341 SPACELEFT(filter, fp));
351 (void) sm_snprintf(fp, SPACELEFT(filter, fp),
352 "%.*s", (int) (q - p + 1), p);
353 p = q + (q[1] == '%' ? 2 : 1);
357 (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
358 if (sm_debug_active(&SmLDAPTrace, 20))
359 sm_dprintf("ldap search filter=%s\n", filter);
361 lmap->ldap_res = NULL;
362 msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
363 lmap->ldap_scope, filter,
364 (lmap->ldap_attr[0] == NULL ? NULL :
366 lmap->ldap_attrsonly);
371 ** SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
372 ** particular objectClass
375 ** lmap -- pointer to SM_LDAP_STRUCT in use
376 ** entry -- current LDAP entry struct
377 ** ocvalue -- particular objectclass in question.
378 ** may be of form (fee|foo|fum) meaning
379 ** any entry can be part of either fee,
380 ** foo or fum objectclass
383 ** true if item has that objectClass
387 sm_ldap_has_objectclass(lmap, entry, ocvalue)
388 SM_LDAP_STRUCT *lmap;
398 vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
402 for (i = 0; vals[i] != NULL; i++)
410 while (*p != '\0' && *p != '|')
413 if ((p - q) == strlen(vals[i]) &&
414 sm_strncasecmp(vals[i], q, p - q) == 0)
416 ldap_value_free(vals);
426 ldap_value_free(vals);
431 ** SM_LDAP_RESULTS -- return results from an LDAP lookup in result
434 ** lmap -- pointer to SM_LDAP_STRUCT in use
435 ** msgid -- msgid returned by sm_ldap_search()
436 ** flags -- flags for the lookup
437 ** delim -- delimiter for result concatenation
438 ** rpool -- memory pool for storage
439 ** result -- return string
440 ** recurse -- recursion list
446 # define SM_LDAP_ERROR_CLEANUP() \
448 if (lmap->ldap_res != NULL) \
450 ldap_msgfree(lmap->ldap_res); \
451 lmap->ldap_res = NULL; \
453 (void) ldap_abandon(lmap->ldap_ld, msgid); \
456 static SM_LDAP_RECURSE_ENTRY *
457 sm_ldap_add_recurse(top, item, type, rpool)
458 SM_LDAP_RECURSE_LIST **top;
470 SM_LDAP_RECURSE_ENTRY *newe;
471 SM_LDAP_RECURSE_ENTRY **olddata;
474 ** This code will maintain a list of
475 ** SM_LDAP_RECURSE_ENTRY structures
476 ** in ascending order.
481 /* Allocate an initial SM_LDAP_RECURSE_LIST struct */
482 *top = sm_rpool_malloc_x(rpool, sizeof **top);
485 (*top)->lr_data = NULL;
488 if ((*top)->lr_cnt >= (*top)->lr_size)
490 /* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
491 olddata = (*top)->lr_data;
492 if ((*top)->lr_size == 0)
495 (*top)->lr_size = 256;
499 oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data);
500 (*top)->lr_size *= 2;
502 (*top)->lr_data = sm_rpool_malloc_x(rpool,
503 (*top)->lr_size * sizeof *((*top)->lr_data));
505 memcpy((*top)->lr_data, olddata, oldsizeb);
509 ** Binary search/insert item:type into list.
510 ** Return current entry pointer if already exists.
514 m = (*top)->lr_cnt - 1;
520 while (insertat == -1)
524 rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search);
526 rc = type - (*top)->lr_data[p]->lr_type;
533 return (*top)->lr_data[p];
537 else if (n >= (*top)->lr_cnt)
538 insertat = (*top)->lr_cnt;
544 ** Not found in list, make room
545 ** at insert point and add it.
548 newe = sm_rpool_malloc_x(rpool, sizeof *newe);
551 moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data);
553 memmove(&((*top)->lr_data[insertat + 1]),
554 &((*top)->lr_data[insertat]),
557 newe->lr_search = sm_rpool_strdup_x(rpool, item);
558 newe->lr_type = type;
559 newe->lr_ludp = NULL;
560 newe->lr_attrs = NULL;
561 newe->lr_done = false;
563 ((*top)->lr_data)[insertat] = newe;
570 sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
571 resultln, resultsz, recurse)
572 SM_LDAP_STRUCT *lmap;
580 SM_LDAP_RECURSE_LIST *recurse;
589 SM_LDAP_RECURSE_ENTRY *rl;
591 /* Are we the top top level of the search? */
592 toplevel = (recurse == NULL);
596 while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
597 (lmap->ldap_timeout.tv_sec == 0 ? NULL :
598 &(lmap->ldap_timeout)),
599 &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
603 /* If we don't want multiple values and we have one, break */
604 if ((char) delim == '\0' &&
605 !bitset(SM_LDAP_SINGLEMATCH, flags) &&
609 /* Cycle through all entries */
610 for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
612 entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
620 ** If matching only and found an entry,
621 ** no need to spin through attributes
624 if (bitset(SM_LDAP_MATCHONLY, flags))
630 #if _FFR_LDAP_SINGLEDN
631 if (bitset(SM_LDAP_SINGLEDN, flags) && *result != NULL)
633 /* only wanted one match */
634 SM_LDAP_ERROR_CLEANUP();
638 #endif /* _FFR_LDAP_SINGLEDN */
640 /* record completed DN's to prevent loops */
641 dn = ldap_get_dn(lmap->ldap_ld, entry);
644 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
645 save_errno += E_LDAPBASE;
646 SM_LDAP_ERROR_CLEANUP();
651 rl = sm_ldap_add_recurse(&recurse, dn,
658 SM_LDAP_ERROR_CLEANUP();
662 else if (rl->lr_done)
664 /* already on list, skip it */
670 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
672 ** Reset value to prevent lingering
673 ** LDAP_DECODING_ERROR due to
674 ** OpenLDAP 1.X's hack (see below)
677 lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
678 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
680 for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
683 attr = ldap_next_attribute(lmap->ldap_ld, entry,
688 char *needobjclass = NULL;
690 type = SM_LDAP_ATTR_NONE;
691 for (i = 0; lmap->ldap_attr[i] != NULL; i++)
693 if (sm_strcasecmp(lmap->ldap_attr[i],
696 type = lmap->ldap_attr_type[i];
697 needobjclass = lmap->ldap_attr_needobjclass[i];
702 if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
703 type == SM_LDAP_ATTR_NONE)
705 /* URL lookups specify attrs to use */
706 type = SM_LDAP_ATTR_NORMAL;
710 if (type == SM_LDAP_ATTR_NONE)
712 /* attribute not requested */
714 SM_LDAP_ERROR_CLEANUP();
720 ** For recursion on a particular attribute,
721 ** we may need to see if this entry is
722 ** part of a particular objectclass.
723 ** Also, ignore objectClass attribute.
724 ** Otherwise we just ignore this attribute.
727 if (type == SM_LDAP_ATTR_OBJCLASS ||
728 (needobjclass != NULL &&
729 !sm_ldap_has_objectclass(lmap, entry,
736 if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
738 vals = ldap_get_values(lmap->ldap_ld,
743 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
744 if (save_errno == LDAP_SUCCESS)
750 /* Must be an error */
751 save_errno += E_LDAPBASE;
753 SM_LDAP_ERROR_CLEANUP();
761 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
763 ** Reset value to prevent lingering
764 ** LDAP_DECODING_ERROR due to
765 ** OpenLDAP 1.X's hack (see below)
768 lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
769 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
773 ** no need to spin through entries
776 if (bitset(SM_LDAP_MATCHONLY, flags))
778 if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
779 ldap_value_free(vals);
785 ** If we don't want multiple values,
786 ** return first found.
789 if ((char) delim == '\0')
793 /* already have a value */
794 if (bitset(SM_LDAP_SINGLEMATCH,
797 /* only wanted one match */
798 SM_LDAP_ERROR_CLEANUP();
805 if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
807 *result = sm_rpool_strdup_x(rpool,
815 ldap_value_free(vals);
820 vsize = strlen(vals[0]) + 1;
821 if (lmap->ldap_attrsep != '\0')
822 vsize += strlen(attr) + 1;
823 *result = sm_rpool_malloc_x(rpool,
825 if (lmap->ldap_attrsep != '\0')
826 sm_snprintf(*result, vsize,
832 sm_strlcpy(*result, vals[0],
834 ldap_value_free(vals);
839 /* attributes only */
840 if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
843 *result = sm_rpool_strdup_x(rpool,
847 if (bitset(SM_LDAP_SINGLEMATCH,
851 /* only wanted one match */
852 SM_LDAP_ERROR_CLEANUP();
857 vsize = strlen(*result) +
859 tmp = sm_rpool_malloc_x(rpool,
861 (void) sm_snprintf(tmp,
863 *result, (char) delim,
872 ** If there is more than one, munge then
873 ** into a map_coldelim separated string.
874 ** If we are recursing we may have an entry
875 ** with no 'normal' values to put in the
877 ** This is not an error.
880 if (type == SM_LDAP_ATTR_NORMAL &&
881 bitset(SM_LDAP_SINGLEMATCH, flags) &&
884 /* only wanted one match */
885 SM_LDAP_ERROR_CLEANUP();
891 for (i = 0; vals[i] != NULL; i++)
893 if (type == SM_LDAP_ATTR_DN ||
894 type == SM_LDAP_ATTR_FILTER ||
895 type == SM_LDAP_ATTR_URL)
897 /* add to recursion */
898 if (sm_ldap_add_recurse(&recurse,
903 SM_LDAP_ERROR_CLEANUP();
910 vsize += strlen(vals[i]) + 1;
911 if (lmap->ldap_attrsep != '\0')
912 vsize += strlen(attr) + 1;
916 ** Create/Append to string any normal
917 ** attribute values. Otherwise, just free
918 ** memory and move on to the next
919 ** attribute in this entry.
922 if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
926 /* Grow result string if needed */
927 if ((*resultln + vsize) >= *resultsz)
929 while ((*resultln + vsize) >= *resultsz)
937 vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
947 p = *result + *resultln;
948 pe = *result + *resultsz;
950 for (i = 0; vals[i] != NULL; i++)
956 if (lmap->ldap_attrsep != '\0')
958 p += sm_strlcpy(p, attr,
961 *p++ = lmap->ldap_attrsep;
964 p += sm_strlcpy(p, vals[i],
966 *resultln = p - (*result);
969 /* Internal error: buffer too small for LDAP values */
970 SM_LDAP_ERROR_CLEANUP();
977 ldap_value_free(vals);
980 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
983 ** We check save_errno != LDAP_DECODING_ERROR since
984 ** OpenLDAP 1.X has a very ugly *undocumented*
985 ** hack of returning this error code from
986 ** ldap_next_attribute() if the library freed the
987 ** ber attribute. See:
988 ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
991 if (save_errno != LDAP_SUCCESS &&
992 save_errno != LDAP_DECODING_ERROR)
994 /* Must be an error */
995 save_errno += E_LDAPBASE;
996 SM_LDAP_ERROR_CLEANUP();
1001 /* mark this DN as done */
1003 if (rl->lr_ludp != NULL)
1005 ldap_free_urldesc(rl->lr_ludp);
1008 if (rl->lr_attrs != NULL)
1011 rl->lr_attrs = NULL;
1014 /* We don't want multiple values and we have one */
1015 if ((char) delim == '\0' &&
1016 !bitset(SM_LDAP_SINGLEMATCH, flags) &&
1020 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1021 if (save_errno != LDAP_SUCCESS &&
1022 save_errno != LDAP_DECODING_ERROR)
1024 /* Must be an error */
1025 save_errno += E_LDAPBASE;
1026 SM_LDAP_ERROR_CLEANUP();
1030 ldap_msgfree(lmap->ldap_res);
1031 lmap->ldap_res = NULL;
1035 save_errno = ETIMEDOUT;
1037 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1038 if (save_errno != LDAP_SUCCESS)
1040 statp = EX_TEMPFAIL;
1045 #ifdef LDAP_SERVER_DOWN
1046 case LDAP_SERVER_DOWN:
1047 #endif /* LDAP_SERVER_DOWN */
1049 case LDAP_UNAVAILABLE:
1052 ** server disappeared,
1053 ** try reopen on next search
1059 save_errno += E_LDAPBASE;
1061 SM_LDAP_ERROR_CLEANUP();
1066 if (lmap->ldap_res != NULL)
1068 ldap_msgfree(lmap->ldap_res);
1069 lmap->ldap_res = NULL;
1077 ** Spin through the built-up recurse list at the top
1078 ** of the recursion. Since new items are added at the
1079 ** end of the shared list, we actually only ever get
1080 ** one level of recursion before things pop back to the
1081 ** top. Any items added to the list during that recursion
1082 ** will be expanded by the top level.
1085 for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)
1091 rl = recurse->lr_data[rlidx];
1096 /* already expanded */
1100 if (rl->lr_type == SM_LDAP_ATTR_DN)
1103 sid = ldap_search(lmap->ldap_ld,
1107 (lmap->ldap_attr[0] == NULL ?
1108 NULL : lmap->ldap_attr),
1109 lmap->ldap_attrsonly);
1111 else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
1114 sid = ldap_search(lmap->ldap_ld,
1118 (lmap->ldap_attr[0] == NULL ?
1119 NULL : lmap->ldap_attr),
1120 lmap->ldap_attrsonly);
1122 else if (rl->lr_type == SM_LDAP_ATTR_URL)
1125 sid = ldap_url_parse(rl->lr_search,
1130 errno = sid + E_LDAPURLBASE;
1134 /* We need to add objectClass */
1135 if (rl->lr_ludp->lud_attrs != NULL)
1139 while (rl->lr_ludp->lud_attrs[attrnum] != NULL)
1141 if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum],
1142 "objectClass") == 0)
1144 /* already requested */
1155 rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2));
1156 if (rl->lr_attrs == NULL)
1159 ldap_free_urldesc(rl->lr_ludp);
1163 for (i = 0 ; i < attrnum; i++)
1165 rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i];
1167 rl->lr_attrs[i++] = "objectClass";
1168 rl->lr_attrs[i++] = NULL;
1173 ** Use the existing connection
1174 ** for this search. It really
1175 ** should use lud_scheme://lud_host:lud_port/
1176 ** instead but that would require
1177 ** opening a new connection.
1178 ** This should be fixed ASAP.
1181 sid = ldap_search(lmap->ldap_ld,
1182 rl->lr_ludp->lud_dn,
1183 rl->lr_ludp->lud_scope,
1184 rl->lr_ludp->lud_filter,
1186 lmap->ldap_attrsonly);
1188 /* Use the attributes specified by URL */
1189 newflags |= SM_LDAP_USE_ALLATTR;
1193 /* unknown or illegal attribute type */
1198 /* Collect results */
1201 save_errno = sm_ldap_geterrno(lmap->ldap_ld);
1202 statp = EX_TEMPFAIL;
1205 #ifdef LDAP_SERVER_DOWN
1206 case LDAP_SERVER_DOWN:
1207 #endif /* LDAP_SERVER_DOWN */
1209 case LDAP_UNAVAILABLE:
1212 ** server disappeared,
1213 ** try reopen on next search
1219 errno = save_errno + E_LDAPBASE;
1223 status = sm_ldap_results(lmap, sid, newflags, delim,
1224 rpool, result, resultln,
1227 if (status != EX_OK && status != EX_NOTFOUND)
1235 if (rl->lr_ludp != NULL)
1237 ldap_free_urldesc(rl->lr_ludp);
1240 if (rl->lr_attrs != NULL)
1243 rl->lr_attrs = NULL;
1246 /* Reset rlidx as new items may have been added */
1254 ** SM_LDAP_CLOSE -- close LDAP connection
1257 ** lmap -- LDAP map information
1266 SM_LDAP_STRUCT *lmap;
1268 if (lmap->ldap_ld == NULL)
1271 if (lmap->ldap_pid == getpid())
1272 ldap_unbind(lmap->ldap_ld);
1273 lmap->ldap_ld = NULL;
1278 ** SM_LDAP_SETOPTS -- set LDAP options
1281 ** ld -- LDAP session handle
1282 ** lmap -- LDAP map information
1290 sm_ldap_setopts(ld, lmap)
1292 SM_LDAP_STRUCT *lmap;
1294 # if USE_LDAP_SET_OPTION
1295 if (lmap->ldap_version != 0)
1297 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
1298 &lmap->ldap_version);
1300 ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
1301 if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
1302 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1304 ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1305 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
1306 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
1307 # ifdef LDAP_OPT_RESTART
1308 ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1309 # endif /* LDAP_OPT_RESTART */
1310 # else /* USE_LDAP_SET_OPTION */
1311 /* From here on in we can use ldap internal timelimits */
1312 ld->ld_deref = lmap->ldap_deref;
1313 ld->ld_options = lmap->ldap_options;
1314 ld->ld_sizelimit = lmap->ldap_sizelimit;
1315 ld->ld_timelimit = lmap->ldap_timelimit;
1316 # endif /* USE_LDAP_SET_OPTION */
1320 ** SM_LDAP_GETERRNO -- get ldap errno value
1323 ** ld -- LDAP session handle
1331 sm_ldap_geterrno(ld)
1334 int err = LDAP_SUCCESS;
1336 # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
1337 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
1338 # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1339 # ifdef LDAP_OPT_SIZELIMIT
1340 err = ldap_get_lderrno(ld, NULL, NULL);
1341 # else /* LDAP_OPT_SIZELIMIT */
1345 ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
1346 ** OpenLDAP 1.X's hack (see above)
1349 ld->ld_errno = LDAP_SUCCESS;
1350 # endif /* LDAP_OPT_SIZELIMIT */
1351 # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
1354 # endif /* LDAPMAP */