xref: /freebsd/contrib/sendmail/libsm/ldap.c (revision 323f6dcb88194c5561fc9e314d5b98539ab3fe5a)
140266059SGregory Neil Shapiro /*
2323f6dcbSGregory Neil Shapiro  * Copyright (c) 2001-2003 Sendmail, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *      All rights reserved.
440266059SGregory Neil Shapiro  *
540266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
640266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
740266059SGregory Neil Shapiro  * the sendmail distribution.
840266059SGregory Neil Shapiro  */
940266059SGregory Neil Shapiro 
1040266059SGregory Neil Shapiro #include <sm/gen.h>
11323f6dcbSGregory Neil Shapiro SM_RCSID("@(#)$Id: ldap.c,v 1.44.2.5 2003/12/23 21:21:56 gshapiro Exp $")
1240266059SGregory Neil Shapiro 
1340266059SGregory Neil Shapiro #if LDAPMAP
1440266059SGregory Neil Shapiro # include <sys/types.h>
1540266059SGregory Neil Shapiro # include <errno.h>
1640266059SGregory Neil Shapiro # include <setjmp.h>
1740266059SGregory Neil Shapiro # include <stdlib.h>
1840266059SGregory Neil Shapiro # include <unistd.h>
1940266059SGregory Neil Shapiro 
2040266059SGregory Neil Shapiro # include <sm/bitops.h>
2140266059SGregory Neil Shapiro # include <sm/clock.h>
2240266059SGregory Neil Shapiro # include <sm/conf.h>
2340266059SGregory Neil Shapiro # include <sm/debug.h>
2440266059SGregory Neil Shapiro # include <sm/errstring.h>
2540266059SGregory Neil Shapiro # include <sm/ldap.h>
2640266059SGregory Neil Shapiro # include <sm/string.h>
27605302a5SGregory Neil Shapiro #  ifdef EX_OK
28605302a5SGregory Neil Shapiro #   undef EX_OK			/* for SVr4.2 SMP */
29605302a5SGregory Neil Shapiro #  endif /* EX_OK */
3040266059SGregory Neil Shapiro # include <sm/sysexits.h>
3140266059SGregory Neil Shapiro 
3240266059SGregory Neil Shapiro SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
3340266059SGregory Neil Shapiro 	"@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
3440266059SGregory Neil Shapiro 
3540266059SGregory Neil Shapiro static void	ldaptimeout __P((int));
3640266059SGregory Neil Shapiro 
3740266059SGregory Neil Shapiro /*
3840266059SGregory Neil Shapiro **  SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
3940266059SGregory Neil Shapiro **
4040266059SGregory Neil Shapiro **	Parameters:
4140266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT to clear
4240266059SGregory Neil Shapiro **
4340266059SGregory Neil Shapiro **	Returns:
4440266059SGregory Neil Shapiro **		None.
4540266059SGregory Neil Shapiro **
4640266059SGregory Neil Shapiro */
4740266059SGregory Neil Shapiro 
4840266059SGregory Neil Shapiro void
4940266059SGregory Neil Shapiro sm_ldap_clear(lmap)
5040266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
5140266059SGregory Neil Shapiro {
5240266059SGregory Neil Shapiro 	if (lmap == NULL)
5340266059SGregory Neil Shapiro 		return;
5440266059SGregory Neil Shapiro 
55605302a5SGregory Neil Shapiro 	lmap->ldap_target = NULL;
5640266059SGregory Neil Shapiro 	lmap->ldap_port = LDAP_PORT;
57605302a5SGregory Neil Shapiro #if _FFR_LDAP_URI
58605302a5SGregory Neil Shapiro 	lmap->ldap_uri = false;
59605302a5SGregory Neil Shapiro #endif /* _FFR_LDAP_URI */
60605302a5SGregory Neil Shapiro #  if _FFR_LDAP_SETVERSION
61605302a5SGregory Neil Shapiro 	lmap->ldap_version = 0;
62605302a5SGregory Neil Shapiro #  endif /* _FFR_LDAP_SETVERSION */
6340266059SGregory Neil Shapiro 	lmap->ldap_deref = LDAP_DEREF_NEVER;
6440266059SGregory Neil Shapiro 	lmap->ldap_timelimit = LDAP_NO_LIMIT;
6540266059SGregory Neil Shapiro 	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
6640266059SGregory Neil Shapiro # ifdef LDAP_REFERRALS
6740266059SGregory Neil Shapiro 	lmap->ldap_options = LDAP_OPT_REFERRALS;
6840266059SGregory Neil Shapiro # else /* LDAP_REFERRALS */
6940266059SGregory Neil Shapiro 	lmap->ldap_options = 0;
7040266059SGregory Neil Shapiro # endif /* LDAP_REFERRALS */
7140266059SGregory Neil Shapiro 	lmap->ldap_attrsep = '\0';
7240266059SGregory Neil Shapiro 	lmap->ldap_binddn = NULL;
7340266059SGregory Neil Shapiro 	lmap->ldap_secret = NULL;
7440266059SGregory Neil Shapiro 	lmap->ldap_method = LDAP_AUTH_SIMPLE;
7540266059SGregory Neil Shapiro 	lmap->ldap_base = NULL;
7640266059SGregory Neil Shapiro 	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
7740266059SGregory Neil Shapiro 	lmap->ldap_attrsonly = LDAPMAP_FALSE;
7840266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_sec = 0;
7940266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_usec = 0;
8040266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
8140266059SGregory Neil Shapiro 	lmap->ldap_filter = NULL;
8240266059SGregory Neil Shapiro 	lmap->ldap_attr[0] = NULL;
8340266059SGregory Neil Shapiro #if _FFR_LDAP_RECURSION
84605302a5SGregory Neil Shapiro 	lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
85605302a5SGregory Neil Shapiro 	lmap->ldap_attr_needobjclass[0] = NULL;
8640266059SGregory Neil Shapiro #endif /* _FFR_LDAP_RECURSION */
8740266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
8840266059SGregory Neil Shapiro 	lmap->ldap_next = NULL;
8940266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
9040266059SGregory Neil Shapiro }
9140266059SGregory Neil Shapiro 
9240266059SGregory Neil Shapiro /*
9340266059SGregory Neil Shapiro **  SM_LDAP_START -- actually connect to an LDAP server
9440266059SGregory Neil Shapiro **
9540266059SGregory Neil Shapiro **	Parameters:
9640266059SGregory Neil Shapiro **		name -- name of map for debug output.
9740266059SGregory Neil Shapiro **		lmap -- the LDAP map being opened.
9840266059SGregory Neil Shapiro **
9940266059SGregory Neil Shapiro **	Returns:
10040266059SGregory Neil Shapiro **		true if connection is successful, false otherwise.
10140266059SGregory Neil Shapiro **
10240266059SGregory Neil Shapiro **	Side Effects:
10340266059SGregory Neil Shapiro **		Populates lmap->ldap_ld.
10440266059SGregory Neil Shapiro */
10540266059SGregory Neil Shapiro 
10640266059SGregory Neil Shapiro static jmp_buf	LDAPTimeout;
10740266059SGregory Neil Shapiro 
10840266059SGregory Neil Shapiro #define SM_LDAP_SETTIMEOUT(to)						\
10940266059SGregory Neil Shapiro do									\
11040266059SGregory Neil Shapiro {									\
11140266059SGregory Neil Shapiro 	if (to != 0)							\
11240266059SGregory Neil Shapiro 	{								\
11340266059SGregory Neil Shapiro 		if (setjmp(LDAPTimeout) != 0)				\
11440266059SGregory Neil Shapiro 		{							\
11540266059SGregory Neil Shapiro 			errno = ETIMEDOUT;				\
11640266059SGregory Neil Shapiro 			return false;					\
11740266059SGregory Neil Shapiro 		}							\
11840266059SGregory Neil Shapiro 		ev = sm_setevent(to, ldaptimeout, 0);			\
11940266059SGregory Neil Shapiro 	}								\
12040266059SGregory Neil Shapiro } while (0)
12140266059SGregory Neil Shapiro 
12240266059SGregory Neil Shapiro #define SM_LDAP_CLEARTIMEOUT()						\
12340266059SGregory Neil Shapiro do									\
12440266059SGregory Neil Shapiro {									\
12540266059SGregory Neil Shapiro 	if (ev != NULL)							\
12640266059SGregory Neil Shapiro 		sm_clrevent(ev);					\
12740266059SGregory Neil Shapiro } while (0)
12840266059SGregory Neil Shapiro 
12940266059SGregory Neil Shapiro bool
13040266059SGregory Neil Shapiro sm_ldap_start(name, lmap)
13140266059SGregory Neil Shapiro 	char *name;
13240266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
13340266059SGregory Neil Shapiro {
13440266059SGregory Neil Shapiro 	int bind_result;
13540266059SGregory Neil Shapiro 	int save_errno;
13640266059SGregory Neil Shapiro 	SM_EVENT *ev = NULL;
13740266059SGregory Neil Shapiro 	LDAP *ld;
13840266059SGregory Neil Shapiro 
13940266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 2))
14040266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
14140266059SGregory Neil Shapiro 
14240266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
14340266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s, %d)\n",
144605302a5SGregory Neil Shapiro 			   lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target,
14540266059SGregory Neil Shapiro 			   lmap->ldap_port);
14640266059SGregory Neil Shapiro 
14740266059SGregory Neil Shapiro # if USE_LDAP_INIT
148605302a5SGregory Neil Shapiro #  if _FFR_LDAP_URI
149605302a5SGregory Neil Shapiro 	if (lmap->ldap_uri)
150605302a5SGregory Neil Shapiro 		errno = ldap_initialize(&ld, lmap->ldap_target);
151605302a5SGregory Neil Shapiro 	else
152605302a5SGregory Neil Shapiro #  endif /* _FFR_LDAP_URI */
153605302a5SGregory Neil Shapiro 		ld = ldap_init(lmap->ldap_target, lmap->ldap_port);
15440266059SGregory Neil Shapiro 	save_errno = errno;
15540266059SGregory Neil Shapiro # else /* USE_LDAP_INIT */
15640266059SGregory Neil Shapiro 	/*
15740266059SGregory Neil Shapiro 	**  If using ldap_open(), the actual connection to the server
15840266059SGregory Neil Shapiro 	**  happens now so we need the timeout here.  For ldap_init(),
15940266059SGregory Neil Shapiro 	**  the connection happens at bind time.
16040266059SGregory Neil Shapiro 	*/
16140266059SGregory Neil Shapiro 
16240266059SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
163605302a5SGregory Neil Shapiro 	ld = ldap_open(lmap->ldap_target, lmap->ldap_port);
16440266059SGregory Neil Shapiro 	save_errno = errno;
16540266059SGregory Neil Shapiro 
16640266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
16740266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
16840266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
16940266059SGregory Neil Shapiro 
17040266059SGregory Neil Shapiro 	errno = save_errno;
17140266059SGregory Neil Shapiro 	if (ld == NULL)
17240266059SGregory Neil Shapiro 		return false;
17340266059SGregory Neil Shapiro 
17440266059SGregory Neil Shapiro 	sm_ldap_setopts(ld, lmap);
17540266059SGregory Neil Shapiro 
17640266059SGregory Neil Shapiro # if USE_LDAP_INIT
17740266059SGregory Neil Shapiro 	/*
17840266059SGregory Neil Shapiro 	**  If using ldap_init(), the actual connection to the server
17940266059SGregory Neil Shapiro 	**  happens at ldap_bind_s() so we need the timeout here.
18040266059SGregory Neil Shapiro 	*/
18140266059SGregory Neil Shapiro 
18240266059SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
18340266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
18440266059SGregory Neil Shapiro 
18540266059SGregory Neil Shapiro # ifdef LDAP_AUTH_KRBV4
18640266059SGregory Neil Shapiro 	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
18740266059SGregory Neil Shapiro 	    lmap->ldap_secret != NULL)
18840266059SGregory Neil Shapiro 	{
18940266059SGregory Neil Shapiro 		/*
19040266059SGregory Neil Shapiro 		**  Need to put ticket in environment here instead of
19140266059SGregory Neil Shapiro 		**  during parseargs as there may be different tickets
19240266059SGregory Neil Shapiro 		**  for different LDAP connections.
19340266059SGregory Neil Shapiro 		*/
19440266059SGregory Neil Shapiro 
19540266059SGregory Neil Shapiro 		(void) putenv(lmap->ldap_secret);
19640266059SGregory Neil Shapiro 	}
19740266059SGregory Neil Shapiro # endif /* LDAP_AUTH_KRBV4 */
19840266059SGregory Neil Shapiro 
19940266059SGregory Neil Shapiro 	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
20040266059SGregory Neil Shapiro 				  lmap->ldap_secret, lmap->ldap_method);
20140266059SGregory Neil Shapiro 
20240266059SGregory Neil Shapiro # if USE_LDAP_INIT
20340266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
20440266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
20540266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
20640266059SGregory Neil Shapiro 
20740266059SGregory Neil Shapiro 	if (bind_result != LDAP_SUCCESS)
20840266059SGregory Neil Shapiro 	{
20940266059SGregory Neil Shapiro 		errno = bind_result + E_LDAPBASE;
21040266059SGregory Neil Shapiro 		return false;
21140266059SGregory Neil Shapiro 	}
21240266059SGregory Neil Shapiro 
21340266059SGregory Neil Shapiro 	/* Save PID to make sure only this PID closes the LDAP connection */
21440266059SGregory Neil Shapiro 	lmap->ldap_pid = getpid();
21540266059SGregory Neil Shapiro 	lmap->ldap_ld = ld;
21640266059SGregory Neil Shapiro 	return true;
21740266059SGregory Neil Shapiro }
21840266059SGregory Neil Shapiro 
21940266059SGregory Neil Shapiro /* ARGSUSED */
22040266059SGregory Neil Shapiro static void
22140266059SGregory Neil Shapiro ldaptimeout(unused)
22240266059SGregory Neil Shapiro 	int unused;
22340266059SGregory Neil Shapiro {
22440266059SGregory Neil Shapiro 	/*
22540266059SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
22640266059SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
22740266059SGregory Neil Shapiro 	**	DOING.
22840266059SGregory Neil Shapiro 	*/
22940266059SGregory Neil Shapiro 
23040266059SGregory Neil Shapiro 	errno = ETIMEDOUT;
23140266059SGregory Neil Shapiro 	longjmp(LDAPTimeout, 1);
23240266059SGregory Neil Shapiro }
23340266059SGregory Neil Shapiro 
23440266059SGregory Neil Shapiro /*
23540266059SGregory Neil Shapiro **  SM_LDAP_SEARCH -- iniate LDAP search
23640266059SGregory Neil Shapiro **
23740266059SGregory Neil Shapiro **	Initiate an LDAP search, return the msgid.
23840266059SGregory Neil Shapiro **	The calling function must collect the results.
23940266059SGregory Neil Shapiro **
24040266059SGregory Neil Shapiro **	Parameters:
24140266059SGregory Neil Shapiro **		lmap -- LDAP map information
24240266059SGregory Neil Shapiro **		key -- key to substitute in LDAP filter
24340266059SGregory Neil Shapiro **
24440266059SGregory Neil Shapiro **	Returns:
24540266059SGregory Neil Shapiro **		-1 on failure, msgid on success
24640266059SGregory Neil Shapiro **
24740266059SGregory Neil Shapiro */
24840266059SGregory Neil Shapiro 
24940266059SGregory Neil Shapiro int
25040266059SGregory Neil Shapiro sm_ldap_search(lmap, key)
25140266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
25240266059SGregory Neil Shapiro 	char *key;
25340266059SGregory Neil Shapiro {
25440266059SGregory Neil Shapiro 	int msgid;
25540266059SGregory Neil Shapiro 	char *fp, *p, *q;
25640266059SGregory Neil Shapiro 	char filter[LDAPMAP_MAX_FILTER + 1];
25740266059SGregory Neil Shapiro 
25840266059SGregory Neil Shapiro 	/* substitute key into filter, perhaps multiple times */
25940266059SGregory Neil Shapiro 	memset(filter, '\0', sizeof filter);
26040266059SGregory Neil Shapiro 	fp = filter;
26140266059SGregory Neil Shapiro 	p = lmap->ldap_filter;
26240266059SGregory Neil Shapiro 	while ((q = strchr(p, '%')) != NULL)
26340266059SGregory Neil Shapiro 	{
26440266059SGregory Neil Shapiro 		if (q[1] == 's')
26540266059SGregory Neil Shapiro 		{
26640266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
26740266059SGregory Neil Shapiro 					   "%.*s%s", (int) (q - p), p, key);
26840266059SGregory Neil Shapiro 			fp += strlen(fp);
26940266059SGregory Neil Shapiro 			p = q + 2;
27040266059SGregory Neil Shapiro 		}
27140266059SGregory Neil Shapiro 		else if (q[1] == '0')
27240266059SGregory Neil Shapiro 		{
27340266059SGregory Neil Shapiro 			char *k = key;
27440266059SGregory Neil Shapiro 
27540266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
27640266059SGregory Neil Shapiro 					   "%.*s", (int) (q - p), p);
27740266059SGregory Neil Shapiro 			fp += strlen(fp);
27840266059SGregory Neil Shapiro 			p = q + 2;
27940266059SGregory Neil Shapiro 
28040266059SGregory Neil Shapiro 			/* Properly escape LDAP special characters */
28140266059SGregory Neil Shapiro 			while (SPACELEFT(filter, fp) > 0 &&
28240266059SGregory Neil Shapiro 			       *k != '\0')
28340266059SGregory Neil Shapiro 			{
28440266059SGregory Neil Shapiro 				if (*k == '*' || *k == '(' ||
28540266059SGregory Neil Shapiro 				    *k == ')' || *k == '\\')
28640266059SGregory Neil Shapiro 				{
28740266059SGregory Neil Shapiro 					(void) sm_strlcat(fp,
28840266059SGregory Neil Shapiro 						       (*k == '*' ? "\\2A" :
28940266059SGregory Neil Shapiro 							(*k == '(' ? "\\28" :
29040266059SGregory Neil Shapiro 							 (*k == ')' ? "\\29" :
29140266059SGregory Neil Shapiro 							  (*k == '\\' ? "\\5C" :
29240266059SGregory Neil Shapiro 							   "\00")))),
29340266059SGregory Neil Shapiro 						SPACELEFT(filter, fp));
29440266059SGregory Neil Shapiro 					fp += strlen(fp);
29540266059SGregory Neil Shapiro 					k++;
29640266059SGregory Neil Shapiro 				}
29740266059SGregory Neil Shapiro 				else
29840266059SGregory Neil Shapiro 					*fp++ = *k++;
29940266059SGregory Neil Shapiro 			}
30040266059SGregory Neil Shapiro 		}
30140266059SGregory Neil Shapiro 		else
30240266059SGregory Neil Shapiro 		{
30340266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
30440266059SGregory Neil Shapiro 				"%.*s", (int) (q - p + 1), p);
30540266059SGregory Neil Shapiro 			p = q + (q[1] == '%' ? 2 : 1);
30640266059SGregory Neil Shapiro 			fp += strlen(fp);
30740266059SGregory Neil Shapiro 		}
30840266059SGregory Neil Shapiro 	}
30940266059SGregory Neil Shapiro 	(void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
31040266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 20))
31140266059SGregory Neil Shapiro 		sm_dprintf("ldap search filter=%s\n", filter);
31240266059SGregory Neil Shapiro 
31340266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
314605302a5SGregory Neil Shapiro 	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
315605302a5SGregory Neil Shapiro 			    lmap->ldap_scope, filter,
31640266059SGregory Neil Shapiro 			    (lmap->ldap_attr[0] == NULL ? NULL :
31740266059SGregory Neil Shapiro 			     lmap->ldap_attr),
31840266059SGregory Neil Shapiro 			    lmap->ldap_attrsonly);
31940266059SGregory Neil Shapiro 	return msgid;
32040266059SGregory Neil Shapiro }
32140266059SGregory Neil Shapiro 
32240266059SGregory Neil Shapiro # if _FFR_LDAP_RECURSION
32340266059SGregory Neil Shapiro /*
324605302a5SGregory Neil Shapiro **  SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
325605302a5SGregory Neil Shapiro **			       particular objectClass
326605302a5SGregory Neil Shapiro **
327605302a5SGregory Neil Shapiro **	Parameters:
328605302a5SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
329605302a5SGregory Neil Shapiro **		entry -- current LDAP entry struct
330605302a5SGregory Neil Shapiro **		ocvalue -- particular objectclass in question.
331605302a5SGregory Neil Shapiro **			   may be of form (fee|foo|fum) meaning
332605302a5SGregory Neil Shapiro **			   any entry can be part of either fee,
333605302a5SGregory Neil Shapiro **			   foo or fum objectclass
334605302a5SGregory Neil Shapiro **
335605302a5SGregory Neil Shapiro **	Returns:
336605302a5SGregory Neil Shapiro **		true if item has that objectClass
337605302a5SGregory Neil Shapiro */
338605302a5SGregory Neil Shapiro 
339605302a5SGregory Neil Shapiro static bool
340605302a5SGregory Neil Shapiro sm_ldap_has_objectclass(lmap, entry, ocvalue)
341605302a5SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
342605302a5SGregory Neil Shapiro 	LDAPMessage *entry;
343605302a5SGregory Neil Shapiro 	char *ocvalue;
344605302a5SGregory Neil Shapiro {
345605302a5SGregory Neil Shapiro 	char **vals = NULL;
346605302a5SGregory Neil Shapiro 	int i;
347605302a5SGregory Neil Shapiro 
348605302a5SGregory Neil Shapiro 	if (ocvalue == NULL)
349605302a5SGregory Neil Shapiro 		return false;
350605302a5SGregory Neil Shapiro 
351605302a5SGregory Neil Shapiro 	vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
352605302a5SGregory Neil Shapiro 	if (vals == NULL)
353605302a5SGregory Neil Shapiro 		return false;
354605302a5SGregory Neil Shapiro 
355605302a5SGregory Neil Shapiro 	for (i = 0; vals[i] != NULL; i++)
356605302a5SGregory Neil Shapiro 	{
357605302a5SGregory Neil Shapiro 		char *p;
358605302a5SGregory Neil Shapiro 		char *q;
359605302a5SGregory Neil Shapiro 
360605302a5SGregory Neil Shapiro 		p = q = ocvalue;
361605302a5SGregory Neil Shapiro 		while (*p != '\0')
362605302a5SGregory Neil Shapiro 		{
363605302a5SGregory Neil Shapiro 			while (*p != '\0' && *p != '|')
364605302a5SGregory Neil Shapiro 				p++;
365605302a5SGregory Neil Shapiro 
366605302a5SGregory Neil Shapiro 			if ((p - q) == strlen(vals[i]) &&
367605302a5SGregory Neil Shapiro 			    sm_strncasecmp(vals[i], q, p - q) == 0)
368605302a5SGregory Neil Shapiro 			{
369605302a5SGregory Neil Shapiro 				ldap_value_free(vals);
370605302a5SGregory Neil Shapiro 				return true;
371605302a5SGregory Neil Shapiro 			}
372605302a5SGregory Neil Shapiro 
373605302a5SGregory Neil Shapiro 			while (*p == '|')
374605302a5SGregory Neil Shapiro 				p++;
375605302a5SGregory Neil Shapiro 			q = p;
376605302a5SGregory Neil Shapiro 		}
377605302a5SGregory Neil Shapiro 	}
378605302a5SGregory Neil Shapiro 
379605302a5SGregory Neil Shapiro 	ldap_value_free(vals);
380605302a5SGregory Neil Shapiro 	return false;
381605302a5SGregory Neil Shapiro }
382605302a5SGregory Neil Shapiro 
383605302a5SGregory Neil Shapiro /*
38440266059SGregory Neil Shapiro **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
38540266059SGregory Neil Shapiro **
38640266059SGregory Neil Shapiro **	Parameters:
38740266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
38840266059SGregory Neil Shapiro **		msgid -- msgid returned by sm_ldap_search()
38940266059SGregory Neil Shapiro **		flags -- flags for the lookup
39040266059SGregory Neil Shapiro **		delim -- delimiter for result concatenation
39140266059SGregory Neil Shapiro **		rpool -- memory pool for storage
39240266059SGregory Neil Shapiro **		result -- return string
39340266059SGregory Neil Shapiro **		recurse -- recursion list
39440266059SGregory Neil Shapiro **
39540266059SGregory Neil Shapiro **	Returns:
39640266059SGregory Neil Shapiro **		status (sysexit)
39740266059SGregory Neil Shapiro */
39840266059SGregory Neil Shapiro 
399605302a5SGregory Neil Shapiro # define SM_LDAP_ERROR_CLEANUP()				\
40040266059SGregory Neil Shapiro {								\
40140266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)				\
40240266059SGregory Neil Shapiro 	{							\
40340266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);			\
40440266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;				\
40540266059SGregory Neil Shapiro 	}							\
40640266059SGregory Neil Shapiro 	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
40740266059SGregory Neil Shapiro }
40840266059SGregory Neil Shapiro 
409605302a5SGregory Neil Shapiro static SM_LDAP_RECURSE_ENTRY *
410605302a5SGregory Neil Shapiro sm_ldap_add_recurse(top, item, type, rpool)
41140266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST **top;
41240266059SGregory Neil Shapiro 	char *item;
41340266059SGregory Neil Shapiro 	int type;
41440266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
41540266059SGregory Neil Shapiro {
416605302a5SGregory Neil Shapiro 	int n;
417605302a5SGregory Neil Shapiro 	int m;
418605302a5SGregory Neil Shapiro 	int p;
419605302a5SGregory Neil Shapiro 	int insertat;
420605302a5SGregory Neil Shapiro 	int moveb;
421605302a5SGregory Neil Shapiro 	int oldsizeb;
422605302a5SGregory Neil Shapiro 	int rc;
423605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *newe;
424605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY **olddata;
42540266059SGregory Neil Shapiro 
426605302a5SGregory Neil Shapiro 	/*
427605302a5SGregory Neil Shapiro 	**  This code will maintain a list of
428605302a5SGregory Neil Shapiro 	**  SM_LDAP_RECURSE_ENTRY structures
429605302a5SGregory Neil Shapiro 	**  in ascending order.
430605302a5SGregory Neil Shapiro 	*/
431605302a5SGregory Neil Shapiro 
432605302a5SGregory Neil Shapiro 	if (*top == NULL)
43340266059SGregory Neil Shapiro 	{
434605302a5SGregory Neil Shapiro 		/* Allocate an initial SM_LDAP_RECURSE_LIST struct */
435605302a5SGregory Neil Shapiro 		*top = sm_rpool_malloc_x(rpool, sizeof **top);
436605302a5SGregory Neil Shapiro 		(*top)->lr_cnt = 0;
437605302a5SGregory Neil Shapiro 		(*top)->lr_size = 0;
438605302a5SGregory Neil Shapiro 		(*top)->lr_data = NULL;
43940266059SGregory Neil Shapiro 	}
44040266059SGregory Neil Shapiro 
441605302a5SGregory Neil Shapiro 	if ((*top)->lr_cnt >= (*top)->lr_size)
442605302a5SGregory Neil Shapiro 	{
443605302a5SGregory Neil Shapiro 		/* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
444605302a5SGregory Neil Shapiro 		olddata = (*top)->lr_data;
445605302a5SGregory Neil Shapiro 		if ((*top)->lr_size == 0)
446605302a5SGregory Neil Shapiro 		{
447605302a5SGregory Neil Shapiro 			oldsizeb = 0;
448605302a5SGregory Neil Shapiro 			(*top)->lr_size = 256;
449605302a5SGregory Neil Shapiro 		}
45040266059SGregory Neil Shapiro 		else
451605302a5SGregory Neil Shapiro 		{
452605302a5SGregory Neil Shapiro 			oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data);
453605302a5SGregory Neil Shapiro 			(*top)->lr_size *= 2;
454605302a5SGregory Neil Shapiro 		}
455605302a5SGregory Neil Shapiro 		(*top)->lr_data = sm_rpool_malloc_x(rpool,
456605302a5SGregory Neil Shapiro 						    (*top)->lr_size * sizeof *((*top)->lr_data));
457605302a5SGregory Neil Shapiro 		if (oldsizeb > 0)
458605302a5SGregory Neil Shapiro 			memcpy((*top)->lr_data, olddata, oldsizeb);
459605302a5SGregory Neil Shapiro 	}
460605302a5SGregory Neil Shapiro 
461605302a5SGregory Neil Shapiro 	/*
462605302a5SGregory Neil Shapiro 	**  Binary search/insert item:type into list.
463605302a5SGregory Neil Shapiro 	**  Return current entry pointer if already exists.
464605302a5SGregory Neil Shapiro 	*/
465605302a5SGregory Neil Shapiro 
466605302a5SGregory Neil Shapiro 	n = 0;
467605302a5SGregory Neil Shapiro 	m = (*top)->lr_cnt - 1;
468605302a5SGregory Neil Shapiro 	if (m < 0)
469605302a5SGregory Neil Shapiro 		insertat = 0;
470605302a5SGregory Neil Shapiro 	else
471605302a5SGregory Neil Shapiro 		insertat = -1;
472605302a5SGregory Neil Shapiro 
473605302a5SGregory Neil Shapiro 	while (insertat == -1)
474605302a5SGregory Neil Shapiro 	{
475605302a5SGregory Neil Shapiro 		p = (m + n) / 2;
476605302a5SGregory Neil Shapiro 
477605302a5SGregory Neil Shapiro 		rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search);
478605302a5SGregory Neil Shapiro 		if (rc == 0)
479605302a5SGregory Neil Shapiro 			rc = type - (*top)->lr_data[p]->lr_type;
480605302a5SGregory Neil Shapiro 
481605302a5SGregory Neil Shapiro 		if (rc < 0)
482605302a5SGregory Neil Shapiro 			m = p - 1;
483605302a5SGregory Neil Shapiro 		else if (rc > 0)
484605302a5SGregory Neil Shapiro 			n = p + 1;
485605302a5SGregory Neil Shapiro 		else
486605302a5SGregory Neil Shapiro 			return (*top)->lr_data[p];
487605302a5SGregory Neil Shapiro 
488605302a5SGregory Neil Shapiro 		if (m == -1)
489605302a5SGregory Neil Shapiro 			insertat = 0;
490605302a5SGregory Neil Shapiro 		else if (n >= (*top)->lr_cnt)
491605302a5SGregory Neil Shapiro 			insertat = (*top)->lr_cnt;
492605302a5SGregory Neil Shapiro 		else if (m < n)
493605302a5SGregory Neil Shapiro 			insertat = m + 1;
494605302a5SGregory Neil Shapiro 	}
495605302a5SGregory Neil Shapiro 
496605302a5SGregory Neil Shapiro 	/*
497605302a5SGregory Neil Shapiro 	** Not found in list, make room
498605302a5SGregory Neil Shapiro 	** at insert point and add it.
499605302a5SGregory Neil Shapiro 	*/
500605302a5SGregory Neil Shapiro 
501605302a5SGregory Neil Shapiro 	newe = sm_rpool_malloc_x(rpool, sizeof *newe);
502605302a5SGregory Neil Shapiro 	if (newe != NULL)
503605302a5SGregory Neil Shapiro 	{
504605302a5SGregory Neil Shapiro 		moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data);
505605302a5SGregory Neil Shapiro 		if (moveb > 0)
506605302a5SGregory Neil Shapiro 			memmove(&((*top)->lr_data[insertat + 1]),
507605302a5SGregory Neil Shapiro 				&((*top)->lr_data[insertat]),
508605302a5SGregory Neil Shapiro 				moveb);
509605302a5SGregory Neil Shapiro 
510605302a5SGregory Neil Shapiro 		newe->lr_search = sm_rpool_strdup_x(rpool, item);
511605302a5SGregory Neil Shapiro 		newe->lr_type = type;
512605302a5SGregory Neil Shapiro 		newe->lr_done = false;
513605302a5SGregory Neil Shapiro 
514605302a5SGregory Neil Shapiro 		((*top)->lr_data)[insertat] = newe;
515605302a5SGregory Neil Shapiro 		(*top)->lr_cnt++;
516605302a5SGregory Neil Shapiro 	}
517605302a5SGregory Neil Shapiro 	return newe;
51840266059SGregory Neil Shapiro }
51940266059SGregory Neil Shapiro 
52040266059SGregory Neil Shapiro int
521605302a5SGregory Neil Shapiro sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
522605302a5SGregory Neil Shapiro 		resultln, resultsz, recurse)
52340266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
52440266059SGregory Neil Shapiro 	int msgid;
52540266059SGregory Neil Shapiro 	int flags;
526605302a5SGregory Neil Shapiro 	int delim;
52740266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
52840266059SGregory Neil Shapiro 	char **result;
529605302a5SGregory Neil Shapiro 	int *resultln;
530605302a5SGregory Neil Shapiro 	int *resultsz;
53140266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *recurse;
53240266059SGregory Neil Shapiro {
53340266059SGregory Neil Shapiro 	bool toplevel;
53440266059SGregory Neil Shapiro 	int i;
53540266059SGregory Neil Shapiro 	int statp;
53640266059SGregory Neil Shapiro 	int vsize;
53740266059SGregory Neil Shapiro 	int ret;
53840266059SGregory Neil Shapiro 	int save_errno;
53940266059SGregory Neil Shapiro 	char *p;
540605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *rl;
54140266059SGregory Neil Shapiro 
54240266059SGregory Neil Shapiro 	/* Are we the top top level of the search? */
54340266059SGregory Neil Shapiro 	toplevel = (recurse == NULL);
54440266059SGregory Neil Shapiro 
54540266059SGregory Neil Shapiro 	/* Get results */
54640266059SGregory Neil Shapiro 	statp = EX_NOTFOUND;
54740266059SGregory Neil Shapiro 	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
54840266059SGregory Neil Shapiro 				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
54940266059SGregory Neil Shapiro 				   &(lmap->ldap_timeout)),
55040266059SGregory Neil Shapiro 				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
55140266059SGregory Neil Shapiro 	{
55240266059SGregory Neil Shapiro 		LDAPMessage *entry;
55340266059SGregory Neil Shapiro 
55440266059SGregory Neil Shapiro 		/* If we don't want multiple values and we have one, break */
555605302a5SGregory Neil Shapiro 		if ((char) delim == '\0' && *result != NULL)
55640266059SGregory Neil Shapiro 			break;
55740266059SGregory Neil Shapiro 
55840266059SGregory Neil Shapiro 		/* Cycle through all entries */
55940266059SGregory Neil Shapiro 		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
56040266059SGregory Neil Shapiro 		     entry != NULL;
56140266059SGregory Neil Shapiro 		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
56240266059SGregory Neil Shapiro 		{
56340266059SGregory Neil Shapiro 			BerElement *ber;
56440266059SGregory Neil Shapiro 			char *attr;
56540266059SGregory Neil Shapiro 			char **vals = NULL;
56640266059SGregory Neil Shapiro 			char *dn;
56740266059SGregory Neil Shapiro 
56840266059SGregory Neil Shapiro 			/*
56940266059SGregory Neil Shapiro 			**  If matching only and found an entry,
57040266059SGregory Neil Shapiro 			**  no need to spin through attributes
57140266059SGregory Neil Shapiro 			*/
57240266059SGregory Neil Shapiro 
573323f6dcbSGregory Neil Shapiro 			if (bitset(SM_LDAP_MATCHONLY, flags))
574323f6dcbSGregory Neil Shapiro 			{
575323f6dcbSGregory Neil Shapiro 				statp = EX_OK;
57640266059SGregory Neil Shapiro 				continue;
577323f6dcbSGregory Neil Shapiro 			}
57840266059SGregory Neil Shapiro 
57940266059SGregory Neil Shapiro 			/* record completed DN's to prevent loops */
58040266059SGregory Neil Shapiro 			dn = ldap_get_dn(lmap->ldap_ld, entry);
58140266059SGregory Neil Shapiro 			if (dn == NULL)
58240266059SGregory Neil Shapiro 			{
58340266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
58440266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
585605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
58640266059SGregory Neil Shapiro 				errno = save_errno;
587a7ec597cSGregory Neil Shapiro 				return EX_TEMPFAIL;
58840266059SGregory Neil Shapiro 			}
58940266059SGregory Neil Shapiro 
590605302a5SGregory Neil Shapiro 			rl = sm_ldap_add_recurse(&recurse, dn,
591605302a5SGregory Neil Shapiro 						 SM_LDAP_ATTR_DN,
592605302a5SGregory Neil Shapiro 						 rpool);
593605302a5SGregory Neil Shapiro 
594605302a5SGregory Neil Shapiro 			if (rl == NULL)
59540266059SGregory Neil Shapiro 			{
59640266059SGregory Neil Shapiro 				ldap_memfree(dn);
597605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
59840266059SGregory Neil Shapiro 				errno = ENOMEM;
59940266059SGregory Neil Shapiro 				return EX_OSERR;
600605302a5SGregory Neil Shapiro 			}
601605302a5SGregory Neil Shapiro 			else if (rl->lr_done)
602605302a5SGregory Neil Shapiro 			{
60340266059SGregory Neil Shapiro 				/* already on list, skip it */
60440266059SGregory Neil Shapiro 				ldap_memfree(dn);
60540266059SGregory Neil Shapiro 				continue;
60640266059SGregory Neil Shapiro 			}
60740266059SGregory Neil Shapiro 			ldap_memfree(dn);
60840266059SGregory Neil Shapiro 
60940266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
61040266059SGregory Neil Shapiro 			/*
61140266059SGregory Neil Shapiro 			**  Reset value to prevent lingering
61240266059SGregory Neil Shapiro 			**  LDAP_DECODING_ERROR due to
61340266059SGregory Neil Shapiro 			**  OpenLDAP 1.X's hack (see below)
61440266059SGregory Neil Shapiro 			*/
61540266059SGregory Neil Shapiro 
61640266059SGregory Neil Shapiro 			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
61740266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
61840266059SGregory Neil Shapiro 
61940266059SGregory Neil Shapiro 			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
62040266059SGregory Neil Shapiro 							 &ber);
62140266059SGregory Neil Shapiro 			     attr != NULL;
62240266059SGregory Neil Shapiro 			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
62340266059SGregory Neil Shapiro 							ber))
62440266059SGregory Neil Shapiro 			{
62540266059SGregory Neil Shapiro 				char *tmp, *vp_tmp;
62640266059SGregory Neil Shapiro 				int type;
627605302a5SGregory Neil Shapiro 				char *needobjclass = NULL;
62840266059SGregory Neil Shapiro 
629605302a5SGregory Neil Shapiro 				type = SM_LDAP_ATTR_NONE;
63040266059SGregory Neil Shapiro 				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
63140266059SGregory Neil Shapiro 				{
63240266059SGregory Neil Shapiro 					if (sm_strcasecmp(lmap->ldap_attr[i],
63340266059SGregory Neil Shapiro 							  attr) == 0)
63440266059SGregory Neil Shapiro 					{
63540266059SGregory Neil Shapiro 						type = lmap->ldap_attr_type[i];
636605302a5SGregory Neil Shapiro 						needobjclass = lmap->ldap_attr_needobjclass[i];
63740266059SGregory Neil Shapiro 						break;
63840266059SGregory Neil Shapiro 					}
63940266059SGregory Neil Shapiro 				}
640605302a5SGregory Neil Shapiro 
641605302a5SGregory Neil Shapiro 				if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
642605302a5SGregory Neil Shapiro 				    type == SM_LDAP_ATTR_NONE)
643605302a5SGregory Neil Shapiro 				{
644605302a5SGregory Neil Shapiro 					/* URL lookups specify attrs to use */
645605302a5SGregory Neil Shapiro 					type = SM_LDAP_ATTR_NORMAL;
646605302a5SGregory Neil Shapiro 					needobjclass = NULL;
647605302a5SGregory Neil Shapiro 				}
648605302a5SGregory Neil Shapiro 
649605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NONE)
65040266059SGregory Neil Shapiro 				{
65140266059SGregory Neil Shapiro 					/* attribute not requested */
65240266059SGregory Neil Shapiro 					ldap_memfree(attr);
653605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
65440266059SGregory Neil Shapiro 					errno = EFAULT;
65540266059SGregory Neil Shapiro 					return EX_SOFTWARE;
65640266059SGregory Neil Shapiro 				}
65740266059SGregory Neil Shapiro 
658605302a5SGregory Neil Shapiro 				/*
659605302a5SGregory Neil Shapiro 				**  For recursion on a particular attribute,
660605302a5SGregory Neil Shapiro 				**  we may need to see if this entry is
661605302a5SGregory Neil Shapiro 				**  part of a particular objectclass.
662605302a5SGregory Neil Shapiro 				**  Also, ignore objectClass attribute.
663605302a5SGregory Neil Shapiro 				**  Otherwise we just ignore this attribute.
664605302a5SGregory Neil Shapiro 				*/
665605302a5SGregory Neil Shapiro 
666605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_OBJCLASS ||
667605302a5SGregory Neil Shapiro 				    (needobjclass != NULL &&
668605302a5SGregory Neil Shapiro 				     !sm_ldap_has_objectclass(lmap, entry,
669605302a5SGregory Neil Shapiro 							      needobjclass)))
670605302a5SGregory Neil Shapiro 				{
671605302a5SGregory Neil Shapiro 					ldap_memfree(attr);
672605302a5SGregory Neil Shapiro 					continue;
673605302a5SGregory Neil Shapiro 				}
674605302a5SGregory Neil Shapiro 
67540266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
67640266059SGregory Neil Shapiro 				{
67740266059SGregory Neil Shapiro 					vals = ldap_get_values(lmap->ldap_ld,
67840266059SGregory Neil Shapiro 							       entry,
67940266059SGregory Neil Shapiro 							       attr);
68040266059SGregory Neil Shapiro 					if (vals == NULL)
68140266059SGregory Neil Shapiro 					{
68240266059SGregory Neil Shapiro 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
68340266059SGregory Neil Shapiro 						if (save_errno == LDAP_SUCCESS)
68440266059SGregory Neil Shapiro 						{
68540266059SGregory Neil Shapiro 							ldap_memfree(attr);
68640266059SGregory Neil Shapiro 							continue;
68740266059SGregory Neil Shapiro 						}
68840266059SGregory Neil Shapiro 
68940266059SGregory Neil Shapiro 						/* Must be an error */
69040266059SGregory Neil Shapiro 						save_errno += E_LDAPBASE;
69140266059SGregory Neil Shapiro 						ldap_memfree(attr);
692605302a5SGregory Neil Shapiro 						SM_LDAP_ERROR_CLEANUP();
69340266059SGregory Neil Shapiro 						errno = save_errno;
69440266059SGregory Neil Shapiro 						return EX_TEMPFAIL;
69540266059SGregory Neil Shapiro 					}
69640266059SGregory Neil Shapiro 				}
69740266059SGregory Neil Shapiro 
69840266059SGregory Neil Shapiro 				statp = EX_OK;
69940266059SGregory Neil Shapiro 
70040266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
70140266059SGregory Neil Shapiro 				/*
70240266059SGregory Neil Shapiro 				**  Reset value to prevent lingering
70340266059SGregory Neil Shapiro 				**  LDAP_DECODING_ERROR due to
70440266059SGregory Neil Shapiro 				**  OpenLDAP 1.X's hack (see below)
70540266059SGregory Neil Shapiro 				*/
70640266059SGregory Neil Shapiro 
70740266059SGregory Neil Shapiro 				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
70840266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
70940266059SGregory Neil Shapiro 
71040266059SGregory Neil Shapiro 				/*
71140266059SGregory Neil Shapiro 				**  If matching only,
71240266059SGregory Neil Shapiro 				**  no need to spin through entries
71340266059SGregory Neil Shapiro 				*/
71440266059SGregory Neil Shapiro 
71540266059SGregory Neil Shapiro 				if (bitset(SM_LDAP_MATCHONLY, flags))
71640266059SGregory Neil Shapiro 				{
71740266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
71840266059SGregory Neil Shapiro 						ldap_value_free(vals);
71940266059SGregory Neil Shapiro 					ldap_memfree(attr);
72040266059SGregory Neil Shapiro 					continue;
72140266059SGregory Neil Shapiro 				}
72240266059SGregory Neil Shapiro 
72340266059SGregory Neil Shapiro 				/*
72440266059SGregory Neil Shapiro 				**  If we don't want multiple values,
72540266059SGregory Neil Shapiro 				**  return first found.
72640266059SGregory Neil Shapiro 				*/
72740266059SGregory Neil Shapiro 
728605302a5SGregory Neil Shapiro 				if ((char) delim == '\0')
72940266059SGregory Neil Shapiro 				{
730605302a5SGregory Neil Shapiro 					if (*result != NULL)
731605302a5SGregory Neil Shapiro 					{
732605302a5SGregory Neil Shapiro 						/* already have a value */
733605302a5SGregory Neil Shapiro 						break;
734605302a5SGregory Neil Shapiro 					}
735605302a5SGregory Neil Shapiro 
736605302a5SGregory Neil Shapiro 					if (bitset(SM_LDAP_SINGLEMATCH,
737605302a5SGregory Neil Shapiro 						   flags) &&
738605302a5SGregory Neil Shapiro 					    *result != NULL)
739605302a5SGregory Neil Shapiro 					{
740605302a5SGregory Neil Shapiro 						/* only wanted one match */
741605302a5SGregory Neil Shapiro 						SM_LDAP_ERROR_CLEANUP();
742605302a5SGregory Neil Shapiro 						errno = ENOENT;
743605302a5SGregory Neil Shapiro 						return EX_NOTFOUND;
744605302a5SGregory Neil Shapiro 					}
745605302a5SGregory Neil Shapiro 
74640266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
74740266059SGregory Neil Shapiro 					{
74840266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
74940266059SGregory Neil Shapiro 									    attr);
75040266059SGregory Neil Shapiro 						ldap_memfree(attr);
75140266059SGregory Neil Shapiro 						break;
75240266059SGregory Neil Shapiro 					}
75340266059SGregory Neil Shapiro 
75440266059SGregory Neil Shapiro 					if (vals[0] == NULL)
75540266059SGregory Neil Shapiro 					{
75640266059SGregory Neil Shapiro 						ldap_value_free(vals);
75740266059SGregory Neil Shapiro 						ldap_memfree(attr);
75840266059SGregory Neil Shapiro 						continue;
75940266059SGregory Neil Shapiro 					}
76040266059SGregory Neil Shapiro 
76140266059SGregory Neil Shapiro 					vsize = strlen(vals[0]) + 1;
76240266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
76340266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
76440266059SGregory Neil Shapiro 					*result = sm_rpool_malloc_x(rpool,
76540266059SGregory Neil Shapiro 								    vsize);
76640266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
76740266059SGregory Neil Shapiro 						sm_snprintf(*result, vsize,
76840266059SGregory Neil Shapiro 							    "%s%c%s",
76940266059SGregory Neil Shapiro 							    attr,
77040266059SGregory Neil Shapiro 							    lmap->ldap_attrsep,
77140266059SGregory Neil Shapiro 							    vals[0]);
77240266059SGregory Neil Shapiro 					else
77340266059SGregory Neil Shapiro 						sm_strlcpy(*result, vals[0],
77440266059SGregory Neil Shapiro 							   vsize);
77540266059SGregory Neil Shapiro 					ldap_value_free(vals);
77640266059SGregory Neil Shapiro 					ldap_memfree(attr);
77740266059SGregory Neil Shapiro 					break;
77840266059SGregory Neil Shapiro 				}
77940266059SGregory Neil Shapiro 
78040266059SGregory Neil Shapiro 				/* attributes only */
78140266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
78240266059SGregory Neil Shapiro 				{
78340266059SGregory Neil Shapiro 					if (*result == NULL)
78440266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
78540266059SGregory Neil Shapiro 									    attr);
78640266059SGregory Neil Shapiro 					else
78740266059SGregory Neil Shapiro 					{
788605302a5SGregory Neil Shapiro 						if (bitset(SM_LDAP_SINGLEMATCH,
789605302a5SGregory Neil Shapiro 							   flags) &&
790605302a5SGregory Neil Shapiro 						    *result != NULL)
791605302a5SGregory Neil Shapiro 						{
792605302a5SGregory Neil Shapiro 							/* only wanted one match */
793605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
794605302a5SGregory Neil Shapiro 							errno = ENOENT;
795605302a5SGregory Neil Shapiro 							return EX_NOTFOUND;
796605302a5SGregory Neil Shapiro 						}
797605302a5SGregory Neil Shapiro 
79840266059SGregory Neil Shapiro 						vsize = strlen(*result) +
79940266059SGregory Neil Shapiro 							strlen(attr) + 2;
80040266059SGregory Neil Shapiro 						tmp = sm_rpool_malloc_x(rpool,
80140266059SGregory Neil Shapiro 									vsize);
80240266059SGregory Neil Shapiro 						(void) sm_snprintf(tmp,
80340266059SGregory Neil Shapiro 							vsize, "%s%c%s",
804605302a5SGregory Neil Shapiro 							*result, (char) delim,
80540266059SGregory Neil Shapiro 							attr);
80640266059SGregory Neil Shapiro 						*result = tmp;
80740266059SGregory Neil Shapiro 					}
80840266059SGregory Neil Shapiro 					ldap_memfree(attr);
80940266059SGregory Neil Shapiro 					continue;
81040266059SGregory Neil Shapiro 				}
81140266059SGregory Neil Shapiro 
81240266059SGregory Neil Shapiro 				/*
813605302a5SGregory Neil Shapiro 				**  If there is more than one, munge then
814605302a5SGregory Neil Shapiro 				**  into a map_coldelim separated string.
815605302a5SGregory Neil Shapiro 				**  If we are recursing we may have an entry
816605302a5SGregory Neil Shapiro 				**  with no 'normal' values to put in the
817605302a5SGregory Neil Shapiro 				**  string.
818605302a5SGregory Neil Shapiro 				**  This is not an error.
81940266059SGregory Neil Shapiro 				*/
82040266059SGregory Neil Shapiro 
821605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL &&
822605302a5SGregory Neil Shapiro 				    bitset(SM_LDAP_SINGLEMATCH, flags) &&
823605302a5SGregory Neil Shapiro 				    *result != NULL)
824605302a5SGregory Neil Shapiro 				{
825605302a5SGregory Neil Shapiro 					/* only wanted one match */
826605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
827605302a5SGregory Neil Shapiro 					errno = ENOENT;
828605302a5SGregory Neil Shapiro 					return EX_NOTFOUND;
829605302a5SGregory Neil Shapiro 				}
830605302a5SGregory Neil Shapiro 
83140266059SGregory Neil Shapiro 				vsize = 0;
83240266059SGregory Neil Shapiro 				for (i = 0; vals[i] != NULL; i++)
83340266059SGregory Neil Shapiro 				{
834605302a5SGregory Neil Shapiro 					if (type == SM_LDAP_ATTR_DN ||
835605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_FILTER ||
836605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_URL)
83740266059SGregory Neil Shapiro 					{
838605302a5SGregory Neil Shapiro 						/* add to recursion */
839605302a5SGregory Neil Shapiro 						if (sm_ldap_add_recurse(&recurse,
84040266059SGregory Neil Shapiro 									vals[i],
841605302a5SGregory Neil Shapiro 									type,
842605302a5SGregory Neil Shapiro 									rpool) == NULL)
84340266059SGregory Neil Shapiro 						{
844605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
84540266059SGregory Neil Shapiro 							errno = ENOMEM;
84640266059SGregory Neil Shapiro 							return EX_OSERR;
84740266059SGregory Neil Shapiro 						}
84840266059SGregory Neil Shapiro 						continue;
84940266059SGregory Neil Shapiro 					}
850605302a5SGregory Neil Shapiro 
85140266059SGregory Neil Shapiro 					vsize += strlen(vals[i]) + 1;
85240266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
85340266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
85440266059SGregory Neil Shapiro 				}
855605302a5SGregory Neil Shapiro 
856605302a5SGregory Neil Shapiro 				/*
857605302a5SGregory Neil Shapiro 				**  Create/Append to string any normal
858605302a5SGregory Neil Shapiro 				**  attribute values.  Otherwise, just free
859605302a5SGregory Neil Shapiro 				**  memory and move on to the next
860605302a5SGregory Neil Shapiro 				**  attribute in this entry.
861605302a5SGregory Neil Shapiro 				*/
862605302a5SGregory Neil Shapiro 
863605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
864605302a5SGregory Neil Shapiro 				{
865605302a5SGregory Neil Shapiro 					char *pe;
866605302a5SGregory Neil Shapiro 
867605302a5SGregory Neil Shapiro 					/* Grow result string if needed */
868605302a5SGregory Neil Shapiro 					if ((*resultln + vsize) >= *resultsz)
869605302a5SGregory Neil Shapiro 					{
870605302a5SGregory Neil Shapiro 						while ((*resultln + vsize) >= *resultsz)
871605302a5SGregory Neil Shapiro 						{
872605302a5SGregory Neil Shapiro 							if (*resultsz == 0)
873605302a5SGregory Neil Shapiro 								*resultsz = 1024;
874605302a5SGregory Neil Shapiro 							else
875605302a5SGregory Neil Shapiro 								*resultsz *= 2;
876605302a5SGregory Neil Shapiro 						}
877605302a5SGregory Neil Shapiro 
878605302a5SGregory Neil Shapiro 						vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
87940266059SGregory Neil Shapiro 						*vp_tmp = '\0';
88040266059SGregory Neil Shapiro 
881605302a5SGregory Neil Shapiro 						if (*result != NULL)
882605302a5SGregory Neil Shapiro 							sm_strlcpy(vp_tmp,
883605302a5SGregory Neil Shapiro 								   *result,
884605302a5SGregory Neil Shapiro 								   *resultsz);
885605302a5SGregory Neil Shapiro 						*result = vp_tmp;
886605302a5SGregory Neil Shapiro 					}
887605302a5SGregory Neil Shapiro 
888605302a5SGregory Neil Shapiro 					p = *result + *resultln;
889605302a5SGregory Neil Shapiro 					pe = *result + *resultsz;
890605302a5SGregory Neil Shapiro 
89140266059SGregory Neil Shapiro 					for (i = 0; vals[i] != NULL; i++)
89240266059SGregory Neil Shapiro 					{
893959366dcSGregory Neil Shapiro 						if (*resultln > 0 &&
894959366dcSGregory Neil Shapiro 						    p < pe)
895605302a5SGregory Neil Shapiro 							*p++ = (char) delim;
896605302a5SGregory Neil Shapiro 
89740266059SGregory Neil Shapiro 						if (lmap->ldap_attrsep != '\0')
89840266059SGregory Neil Shapiro 						{
89940266059SGregory Neil Shapiro 							p += sm_strlcpy(p, attr,
900605302a5SGregory Neil Shapiro 									pe - p);
901605302a5SGregory Neil Shapiro 							if (p < pe)
90240266059SGregory Neil Shapiro 								*p++ = lmap->ldap_attrsep;
90340266059SGregory Neil Shapiro 						}
904605302a5SGregory Neil Shapiro 
90540266059SGregory Neil Shapiro 						p += sm_strlcpy(p, vals[i],
906605302a5SGregory Neil Shapiro 								pe - p);
907605302a5SGregory Neil Shapiro 						*resultln = p - (*result);
908605302a5SGregory Neil Shapiro 						if (p >= pe)
90940266059SGregory Neil Shapiro 						{
91040266059SGregory Neil Shapiro 							/* Internal error: buffer too small for LDAP values */
911605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
91240266059SGregory Neil Shapiro 							errno = ENOMEM;
91340266059SGregory Neil Shapiro 							return EX_OSERR;
91440266059SGregory Neil Shapiro 						}
915605302a5SGregory Neil Shapiro 					}
91640266059SGregory Neil Shapiro 				}
91740266059SGregory Neil Shapiro 
91840266059SGregory Neil Shapiro 				ldap_value_free(vals);
91940266059SGregory Neil Shapiro 				ldap_memfree(attr);
92040266059SGregory Neil Shapiro 			}
92140266059SGregory Neil Shapiro 			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
92240266059SGregory Neil Shapiro 
92340266059SGregory Neil Shapiro 			/*
92440266059SGregory Neil Shapiro 			**  We check save_errno != LDAP_DECODING_ERROR since
92540266059SGregory Neil Shapiro 			**  OpenLDAP 1.X has a very ugly *undocumented*
92640266059SGregory Neil Shapiro 			**  hack of returning this error code from
92740266059SGregory Neil Shapiro 			**  ldap_next_attribute() if the library freed the
92840266059SGregory Neil Shapiro 			**  ber attribute.  See:
92940266059SGregory Neil Shapiro 			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
93040266059SGregory Neil Shapiro 			*/
93140266059SGregory Neil Shapiro 
93240266059SGregory Neil Shapiro 			if (save_errno != LDAP_SUCCESS &&
93340266059SGregory Neil Shapiro 			    save_errno != LDAP_DECODING_ERROR)
93440266059SGregory Neil Shapiro 			{
93540266059SGregory Neil Shapiro 				/* Must be an error */
93640266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
937605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
93840266059SGregory Neil Shapiro 				errno = save_errno;
93940266059SGregory Neil Shapiro 				return EX_TEMPFAIL;
94040266059SGregory Neil Shapiro 			}
94140266059SGregory Neil Shapiro 
942605302a5SGregory Neil Shapiro 			/* mark this DN as done */
943605302a5SGregory Neil Shapiro 			rl->lr_done = true;
944605302a5SGregory Neil Shapiro 
94540266059SGregory Neil Shapiro 			/* We don't want multiple values and we have one */
946605302a5SGregory Neil Shapiro 			if ((char) delim == '\0' && *result != NULL)
94740266059SGregory Neil Shapiro 				break;
94840266059SGregory Neil Shapiro 		}
94940266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
95040266059SGregory Neil Shapiro 		if (save_errno != LDAP_SUCCESS &&
95140266059SGregory Neil Shapiro 		    save_errno != LDAP_DECODING_ERROR)
95240266059SGregory Neil Shapiro 		{
95340266059SGregory Neil Shapiro 			/* Must be an error */
95440266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
955605302a5SGregory Neil Shapiro 			SM_LDAP_ERROR_CLEANUP();
95640266059SGregory Neil Shapiro 			errno = save_errno;
95740266059SGregory Neil Shapiro 			return EX_TEMPFAIL;
95840266059SGregory Neil Shapiro 		}
95940266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
96040266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
96140266059SGregory Neil Shapiro 	}
96240266059SGregory Neil Shapiro 
96340266059SGregory Neil Shapiro 	if (ret == 0)
96440266059SGregory Neil Shapiro 		save_errno = ETIMEDOUT;
96540266059SGregory Neil Shapiro 	else
96640266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
96740266059SGregory Neil Shapiro 	if (save_errno != LDAP_SUCCESS)
96840266059SGregory Neil Shapiro 	{
96940266059SGregory Neil Shapiro 		statp = EX_TEMPFAIL;
97040266059SGregory Neil Shapiro 		if (ret != 0)
97140266059SGregory Neil Shapiro 		{
97240266059SGregory Neil Shapiro 			switch (save_errno)
97340266059SGregory Neil Shapiro 			{
97440266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
97540266059SGregory Neil Shapiro 			  case LDAP_SERVER_DOWN:
97640266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
97740266059SGregory Neil Shapiro 			  case LDAP_TIMEOUT:
97840266059SGregory Neil Shapiro 			  case LDAP_UNAVAILABLE:
979605302a5SGregory Neil Shapiro 
980605302a5SGregory Neil Shapiro 				/*
981605302a5SGregory Neil Shapiro 				**  server disappeared,
982605302a5SGregory Neil Shapiro 				**  try reopen on next search
983605302a5SGregory Neil Shapiro 				*/
984605302a5SGregory Neil Shapiro 
98540266059SGregory Neil Shapiro 				statp = EX_RESTART;
98640266059SGregory Neil Shapiro 				break;
98740266059SGregory Neil Shapiro 			}
98840266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
98940266059SGregory Neil Shapiro 		}
990605302a5SGregory Neil Shapiro 		SM_LDAP_ERROR_CLEANUP();
99140266059SGregory Neil Shapiro 		errno = save_errno;
99240266059SGregory Neil Shapiro 		return statp;
99340266059SGregory Neil Shapiro 	}
99440266059SGregory Neil Shapiro 
99540266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)
99640266059SGregory Neil Shapiro 	{
99740266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
99840266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
99940266059SGregory Neil Shapiro 	}
100040266059SGregory Neil Shapiro 
100140266059SGregory Neil Shapiro 	if (toplevel)
100240266059SGregory Neil Shapiro 	{
1003605302a5SGregory Neil Shapiro 		int rlidx;
100440266059SGregory Neil Shapiro 
100540266059SGregory Neil Shapiro 		/*
100640266059SGregory Neil Shapiro 		**  Spin through the built-up recurse list at the top
100740266059SGregory Neil Shapiro 		**  of the recursion.  Since new items are added at the
100840266059SGregory Neil Shapiro 		**  end of the shared list, we actually only ever get
100940266059SGregory Neil Shapiro 		**  one level of recursion before things pop back to the
101040266059SGregory Neil Shapiro 		**  top.  Any items added to the list during that recursion
101140266059SGregory Neil Shapiro 		**  will be expanded by the top level.
101240266059SGregory Neil Shapiro 		*/
101340266059SGregory Neil Shapiro 
1014605302a5SGregory Neil Shapiro 		for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)
101540266059SGregory Neil Shapiro 		{
1016605302a5SGregory Neil Shapiro 			int newflags;
101740266059SGregory Neil Shapiro 			int sid;
101840266059SGregory Neil Shapiro 			int status;
101940266059SGregory Neil Shapiro 
1020605302a5SGregory Neil Shapiro 			rl = recurse->lr_data[rlidx];
1021605302a5SGregory Neil Shapiro 
1022605302a5SGregory Neil Shapiro 			newflags = flags;
1023605302a5SGregory Neil Shapiro 			if (rl->lr_done)
102440266059SGregory Neil Shapiro 			{
102540266059SGregory Neil Shapiro 				/* already expanded */
102640266059SGregory Neil Shapiro 				continue;
102740266059SGregory Neil Shapiro 			}
1028605302a5SGregory Neil Shapiro 
1029605302a5SGregory Neil Shapiro 			if (rl->lr_type == SM_LDAP_ATTR_DN)
103040266059SGregory Neil Shapiro 			{
103140266059SGregory Neil Shapiro 				/* do DN search */
103240266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
103340266059SGregory Neil Shapiro 						  rl->lr_search,
103440266059SGregory Neil Shapiro 						  lmap->ldap_scope,
103540266059SGregory Neil Shapiro 						  "(objectClass=*)",
1036605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1037605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
103840266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
103940266059SGregory Neil Shapiro 			}
1040605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
104140266059SGregory Neil Shapiro 			{
104240266059SGregory Neil Shapiro 				/* do new search */
104340266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
104440266059SGregory Neil Shapiro 						  lmap->ldap_base,
104540266059SGregory Neil Shapiro 						  lmap->ldap_scope,
104640266059SGregory Neil Shapiro 						  rl->lr_search,
1047605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1048605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
104940266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
105040266059SGregory Neil Shapiro 			}
1051605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_URL)
105240266059SGregory Neil Shapiro 			{
105340266059SGregory Neil Shapiro 				/* do new URL search */
105440266059SGregory Neil Shapiro 				sid = ldap_url_search(lmap->ldap_ld,
105540266059SGregory Neil Shapiro 						      rl->lr_search,
105640266059SGregory Neil Shapiro 						      lmap->ldap_attrsonly);
1057605302a5SGregory Neil Shapiro 				newflags |= SM_LDAP_USE_ALLATTR;
105840266059SGregory Neil Shapiro 			}
105940266059SGregory Neil Shapiro 			else
106040266059SGregory Neil Shapiro 			{
106140266059SGregory Neil Shapiro 				/* unknown or illegal attribute type */
106240266059SGregory Neil Shapiro 				errno = EFAULT;
106340266059SGregory Neil Shapiro 				return EX_SOFTWARE;
106440266059SGregory Neil Shapiro 			}
106540266059SGregory Neil Shapiro 
106640266059SGregory Neil Shapiro 			/* Collect results */
106740266059SGregory Neil Shapiro 			if (sid == -1)
106840266059SGregory Neil Shapiro 			{
106940266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
107040266059SGregory Neil Shapiro 				statp = EX_TEMPFAIL;
107140266059SGregory Neil Shapiro 				switch (save_errno)
107240266059SGregory Neil Shapiro 				{
107340266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
107440266059SGregory Neil Shapiro 				  case LDAP_SERVER_DOWN:
107540266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
107640266059SGregory Neil Shapiro 				  case LDAP_TIMEOUT:
107740266059SGregory Neil Shapiro 				  case LDAP_UNAVAILABLE:
1078605302a5SGregory Neil Shapiro 
1079605302a5SGregory Neil Shapiro 					/*
1080605302a5SGregory Neil Shapiro 					**  server disappeared,
1081605302a5SGregory Neil Shapiro 					**  try reopen on next search
1082605302a5SGregory Neil Shapiro 					*/
1083605302a5SGregory Neil Shapiro 
108440266059SGregory Neil Shapiro 					statp = EX_RESTART;
108540266059SGregory Neil Shapiro 					break;
108640266059SGregory Neil Shapiro 				}
108740266059SGregory Neil Shapiro 				errno = save_errno + E_LDAPBASE;
108840266059SGregory Neil Shapiro 				return statp;
108940266059SGregory Neil Shapiro 			}
109040266059SGregory Neil Shapiro 
1091605302a5SGregory Neil Shapiro 			status = sm_ldap_results(lmap, sid, newflags, delim,
1092605302a5SGregory Neil Shapiro 						 rpool, result, resultln,
1093605302a5SGregory Neil Shapiro 						 resultsz, recurse);
109440266059SGregory Neil Shapiro 			save_errno = errno;
109540266059SGregory Neil Shapiro 			if (status != EX_OK && status != EX_NOTFOUND)
109640266059SGregory Neil Shapiro 			{
109740266059SGregory Neil Shapiro 				errno = save_errno;
109840266059SGregory Neil Shapiro 				return status;
109940266059SGregory Neil Shapiro 			}
110040266059SGregory Neil Shapiro 
110140266059SGregory Neil Shapiro 			/* Mark as done */
1102605302a5SGregory Neil Shapiro 			rl->lr_done = true;
1103605302a5SGregory Neil Shapiro 
1104605302a5SGregory Neil Shapiro 			/* Reset rlidx as new items may have been added */
1105605302a5SGregory Neil Shapiro 			rlidx = -1;
110640266059SGregory Neil Shapiro 		}
110740266059SGregory Neil Shapiro 	}
110840266059SGregory Neil Shapiro 	return statp;
110940266059SGregory Neil Shapiro }
111040266059SGregory Neil Shapiro #endif /* _FFR_LDAP_RECURSION */
111140266059SGregory Neil Shapiro 
111240266059SGregory Neil Shapiro /*
111340266059SGregory Neil Shapiro **  SM_LDAP_CLOSE -- close LDAP connection
111440266059SGregory Neil Shapiro **
111540266059SGregory Neil Shapiro **	Parameters:
111640266059SGregory Neil Shapiro **		lmap -- LDAP map information
111740266059SGregory Neil Shapiro **
111840266059SGregory Neil Shapiro **	Returns:
111940266059SGregory Neil Shapiro **		None.
112040266059SGregory Neil Shapiro **
112140266059SGregory Neil Shapiro */
112240266059SGregory Neil Shapiro 
112340266059SGregory Neil Shapiro void
112440266059SGregory Neil Shapiro sm_ldap_close(lmap)
112540266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
112640266059SGregory Neil Shapiro {
112740266059SGregory Neil Shapiro 	if (lmap->ldap_ld == NULL)
112840266059SGregory Neil Shapiro 		return;
112940266059SGregory Neil Shapiro 
113040266059SGregory Neil Shapiro 	if (lmap->ldap_pid == getpid())
113140266059SGregory Neil Shapiro 		ldap_unbind(lmap->ldap_ld);
113240266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
113340266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
113440266059SGregory Neil Shapiro }
113540266059SGregory Neil Shapiro 
113640266059SGregory Neil Shapiro /*
113740266059SGregory Neil Shapiro **  SM_LDAP_SETOPTS -- set LDAP options
113840266059SGregory Neil Shapiro **
113940266059SGregory Neil Shapiro **	Parameters:
114040266059SGregory Neil Shapiro **		ld -- LDAP session handle
114140266059SGregory Neil Shapiro **		lmap -- LDAP map information
114240266059SGregory Neil Shapiro **
114340266059SGregory Neil Shapiro **	Returns:
114440266059SGregory Neil Shapiro **		None.
114540266059SGregory Neil Shapiro **
114640266059SGregory Neil Shapiro */
114740266059SGregory Neil Shapiro 
114840266059SGregory Neil Shapiro void
114940266059SGregory Neil Shapiro sm_ldap_setopts(ld, lmap)
115040266059SGregory Neil Shapiro 	LDAP *ld;
115140266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
115240266059SGregory Neil Shapiro {
115340266059SGregory Neil Shapiro # if USE_LDAP_SET_OPTION
1154605302a5SGregory Neil Shapiro #  if _FFR_LDAP_SETVERSION
1155605302a5SGregory Neil Shapiro 	if (lmap->ldap_version != 0)
1156605302a5SGregory Neil Shapiro 	{
1157605302a5SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
1158605302a5SGregory Neil Shapiro 				&lmap->ldap_version);
1159605302a5SGregory Neil Shapiro 	}
1160605302a5SGregory Neil Shapiro #  endif /* _FFR_LDAP_SETVERSION */
116140266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
116240266059SGregory Neil Shapiro 	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
116340266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
116440266059SGregory Neil Shapiro 	else
116540266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
116640266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
116740266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
1168959366dcSGregory Neil Shapiro #  ifdef LDAP_OPT_RESTART
1169959366dcSGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1170959366dcSGregory Neil Shapiro #  endif /* LDAP_OPT_RESTART */
117140266059SGregory Neil Shapiro # else /* USE_LDAP_SET_OPTION */
117240266059SGregory Neil Shapiro 	/* From here on in we can use ldap internal timelimits */
117340266059SGregory Neil Shapiro 	ld->ld_deref = lmap->ldap_deref;
117440266059SGregory Neil Shapiro 	ld->ld_options = lmap->ldap_options;
117540266059SGregory Neil Shapiro 	ld->ld_sizelimit = lmap->ldap_sizelimit;
117640266059SGregory Neil Shapiro 	ld->ld_timelimit = lmap->ldap_timelimit;
117740266059SGregory Neil Shapiro # endif /* USE_LDAP_SET_OPTION */
117840266059SGregory Neil Shapiro }
117940266059SGregory Neil Shapiro 
118040266059SGregory Neil Shapiro /*
118140266059SGregory Neil Shapiro **  SM_LDAP_GETERRNO -- get ldap errno value
118240266059SGregory Neil Shapiro **
118340266059SGregory Neil Shapiro **	Parameters:
118440266059SGregory Neil Shapiro **		ld -- LDAP session handle
118540266059SGregory Neil Shapiro **
118640266059SGregory Neil Shapiro **	Returns:
118740266059SGregory Neil Shapiro **		LDAP errno.
118840266059SGregory Neil Shapiro **
118940266059SGregory Neil Shapiro */
119040266059SGregory Neil Shapiro 
119140266059SGregory Neil Shapiro int
119240266059SGregory Neil Shapiro sm_ldap_geterrno(ld)
119340266059SGregory Neil Shapiro 	LDAP *ld;
119440266059SGregory Neil Shapiro {
119540266059SGregory Neil Shapiro 	int err = LDAP_SUCCESS;
119640266059SGregory Neil Shapiro 
119740266059SGregory Neil Shapiro # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
119840266059SGregory Neil Shapiro 	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
119940266059SGregory Neil Shapiro # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
120040266059SGregory Neil Shapiro #  ifdef LDAP_OPT_SIZELIMIT
120140266059SGregory Neil Shapiro 	err = ldap_get_lderrno(ld, NULL, NULL);
120240266059SGregory Neil Shapiro #  else /* LDAP_OPT_SIZELIMIT */
120340266059SGregory Neil Shapiro 	err = ld->ld_errno;
120440266059SGregory Neil Shapiro 
120540266059SGregory Neil Shapiro 	/*
120640266059SGregory Neil Shapiro 	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
120740266059SGregory Neil Shapiro 	**  OpenLDAP 1.X's hack (see above)
120840266059SGregory Neil Shapiro 	*/
120940266059SGregory Neil Shapiro 
121040266059SGregory Neil Shapiro 	ld->ld_errno = LDAP_SUCCESS;
121140266059SGregory Neil Shapiro #  endif /* LDAP_OPT_SIZELIMIT */
121240266059SGregory Neil Shapiro # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
121340266059SGregory Neil Shapiro 	return err;
121440266059SGregory Neil Shapiro }
121540266059SGregory Neil Shapiro # endif /* LDAPMAP */
1216