xref: /freebsd/contrib/sendmail/libsm/ldap.c (revision 13d882686343bf9a76ffdfa83854043d808703dd)
140266059SGregory Neil Shapiro /*
213d88268SGregory Neil Shapiro  * Copyright (c) 2001-2005 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>
1113d88268SGregory Neil Shapiro SM_RCSID("@(#)$Id: ldap.c,v 1.62 2005/02/24 00:30:01 ca 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));
36b6bacd31SGregory Neil Shapiro static bool	sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *));
37b6bacd31SGregory Neil Shapiro static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *));
3840266059SGregory Neil Shapiro 
3940266059SGregory Neil Shapiro /*
4040266059SGregory Neil Shapiro **  SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
4140266059SGregory Neil Shapiro **
4240266059SGregory Neil Shapiro **	Parameters:
4340266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT to clear
4440266059SGregory Neil Shapiro **
4540266059SGregory Neil Shapiro **	Returns:
4640266059SGregory Neil Shapiro **		None.
4740266059SGregory Neil Shapiro **
4840266059SGregory Neil Shapiro */
4940266059SGregory Neil Shapiro 
5040266059SGregory Neil Shapiro void
5140266059SGregory Neil Shapiro sm_ldap_clear(lmap)
5240266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
5340266059SGregory Neil Shapiro {
5440266059SGregory Neil Shapiro 	if (lmap == NULL)
5540266059SGregory Neil Shapiro 		return;
5640266059SGregory Neil Shapiro 
57e92d3f3fSGregory Neil Shapiro 	lmap->ldap_host = NULL;
5840266059SGregory Neil Shapiro 	lmap->ldap_port = LDAP_PORT;
59e92d3f3fSGregory Neil Shapiro 	lmap->ldap_uri = NULL;
60605302a5SGregory Neil Shapiro 	lmap->ldap_version = 0;
6140266059SGregory Neil Shapiro 	lmap->ldap_deref = LDAP_DEREF_NEVER;
6240266059SGregory Neil Shapiro 	lmap->ldap_timelimit = LDAP_NO_LIMIT;
6340266059SGregory Neil Shapiro 	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
6440266059SGregory Neil Shapiro # ifdef LDAP_REFERRALS
6540266059SGregory Neil Shapiro 	lmap->ldap_options = LDAP_OPT_REFERRALS;
6640266059SGregory Neil Shapiro # else /* LDAP_REFERRALS */
6740266059SGregory Neil Shapiro 	lmap->ldap_options = 0;
6840266059SGregory Neil Shapiro # endif /* LDAP_REFERRALS */
6940266059SGregory Neil Shapiro 	lmap->ldap_attrsep = '\0';
7040266059SGregory Neil Shapiro 	lmap->ldap_binddn = NULL;
7140266059SGregory Neil Shapiro 	lmap->ldap_secret = NULL;
7240266059SGregory Neil Shapiro 	lmap->ldap_method = LDAP_AUTH_SIMPLE;
7340266059SGregory Neil Shapiro 	lmap->ldap_base = NULL;
7440266059SGregory Neil Shapiro 	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
7540266059SGregory Neil Shapiro 	lmap->ldap_attrsonly = LDAPMAP_FALSE;
7640266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_sec = 0;
7740266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_usec = 0;
7840266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
7940266059SGregory Neil Shapiro 	lmap->ldap_filter = NULL;
8040266059SGregory Neil Shapiro 	lmap->ldap_attr[0] = NULL;
81605302a5SGregory Neil Shapiro 	lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
82605302a5SGregory Neil Shapiro 	lmap->ldap_attr_needobjclass[0] = NULL;
8340266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
8440266059SGregory Neil Shapiro 	lmap->ldap_next = NULL;
8540266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
8640266059SGregory Neil Shapiro }
8740266059SGregory Neil Shapiro 
8840266059SGregory Neil Shapiro /*
8940266059SGregory Neil Shapiro **  SM_LDAP_START -- actually connect to an LDAP server
9040266059SGregory Neil Shapiro **
9140266059SGregory Neil Shapiro **	Parameters:
9240266059SGregory Neil Shapiro **		name -- name of map for debug output.
9340266059SGregory Neil Shapiro **		lmap -- the LDAP map being opened.
9440266059SGregory Neil Shapiro **
9540266059SGregory Neil Shapiro **	Returns:
9640266059SGregory Neil Shapiro **		true if connection is successful, false otherwise.
9740266059SGregory Neil Shapiro **
9840266059SGregory Neil Shapiro **	Side Effects:
9940266059SGregory Neil Shapiro **		Populates lmap->ldap_ld.
10040266059SGregory Neil Shapiro */
10140266059SGregory Neil Shapiro 
10240266059SGregory Neil Shapiro static jmp_buf	LDAPTimeout;
10340266059SGregory Neil Shapiro 
10440266059SGregory Neil Shapiro #define SM_LDAP_SETTIMEOUT(to)						\
10540266059SGregory Neil Shapiro do									\
10640266059SGregory Neil Shapiro {									\
10740266059SGregory Neil Shapiro 	if (to != 0)							\
10840266059SGregory Neil Shapiro 	{								\
10940266059SGregory Neil Shapiro 		if (setjmp(LDAPTimeout) != 0)				\
11040266059SGregory Neil Shapiro 		{							\
11140266059SGregory Neil Shapiro 			errno = ETIMEDOUT;				\
11240266059SGregory Neil Shapiro 			return false;					\
11340266059SGregory Neil Shapiro 		}							\
11440266059SGregory Neil Shapiro 		ev = sm_setevent(to, ldaptimeout, 0);			\
11540266059SGregory Neil Shapiro 	}								\
11640266059SGregory Neil Shapiro } while (0)
11740266059SGregory Neil Shapiro 
11840266059SGregory Neil Shapiro #define SM_LDAP_CLEARTIMEOUT()						\
11940266059SGregory Neil Shapiro do									\
12040266059SGregory Neil Shapiro {									\
12140266059SGregory Neil Shapiro 	if (ev != NULL)							\
12240266059SGregory Neil Shapiro 		sm_clrevent(ev);					\
12340266059SGregory Neil Shapiro } while (0)
12440266059SGregory Neil Shapiro 
12540266059SGregory Neil Shapiro bool
12640266059SGregory Neil Shapiro sm_ldap_start(name, lmap)
12740266059SGregory Neil Shapiro 	char *name;
12840266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
12940266059SGregory Neil Shapiro {
13040266059SGregory Neil Shapiro 	int bind_result;
131b6bacd31SGregory Neil Shapiro 	int save_errno = 0;
132e92d3f3fSGregory Neil Shapiro 	char *id;
13340266059SGregory Neil Shapiro 	SM_EVENT *ev = NULL;
134e92d3f3fSGregory Neil Shapiro 	LDAP *ld = NULL;
13540266059SGregory Neil Shapiro 
13640266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 2))
13740266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
13840266059SGregory Neil Shapiro 
139e92d3f3fSGregory Neil Shapiro 	if (lmap->ldap_host != NULL)
140e92d3f3fSGregory Neil Shapiro 		id = lmap->ldap_host;
141e92d3f3fSGregory Neil Shapiro 	else if (lmap->ldap_uri != NULL)
142e92d3f3fSGregory Neil Shapiro 		id = lmap->ldap_uri;
143605302a5SGregory Neil Shapiro 	else
144e92d3f3fSGregory Neil Shapiro 		id = "localhost";
145e92d3f3fSGregory Neil Shapiro 
146e92d3f3fSGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
147e92d3f3fSGregory Neil Shapiro 	{
148e92d3f3fSGregory Neil Shapiro 		/* Don't print a port number for LDAP URIs */
149e92d3f3fSGregory Neil Shapiro 		if (lmap->ldap_uri != NULL)
150e92d3f3fSGregory Neil Shapiro 			sm_dprintf("ldapmap_start(%s)\n", id);
151e92d3f3fSGregory Neil Shapiro 		else
152e92d3f3fSGregory Neil Shapiro 			sm_dprintf("ldapmap_start(%s, %d)\n", id,
153e92d3f3fSGregory Neil Shapiro 				   lmap->ldap_port);
154e92d3f3fSGregory Neil Shapiro 	}
155e92d3f3fSGregory Neil Shapiro 
156e92d3f3fSGregory Neil Shapiro 	if (lmap->ldap_uri != NULL)
157e92d3f3fSGregory Neil Shapiro 	{
158e92d3f3fSGregory Neil Shapiro #if SM_CONF_LDAP_INITIALIZE
159e92d3f3fSGregory Neil Shapiro 		/* LDAP server supports URIs so use them directly */
160e92d3f3fSGregory Neil Shapiro 		save_errno = ldap_initialize(&ld, lmap->ldap_uri);
161e92d3f3fSGregory Neil Shapiro #else /* SM_CONF_LDAP_INITIALIZE */
162e92d3f3fSGregory Neil Shapiro 		int err;
163e92d3f3fSGregory Neil Shapiro 		LDAPURLDesc *ludp = NULL;
164e92d3f3fSGregory Neil Shapiro 
165e92d3f3fSGregory Neil Shapiro 		/* Blast apart URL and use the ldap_init/ldap_open below */
166e92d3f3fSGregory Neil Shapiro 		err = ldap_url_parse(lmap->ldap_uri, &ludp);
167e92d3f3fSGregory Neil Shapiro 		if (err != 0)
168e92d3f3fSGregory Neil Shapiro 		{
169e92d3f3fSGregory Neil Shapiro 			errno = err + E_LDAPURLBASE;
170e92d3f3fSGregory Neil Shapiro 			return false;
171e92d3f3fSGregory Neil Shapiro 		}
172e92d3f3fSGregory Neil Shapiro 		lmap->ldap_host = sm_strdup_x(ludp->lud_host);
173e92d3f3fSGregory Neil Shapiro 		if (lmap->ldap_host == NULL)
174e92d3f3fSGregory Neil Shapiro 		{
175e92d3f3fSGregory Neil Shapiro 			save_errno = errno;
176e92d3f3fSGregory Neil Shapiro 			ldap_free_urldesc(ludp);
177e92d3f3fSGregory Neil Shapiro 			errno = save_errno;
178e92d3f3fSGregory Neil Shapiro 			return false;
179e92d3f3fSGregory Neil Shapiro 		}
180e92d3f3fSGregory Neil Shapiro 		lmap->ldap_port = ludp->lud_port;
181e92d3f3fSGregory Neil Shapiro 		ldap_free_urldesc(ludp);
182e92d3f3fSGregory Neil Shapiro #endif /* SM_CONF_LDAP_INITIALIZE */
183e92d3f3fSGregory Neil Shapiro 	}
184e92d3f3fSGregory Neil Shapiro 
185e92d3f3fSGregory Neil Shapiro 	if (ld == NULL)
186e92d3f3fSGregory Neil Shapiro 	{
187e92d3f3fSGregory Neil Shapiro # if USE_LDAP_INIT
188e92d3f3fSGregory Neil Shapiro 		ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
18940266059SGregory Neil Shapiro 		save_errno = errno;
19040266059SGregory Neil Shapiro # else /* USE_LDAP_INIT */
19140266059SGregory Neil Shapiro 		/*
19240266059SGregory Neil Shapiro 		**  If using ldap_open(), the actual connection to the server
19340266059SGregory Neil Shapiro 		**  happens now so we need the timeout here.  For ldap_init(),
19440266059SGregory Neil Shapiro 		**  the connection happens at bind time.
19540266059SGregory Neil Shapiro 		*/
19640266059SGregory Neil Shapiro 
19740266059SGregory Neil Shapiro 		SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
198e92d3f3fSGregory Neil Shapiro 		ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
19940266059SGregory Neil Shapiro 		save_errno = errno;
20040266059SGregory Neil Shapiro 
20140266059SGregory Neil Shapiro 		/* clear the event if it has not sprung */
20240266059SGregory Neil Shapiro 		SM_LDAP_CLEARTIMEOUT();
20340266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
204e92d3f3fSGregory Neil Shapiro 	}
20540266059SGregory Neil Shapiro 
20640266059SGregory Neil Shapiro 	errno = save_errno;
20740266059SGregory Neil Shapiro 	if (ld == NULL)
20840266059SGregory Neil Shapiro 		return false;
20940266059SGregory Neil Shapiro 
21040266059SGregory Neil Shapiro 	sm_ldap_setopts(ld, lmap);
21140266059SGregory Neil Shapiro 
21240266059SGregory Neil Shapiro # if USE_LDAP_INIT
21340266059SGregory Neil Shapiro 	/*
21440266059SGregory Neil Shapiro 	**  If using ldap_init(), the actual connection to the server
21540266059SGregory Neil Shapiro 	**  happens at ldap_bind_s() so we need the timeout here.
21640266059SGregory Neil Shapiro 	*/
21740266059SGregory Neil Shapiro 
21840266059SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
21940266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
22040266059SGregory Neil Shapiro 
22140266059SGregory Neil Shapiro # ifdef LDAP_AUTH_KRBV4
22240266059SGregory Neil Shapiro 	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
22340266059SGregory Neil Shapiro 	    lmap->ldap_secret != NULL)
22440266059SGregory Neil Shapiro 	{
22540266059SGregory Neil Shapiro 		/*
22640266059SGregory Neil Shapiro 		**  Need to put ticket in environment here instead of
22740266059SGregory Neil Shapiro 		**  during parseargs as there may be different tickets
22840266059SGregory Neil Shapiro 		**  for different LDAP connections.
22940266059SGregory Neil Shapiro 		*/
23040266059SGregory Neil Shapiro 
23140266059SGregory Neil Shapiro 		(void) putenv(lmap->ldap_secret);
23240266059SGregory Neil Shapiro 	}
23340266059SGregory Neil Shapiro # endif /* LDAP_AUTH_KRBV4 */
23440266059SGregory Neil Shapiro 
23540266059SGregory Neil Shapiro 	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
23640266059SGregory Neil Shapiro 				  lmap->ldap_secret, lmap->ldap_method);
23740266059SGregory Neil Shapiro 
23840266059SGregory Neil Shapiro # if USE_LDAP_INIT
23940266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
24040266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
24140266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
24240266059SGregory Neil Shapiro 
24340266059SGregory Neil Shapiro 	if (bind_result != LDAP_SUCCESS)
24440266059SGregory Neil Shapiro 	{
24540266059SGregory Neil Shapiro 		errno = bind_result + E_LDAPBASE;
24640266059SGregory Neil Shapiro 		return false;
24740266059SGregory Neil Shapiro 	}
24840266059SGregory Neil Shapiro 
24940266059SGregory Neil Shapiro 	/* Save PID to make sure only this PID closes the LDAP connection */
25040266059SGregory Neil Shapiro 	lmap->ldap_pid = getpid();
25140266059SGregory Neil Shapiro 	lmap->ldap_ld = ld;
25240266059SGregory Neil Shapiro 	return true;
25340266059SGregory Neil Shapiro }
25440266059SGregory Neil Shapiro 
25540266059SGregory Neil Shapiro /* ARGSUSED */
25640266059SGregory Neil Shapiro static void
25740266059SGregory Neil Shapiro ldaptimeout(unused)
25840266059SGregory Neil Shapiro 	int unused;
25940266059SGregory Neil Shapiro {
26040266059SGregory Neil Shapiro 	/*
26140266059SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
26240266059SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
26340266059SGregory Neil Shapiro 	**	DOING.
26440266059SGregory Neil Shapiro 	*/
26540266059SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro 	errno = ETIMEDOUT;
26740266059SGregory Neil Shapiro 	longjmp(LDAPTimeout, 1);
26840266059SGregory Neil Shapiro }
26940266059SGregory Neil Shapiro 
27040266059SGregory Neil Shapiro /*
271e92d3f3fSGregory Neil Shapiro **  SM_LDAP_SEARCH -- initiate LDAP search
27240266059SGregory Neil Shapiro **
27340266059SGregory Neil Shapiro **	Initiate an LDAP search, return the msgid.
27440266059SGregory Neil Shapiro **	The calling function must collect the results.
27540266059SGregory Neil Shapiro **
27640266059SGregory Neil Shapiro **	Parameters:
27740266059SGregory Neil Shapiro **		lmap -- LDAP map information
27840266059SGregory Neil Shapiro **		key -- key to substitute in LDAP filter
27940266059SGregory Neil Shapiro **
28040266059SGregory Neil Shapiro **	Returns:
28140266059SGregory Neil Shapiro **		-1 on failure, msgid on success
28240266059SGregory Neil Shapiro **
28340266059SGregory Neil Shapiro */
28440266059SGregory Neil Shapiro 
28540266059SGregory Neil Shapiro int
28640266059SGregory Neil Shapiro sm_ldap_search(lmap, key)
28740266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
28840266059SGregory Neil Shapiro 	char *key;
28940266059SGregory Neil Shapiro {
29040266059SGregory Neil Shapiro 	int msgid;
29140266059SGregory Neil Shapiro 	char *fp, *p, *q;
29240266059SGregory Neil Shapiro 	char filter[LDAPMAP_MAX_FILTER + 1];
29340266059SGregory Neil Shapiro 
29440266059SGregory Neil Shapiro 	/* substitute key into filter, perhaps multiple times */
29540266059SGregory Neil Shapiro 	memset(filter, '\0', sizeof filter);
29640266059SGregory Neil Shapiro 	fp = filter;
29740266059SGregory Neil Shapiro 	p = lmap->ldap_filter;
29840266059SGregory Neil Shapiro 	while ((q = strchr(p, '%')) != NULL)
29940266059SGregory Neil Shapiro 	{
30040266059SGregory Neil Shapiro 		if (q[1] == 's')
30140266059SGregory Neil Shapiro 		{
30240266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
30340266059SGregory Neil Shapiro 					   "%.*s%s", (int) (q - p), p, key);
30440266059SGregory Neil Shapiro 			fp += strlen(fp);
30540266059SGregory Neil Shapiro 			p = q + 2;
30640266059SGregory Neil Shapiro 		}
30740266059SGregory Neil Shapiro 		else if (q[1] == '0')
30840266059SGregory Neil Shapiro 		{
30940266059SGregory Neil Shapiro 			char *k = key;
31040266059SGregory Neil Shapiro 
31140266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
31240266059SGregory Neil Shapiro 					   "%.*s", (int) (q - p), p);
31340266059SGregory Neil Shapiro 			fp += strlen(fp);
31440266059SGregory Neil Shapiro 			p = q + 2;
31540266059SGregory Neil Shapiro 
31640266059SGregory Neil Shapiro 			/* Properly escape LDAP special characters */
31740266059SGregory Neil Shapiro 			while (SPACELEFT(filter, fp) > 0 &&
31840266059SGregory Neil Shapiro 			       *k != '\0')
31940266059SGregory Neil Shapiro 			{
32040266059SGregory Neil Shapiro 				if (*k == '*' || *k == '(' ||
32140266059SGregory Neil Shapiro 				    *k == ')' || *k == '\\')
32240266059SGregory Neil Shapiro 				{
32340266059SGregory Neil Shapiro 					(void) sm_strlcat(fp,
32440266059SGregory Neil Shapiro 						       (*k == '*' ? "\\2A" :
32540266059SGregory Neil Shapiro 							(*k == '(' ? "\\28" :
32640266059SGregory Neil Shapiro 							 (*k == ')' ? "\\29" :
32740266059SGregory Neil Shapiro 							  (*k == '\\' ? "\\5C" :
32840266059SGregory Neil Shapiro 							   "\00")))),
32940266059SGregory Neil Shapiro 						SPACELEFT(filter, fp));
33040266059SGregory Neil Shapiro 					fp += strlen(fp);
33140266059SGregory Neil Shapiro 					k++;
33240266059SGregory Neil Shapiro 				}
33340266059SGregory Neil Shapiro 				else
33440266059SGregory Neil Shapiro 					*fp++ = *k++;
33540266059SGregory Neil Shapiro 			}
33640266059SGregory Neil Shapiro 		}
33740266059SGregory Neil Shapiro 		else
33840266059SGregory Neil Shapiro 		{
33940266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
34040266059SGregory Neil Shapiro 				"%.*s", (int) (q - p + 1), p);
34140266059SGregory Neil Shapiro 			p = q + (q[1] == '%' ? 2 : 1);
34240266059SGregory Neil Shapiro 			fp += strlen(fp);
34340266059SGregory Neil Shapiro 		}
34440266059SGregory Neil Shapiro 	}
34540266059SGregory Neil Shapiro 	(void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
34640266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 20))
34740266059SGregory Neil Shapiro 		sm_dprintf("ldap search filter=%s\n", filter);
34840266059SGregory Neil Shapiro 
34940266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
350605302a5SGregory Neil Shapiro 	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
351605302a5SGregory Neil Shapiro 			    lmap->ldap_scope, filter,
35240266059SGregory Neil Shapiro 			    (lmap->ldap_attr[0] == NULL ? NULL :
35340266059SGregory Neil Shapiro 			     lmap->ldap_attr),
35440266059SGregory Neil Shapiro 			    lmap->ldap_attrsonly);
35540266059SGregory Neil Shapiro 	return msgid;
35640266059SGregory Neil Shapiro }
35740266059SGregory Neil Shapiro 
35840266059SGregory Neil Shapiro /*
359605302a5SGregory Neil Shapiro **  SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
360605302a5SGregory Neil Shapiro **			       particular objectClass
361605302a5SGregory Neil Shapiro **
362605302a5SGregory Neil Shapiro **	Parameters:
363605302a5SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
364605302a5SGregory Neil Shapiro **		entry -- current LDAP entry struct
365605302a5SGregory Neil Shapiro **		ocvalue -- particular objectclass in question.
366605302a5SGregory Neil Shapiro **			   may be of form (fee|foo|fum) meaning
367605302a5SGregory Neil Shapiro **			   any entry can be part of either fee,
368605302a5SGregory Neil Shapiro **			   foo or fum objectclass
369605302a5SGregory Neil Shapiro **
370605302a5SGregory Neil Shapiro **	Returns:
371605302a5SGregory Neil Shapiro **		true if item has that objectClass
372605302a5SGregory Neil Shapiro */
373605302a5SGregory Neil Shapiro 
374605302a5SGregory Neil Shapiro static bool
375605302a5SGregory Neil Shapiro sm_ldap_has_objectclass(lmap, entry, ocvalue)
376605302a5SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
377605302a5SGregory Neil Shapiro 	LDAPMessage *entry;
378605302a5SGregory Neil Shapiro 	char *ocvalue;
379605302a5SGregory Neil Shapiro {
380605302a5SGregory Neil Shapiro 	char **vals = NULL;
381605302a5SGregory Neil Shapiro 	int i;
382605302a5SGregory Neil Shapiro 
383605302a5SGregory Neil Shapiro 	if (ocvalue == NULL)
384605302a5SGregory Neil Shapiro 		return false;
385605302a5SGregory Neil Shapiro 
386605302a5SGregory Neil Shapiro 	vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
387605302a5SGregory Neil Shapiro 	if (vals == NULL)
388605302a5SGregory Neil Shapiro 		return false;
389605302a5SGregory Neil Shapiro 
390605302a5SGregory Neil Shapiro 	for (i = 0; vals[i] != NULL; i++)
391605302a5SGregory Neil Shapiro 	{
392605302a5SGregory Neil Shapiro 		char *p;
393605302a5SGregory Neil Shapiro 		char *q;
394605302a5SGregory Neil Shapiro 
395605302a5SGregory Neil Shapiro 		p = q = ocvalue;
396605302a5SGregory Neil Shapiro 		while (*p != '\0')
397605302a5SGregory Neil Shapiro 		{
398605302a5SGregory Neil Shapiro 			while (*p != '\0' && *p != '|')
399605302a5SGregory Neil Shapiro 				p++;
400605302a5SGregory Neil Shapiro 
401605302a5SGregory Neil Shapiro 			if ((p - q) == strlen(vals[i]) &&
402605302a5SGregory Neil Shapiro 			    sm_strncasecmp(vals[i], q, p - q) == 0)
403605302a5SGregory Neil Shapiro 			{
404605302a5SGregory Neil Shapiro 				ldap_value_free(vals);
405605302a5SGregory Neil Shapiro 				return true;
406605302a5SGregory Neil Shapiro 			}
407605302a5SGregory Neil Shapiro 
408605302a5SGregory Neil Shapiro 			while (*p == '|')
409605302a5SGregory Neil Shapiro 				p++;
410605302a5SGregory Neil Shapiro 			q = p;
411605302a5SGregory Neil Shapiro 		}
412605302a5SGregory Neil Shapiro 	}
413605302a5SGregory Neil Shapiro 
414605302a5SGregory Neil Shapiro 	ldap_value_free(vals);
415605302a5SGregory Neil Shapiro 	return false;
416605302a5SGregory Neil Shapiro }
417605302a5SGregory Neil Shapiro 
418605302a5SGregory Neil Shapiro /*
41940266059SGregory Neil Shapiro **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
42040266059SGregory Neil Shapiro **
42140266059SGregory Neil Shapiro **	Parameters:
42240266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
42340266059SGregory Neil Shapiro **		msgid -- msgid returned by sm_ldap_search()
42440266059SGregory Neil Shapiro **		flags -- flags for the lookup
42540266059SGregory Neil Shapiro **		delim -- delimiter for result concatenation
42640266059SGregory Neil Shapiro **		rpool -- memory pool for storage
42740266059SGregory Neil Shapiro **		result -- return string
42840266059SGregory Neil Shapiro **		recurse -- recursion list
42940266059SGregory Neil Shapiro **
43040266059SGregory Neil Shapiro **	Returns:
43140266059SGregory Neil Shapiro **		status (sysexit)
43240266059SGregory Neil Shapiro */
43340266059SGregory Neil Shapiro 
434605302a5SGregory Neil Shapiro # define SM_LDAP_ERROR_CLEANUP()				\
43540266059SGregory Neil Shapiro {								\
43640266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)				\
43740266059SGregory Neil Shapiro 	{							\
43840266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);			\
43940266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;				\
44040266059SGregory Neil Shapiro 	}							\
44140266059SGregory Neil Shapiro 	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
44240266059SGregory Neil Shapiro }
44340266059SGregory Neil Shapiro 
444605302a5SGregory Neil Shapiro static SM_LDAP_RECURSE_ENTRY *
445605302a5SGregory Neil Shapiro sm_ldap_add_recurse(top, item, type, rpool)
44640266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST **top;
44740266059SGregory Neil Shapiro 	char *item;
44840266059SGregory Neil Shapiro 	int type;
44940266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
45040266059SGregory Neil Shapiro {
451605302a5SGregory Neil Shapiro 	int n;
452605302a5SGregory Neil Shapiro 	int m;
453605302a5SGregory Neil Shapiro 	int p;
454605302a5SGregory Neil Shapiro 	int insertat;
455605302a5SGregory Neil Shapiro 	int moveb;
456605302a5SGregory Neil Shapiro 	int oldsizeb;
457605302a5SGregory Neil Shapiro 	int rc;
458605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *newe;
459605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY **olddata;
46040266059SGregory Neil Shapiro 
461605302a5SGregory Neil Shapiro 	/*
462605302a5SGregory Neil Shapiro 	**  This code will maintain a list of
463605302a5SGregory Neil Shapiro 	**  SM_LDAP_RECURSE_ENTRY structures
464605302a5SGregory Neil Shapiro 	**  in ascending order.
465605302a5SGregory Neil Shapiro 	*/
466605302a5SGregory Neil Shapiro 
467605302a5SGregory Neil Shapiro 	if (*top == NULL)
46840266059SGregory Neil Shapiro 	{
469605302a5SGregory Neil Shapiro 		/* Allocate an initial SM_LDAP_RECURSE_LIST struct */
470605302a5SGregory Neil Shapiro 		*top = sm_rpool_malloc_x(rpool, sizeof **top);
471605302a5SGregory Neil Shapiro 		(*top)->lr_cnt = 0;
472605302a5SGregory Neil Shapiro 		(*top)->lr_size = 0;
473605302a5SGregory Neil Shapiro 		(*top)->lr_data = NULL;
47440266059SGregory Neil Shapiro 	}
47540266059SGregory Neil Shapiro 
476605302a5SGregory Neil Shapiro 	if ((*top)->lr_cnt >= (*top)->lr_size)
477605302a5SGregory Neil Shapiro 	{
478605302a5SGregory Neil Shapiro 		/* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
479605302a5SGregory Neil Shapiro 		olddata = (*top)->lr_data;
480605302a5SGregory Neil Shapiro 		if ((*top)->lr_size == 0)
481605302a5SGregory Neil Shapiro 		{
482605302a5SGregory Neil Shapiro 			oldsizeb = 0;
483605302a5SGregory Neil Shapiro 			(*top)->lr_size = 256;
484605302a5SGregory Neil Shapiro 		}
48540266059SGregory Neil Shapiro 		else
486605302a5SGregory Neil Shapiro 		{
487605302a5SGregory Neil Shapiro 			oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data);
488605302a5SGregory Neil Shapiro 			(*top)->lr_size *= 2;
489605302a5SGregory Neil Shapiro 		}
490605302a5SGregory Neil Shapiro 		(*top)->lr_data = sm_rpool_malloc_x(rpool,
491605302a5SGregory Neil Shapiro 						    (*top)->lr_size * sizeof *((*top)->lr_data));
492605302a5SGregory Neil Shapiro 		if (oldsizeb > 0)
493605302a5SGregory Neil Shapiro 			memcpy((*top)->lr_data, olddata, oldsizeb);
494605302a5SGregory Neil Shapiro 	}
495605302a5SGregory Neil Shapiro 
496605302a5SGregory Neil Shapiro 	/*
497605302a5SGregory Neil Shapiro 	**  Binary search/insert item:type into list.
498605302a5SGregory Neil Shapiro 	**  Return current entry pointer if already exists.
499605302a5SGregory Neil Shapiro 	*/
500605302a5SGregory Neil Shapiro 
501605302a5SGregory Neil Shapiro 	n = 0;
502605302a5SGregory Neil Shapiro 	m = (*top)->lr_cnt - 1;
503605302a5SGregory Neil Shapiro 	if (m < 0)
504605302a5SGregory Neil Shapiro 		insertat = 0;
505605302a5SGregory Neil Shapiro 	else
506605302a5SGregory Neil Shapiro 		insertat = -1;
507605302a5SGregory Neil Shapiro 
508605302a5SGregory Neil Shapiro 	while (insertat == -1)
509605302a5SGregory Neil Shapiro 	{
510605302a5SGregory Neil Shapiro 		p = (m + n) / 2;
511605302a5SGregory Neil Shapiro 
512605302a5SGregory Neil Shapiro 		rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search);
513605302a5SGregory Neil Shapiro 		if (rc == 0)
514605302a5SGregory Neil Shapiro 			rc = type - (*top)->lr_data[p]->lr_type;
515605302a5SGregory Neil Shapiro 
516605302a5SGregory Neil Shapiro 		if (rc < 0)
517605302a5SGregory Neil Shapiro 			m = p - 1;
518605302a5SGregory Neil Shapiro 		else if (rc > 0)
519605302a5SGregory Neil Shapiro 			n = p + 1;
520605302a5SGregory Neil Shapiro 		else
521605302a5SGregory Neil Shapiro 			return (*top)->lr_data[p];
522605302a5SGregory Neil Shapiro 
523605302a5SGregory Neil Shapiro 		if (m == -1)
524605302a5SGregory Neil Shapiro 			insertat = 0;
525605302a5SGregory Neil Shapiro 		else if (n >= (*top)->lr_cnt)
526605302a5SGregory Neil Shapiro 			insertat = (*top)->lr_cnt;
527605302a5SGregory Neil Shapiro 		else if (m < n)
528605302a5SGregory Neil Shapiro 			insertat = m + 1;
529605302a5SGregory Neil Shapiro 	}
530605302a5SGregory Neil Shapiro 
531605302a5SGregory Neil Shapiro 	/*
532605302a5SGregory Neil Shapiro 	** Not found in list, make room
533605302a5SGregory Neil Shapiro 	** at insert point and add it.
534605302a5SGregory Neil Shapiro 	*/
535605302a5SGregory Neil Shapiro 
536605302a5SGregory Neil Shapiro 	newe = sm_rpool_malloc_x(rpool, sizeof *newe);
537605302a5SGregory Neil Shapiro 	if (newe != NULL)
538605302a5SGregory Neil Shapiro 	{
539605302a5SGregory Neil Shapiro 		moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data);
540605302a5SGregory Neil Shapiro 		if (moveb > 0)
541605302a5SGregory Neil Shapiro 			memmove(&((*top)->lr_data[insertat + 1]),
542605302a5SGregory Neil Shapiro 				&((*top)->lr_data[insertat]),
543605302a5SGregory Neil Shapiro 				moveb);
544605302a5SGregory Neil Shapiro 
545605302a5SGregory Neil Shapiro 		newe->lr_search = sm_rpool_strdup_x(rpool, item);
546605302a5SGregory Neil Shapiro 		newe->lr_type = type;
547e92d3f3fSGregory Neil Shapiro 		newe->lr_ludp = NULL;
548e92d3f3fSGregory Neil Shapiro 		newe->lr_attrs = NULL;
549605302a5SGregory Neil Shapiro 		newe->lr_done = false;
550605302a5SGregory Neil Shapiro 
551605302a5SGregory Neil Shapiro 		((*top)->lr_data)[insertat] = newe;
552605302a5SGregory Neil Shapiro 		(*top)->lr_cnt++;
553605302a5SGregory Neil Shapiro 	}
554605302a5SGregory Neil Shapiro 	return newe;
55540266059SGregory Neil Shapiro }
55640266059SGregory Neil Shapiro 
55740266059SGregory Neil Shapiro int
558605302a5SGregory Neil Shapiro sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
559605302a5SGregory Neil Shapiro 		resultln, resultsz, recurse)
56040266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
56140266059SGregory Neil Shapiro 	int msgid;
56240266059SGregory Neil Shapiro 	int flags;
563605302a5SGregory Neil Shapiro 	int delim;
56440266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
56540266059SGregory Neil Shapiro 	char **result;
566605302a5SGregory Neil Shapiro 	int *resultln;
567605302a5SGregory Neil Shapiro 	int *resultsz;
56840266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *recurse;
56940266059SGregory Neil Shapiro {
57040266059SGregory Neil Shapiro 	bool toplevel;
57140266059SGregory Neil Shapiro 	int i;
57240266059SGregory Neil Shapiro 	int statp;
57340266059SGregory Neil Shapiro 	int vsize;
57440266059SGregory Neil Shapiro 	int ret;
57540266059SGregory Neil Shapiro 	int save_errno;
57640266059SGregory Neil Shapiro 	char *p;
577605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *rl;
57840266059SGregory Neil Shapiro 
57940266059SGregory Neil Shapiro 	/* Are we the top top level of the search? */
58040266059SGregory Neil Shapiro 	toplevel = (recurse == NULL);
58140266059SGregory Neil Shapiro 
58240266059SGregory Neil Shapiro 	/* Get results */
58340266059SGregory Neil Shapiro 	statp = EX_NOTFOUND;
58440266059SGregory Neil Shapiro 	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
58540266059SGregory Neil Shapiro 				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
58640266059SGregory Neil Shapiro 				   &(lmap->ldap_timeout)),
58740266059SGregory Neil Shapiro 				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
58840266059SGregory Neil Shapiro 	{
58940266059SGregory Neil Shapiro 		LDAPMessage *entry;
59040266059SGregory Neil Shapiro 
59140266059SGregory Neil Shapiro 		/* If we don't want multiple values and we have one, break */
59213d88268SGregory Neil Shapiro 		if ((char) delim == '\0' &&
59313d88268SGregory Neil Shapiro 		    !bitset(SM_LDAP_SINGLEMATCH, flags) &&
59413d88268SGregory Neil Shapiro 		    *result != NULL)
59540266059SGregory Neil Shapiro 			break;
59640266059SGregory Neil Shapiro 
59740266059SGregory Neil Shapiro 		/* Cycle through all entries */
59840266059SGregory Neil Shapiro 		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
59940266059SGregory Neil Shapiro 		     entry != NULL;
60040266059SGregory Neil Shapiro 		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
60140266059SGregory Neil Shapiro 		{
60240266059SGregory Neil Shapiro 			BerElement *ber;
60340266059SGregory Neil Shapiro 			char *attr;
60440266059SGregory Neil Shapiro 			char **vals = NULL;
60540266059SGregory Neil Shapiro 			char *dn;
60640266059SGregory Neil Shapiro 
60740266059SGregory Neil Shapiro 			/*
60840266059SGregory Neil Shapiro 			**  If matching only and found an entry,
60940266059SGregory Neil Shapiro 			**  no need to spin through attributes
61040266059SGregory Neil Shapiro 			*/
61140266059SGregory Neil Shapiro 
612323f6dcbSGregory Neil Shapiro 			if (bitset(SM_LDAP_MATCHONLY, flags))
613323f6dcbSGregory Neil Shapiro 			{
614323f6dcbSGregory Neil Shapiro 				statp = EX_OK;
61540266059SGregory Neil Shapiro 				continue;
616323f6dcbSGregory Neil Shapiro 			}
61740266059SGregory Neil Shapiro 
61840266059SGregory Neil Shapiro 			/* record completed DN's to prevent loops */
61940266059SGregory Neil Shapiro 			dn = ldap_get_dn(lmap->ldap_ld, entry);
62040266059SGregory Neil Shapiro 			if (dn == NULL)
62140266059SGregory Neil Shapiro 			{
62240266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
62340266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
624605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
62540266059SGregory Neil Shapiro 				errno = save_errno;
626a7ec597cSGregory Neil Shapiro 				return EX_TEMPFAIL;
62740266059SGregory Neil Shapiro 			}
62840266059SGregory Neil Shapiro 
629605302a5SGregory Neil Shapiro 			rl = sm_ldap_add_recurse(&recurse, dn,
630605302a5SGregory Neil Shapiro 						 SM_LDAP_ATTR_DN,
631605302a5SGregory Neil Shapiro 						 rpool);
632605302a5SGregory Neil Shapiro 
633605302a5SGregory Neil Shapiro 			if (rl == NULL)
63440266059SGregory Neil Shapiro 			{
63540266059SGregory Neil Shapiro 				ldap_memfree(dn);
636605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
63740266059SGregory Neil Shapiro 				errno = ENOMEM;
63840266059SGregory Neil Shapiro 				return EX_OSERR;
639605302a5SGregory Neil Shapiro 			}
640605302a5SGregory Neil Shapiro 			else if (rl->lr_done)
641605302a5SGregory Neil Shapiro 			{
64240266059SGregory Neil Shapiro 				/* already on list, skip it */
64340266059SGregory Neil Shapiro 				ldap_memfree(dn);
64440266059SGregory Neil Shapiro 				continue;
64540266059SGregory Neil Shapiro 			}
64640266059SGregory Neil Shapiro 			ldap_memfree(dn);
64740266059SGregory Neil Shapiro 
64840266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
64940266059SGregory Neil Shapiro 			/*
65040266059SGregory Neil Shapiro 			**  Reset value to prevent lingering
65140266059SGregory Neil Shapiro 			**  LDAP_DECODING_ERROR due to
65240266059SGregory Neil Shapiro 			**  OpenLDAP 1.X's hack (see below)
65340266059SGregory Neil Shapiro 			*/
65440266059SGregory Neil Shapiro 
65540266059SGregory Neil Shapiro 			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
65640266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
65740266059SGregory Neil Shapiro 
65840266059SGregory Neil Shapiro 			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
65940266059SGregory Neil Shapiro 							 &ber);
66040266059SGregory Neil Shapiro 			     attr != NULL;
66140266059SGregory Neil Shapiro 			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
66240266059SGregory Neil Shapiro 							ber))
66340266059SGregory Neil Shapiro 			{
66440266059SGregory Neil Shapiro 				char *tmp, *vp_tmp;
66540266059SGregory Neil Shapiro 				int type;
666605302a5SGregory Neil Shapiro 				char *needobjclass = NULL;
66740266059SGregory Neil Shapiro 
668605302a5SGregory Neil Shapiro 				type = SM_LDAP_ATTR_NONE;
66940266059SGregory Neil Shapiro 				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
67040266059SGregory Neil Shapiro 				{
67140266059SGregory Neil Shapiro 					if (sm_strcasecmp(lmap->ldap_attr[i],
67240266059SGregory Neil Shapiro 							  attr) == 0)
67340266059SGregory Neil Shapiro 					{
67440266059SGregory Neil Shapiro 						type = lmap->ldap_attr_type[i];
675605302a5SGregory Neil Shapiro 						needobjclass = lmap->ldap_attr_needobjclass[i];
67640266059SGregory Neil Shapiro 						break;
67740266059SGregory Neil Shapiro 					}
67840266059SGregory Neil Shapiro 				}
679605302a5SGregory Neil Shapiro 
680605302a5SGregory Neil Shapiro 				if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
681605302a5SGregory Neil Shapiro 				    type == SM_LDAP_ATTR_NONE)
682605302a5SGregory Neil Shapiro 				{
683605302a5SGregory Neil Shapiro 					/* URL lookups specify attrs to use */
684605302a5SGregory Neil Shapiro 					type = SM_LDAP_ATTR_NORMAL;
685605302a5SGregory Neil Shapiro 					needobjclass = NULL;
686605302a5SGregory Neil Shapiro 				}
687605302a5SGregory Neil Shapiro 
688605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NONE)
68940266059SGregory Neil Shapiro 				{
69040266059SGregory Neil Shapiro 					/* attribute not requested */
69140266059SGregory Neil Shapiro 					ldap_memfree(attr);
692605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
69340266059SGregory Neil Shapiro 					errno = EFAULT;
69440266059SGregory Neil Shapiro 					return EX_SOFTWARE;
69540266059SGregory Neil Shapiro 				}
69640266059SGregory Neil Shapiro 
697605302a5SGregory Neil Shapiro 				/*
698605302a5SGregory Neil Shapiro 				**  For recursion on a particular attribute,
699605302a5SGregory Neil Shapiro 				**  we may need to see if this entry is
700605302a5SGregory Neil Shapiro 				**  part of a particular objectclass.
701605302a5SGregory Neil Shapiro 				**  Also, ignore objectClass attribute.
702605302a5SGregory Neil Shapiro 				**  Otherwise we just ignore this attribute.
703605302a5SGregory Neil Shapiro 				*/
704605302a5SGregory Neil Shapiro 
705605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_OBJCLASS ||
706605302a5SGregory Neil Shapiro 				    (needobjclass != NULL &&
707605302a5SGregory Neil Shapiro 				     !sm_ldap_has_objectclass(lmap, entry,
708605302a5SGregory Neil Shapiro 							      needobjclass)))
709605302a5SGregory Neil Shapiro 				{
710605302a5SGregory Neil Shapiro 					ldap_memfree(attr);
711605302a5SGregory Neil Shapiro 					continue;
712605302a5SGregory Neil Shapiro 				}
713605302a5SGregory Neil Shapiro 
71440266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
71540266059SGregory Neil Shapiro 				{
71640266059SGregory Neil Shapiro 					vals = ldap_get_values(lmap->ldap_ld,
71740266059SGregory Neil Shapiro 							       entry,
71840266059SGregory Neil Shapiro 							       attr);
71940266059SGregory Neil Shapiro 					if (vals == NULL)
72040266059SGregory Neil Shapiro 					{
72140266059SGregory Neil Shapiro 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
72240266059SGregory Neil Shapiro 						if (save_errno == LDAP_SUCCESS)
72340266059SGregory Neil Shapiro 						{
72440266059SGregory Neil Shapiro 							ldap_memfree(attr);
72540266059SGregory Neil Shapiro 							continue;
72640266059SGregory Neil Shapiro 						}
72740266059SGregory Neil Shapiro 
72840266059SGregory Neil Shapiro 						/* Must be an error */
72940266059SGregory Neil Shapiro 						save_errno += E_LDAPBASE;
73040266059SGregory Neil Shapiro 						ldap_memfree(attr);
731605302a5SGregory Neil Shapiro 						SM_LDAP_ERROR_CLEANUP();
73240266059SGregory Neil Shapiro 						errno = save_errno;
73340266059SGregory Neil Shapiro 						return EX_TEMPFAIL;
73440266059SGregory Neil Shapiro 					}
73540266059SGregory Neil Shapiro 				}
73640266059SGregory Neil Shapiro 
73740266059SGregory Neil Shapiro 				statp = EX_OK;
73840266059SGregory Neil Shapiro 
73940266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
74040266059SGregory Neil Shapiro 				/*
74140266059SGregory Neil Shapiro 				**  Reset value to prevent lingering
74240266059SGregory Neil Shapiro 				**  LDAP_DECODING_ERROR due to
74340266059SGregory Neil Shapiro 				**  OpenLDAP 1.X's hack (see below)
74440266059SGregory Neil Shapiro 				*/
74540266059SGregory Neil Shapiro 
74640266059SGregory Neil Shapiro 				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
74740266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
74840266059SGregory Neil Shapiro 
74940266059SGregory Neil Shapiro 				/*
75040266059SGregory Neil Shapiro 				**  If matching only,
75140266059SGregory Neil Shapiro 				**  no need to spin through entries
75240266059SGregory Neil Shapiro 				*/
75340266059SGregory Neil Shapiro 
75440266059SGregory Neil Shapiro 				if (bitset(SM_LDAP_MATCHONLY, flags))
75540266059SGregory Neil Shapiro 				{
75640266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
75740266059SGregory Neil Shapiro 						ldap_value_free(vals);
75840266059SGregory Neil Shapiro 					ldap_memfree(attr);
75940266059SGregory Neil Shapiro 					continue;
76040266059SGregory Neil Shapiro 				}
76140266059SGregory Neil Shapiro 
76240266059SGregory Neil Shapiro 				/*
76340266059SGregory Neil Shapiro 				**  If we don't want multiple values,
76440266059SGregory Neil Shapiro 				**  return first found.
76540266059SGregory Neil Shapiro 				*/
76640266059SGregory Neil Shapiro 
767605302a5SGregory Neil Shapiro 				if ((char) delim == '\0')
76840266059SGregory Neil Shapiro 				{
769605302a5SGregory Neil Shapiro 					if (*result != NULL)
770605302a5SGregory Neil Shapiro 					{
771605302a5SGregory Neil Shapiro 						/* already have a value */
772605302a5SGregory Neil Shapiro 						if (bitset(SM_LDAP_SINGLEMATCH,
77313d88268SGregory Neil Shapiro 							   flags))
774605302a5SGregory Neil Shapiro 						{
775605302a5SGregory Neil Shapiro 							/* only wanted one match */
776605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
777605302a5SGregory Neil Shapiro 							errno = ENOENT;
778605302a5SGregory Neil Shapiro 							return EX_NOTFOUND;
779605302a5SGregory Neil Shapiro 						}
78013d88268SGregory Neil Shapiro 						break;
78113d88268SGregory Neil Shapiro 					}
782605302a5SGregory Neil Shapiro 
78340266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
78440266059SGregory Neil Shapiro 					{
78540266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
78640266059SGregory Neil Shapiro 									    attr);
78740266059SGregory Neil Shapiro 						ldap_memfree(attr);
78840266059SGregory Neil Shapiro 						break;
78940266059SGregory Neil Shapiro 					}
79040266059SGregory Neil Shapiro 
79140266059SGregory Neil Shapiro 					if (vals[0] == NULL)
79240266059SGregory Neil Shapiro 					{
79340266059SGregory Neil Shapiro 						ldap_value_free(vals);
79440266059SGregory Neil Shapiro 						ldap_memfree(attr);
79540266059SGregory Neil Shapiro 						continue;
79640266059SGregory Neil Shapiro 					}
79740266059SGregory Neil Shapiro 
79840266059SGregory Neil Shapiro 					vsize = strlen(vals[0]) + 1;
79940266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
80040266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
80140266059SGregory Neil Shapiro 					*result = sm_rpool_malloc_x(rpool,
80240266059SGregory Neil Shapiro 								    vsize);
80340266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
80440266059SGregory Neil Shapiro 						sm_snprintf(*result, vsize,
80540266059SGregory Neil Shapiro 							    "%s%c%s",
80640266059SGregory Neil Shapiro 							    attr,
80740266059SGregory Neil Shapiro 							    lmap->ldap_attrsep,
80840266059SGregory Neil Shapiro 							    vals[0]);
80940266059SGregory Neil Shapiro 					else
81040266059SGregory Neil Shapiro 						sm_strlcpy(*result, vals[0],
81140266059SGregory Neil Shapiro 							   vsize);
81240266059SGregory Neil Shapiro 					ldap_value_free(vals);
81340266059SGregory Neil Shapiro 					ldap_memfree(attr);
81440266059SGregory Neil Shapiro 					break;
81540266059SGregory Neil Shapiro 				}
81640266059SGregory Neil Shapiro 
81740266059SGregory Neil Shapiro 				/* attributes only */
81840266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
81940266059SGregory Neil Shapiro 				{
82040266059SGregory Neil Shapiro 					if (*result == NULL)
82140266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
82240266059SGregory Neil Shapiro 									    attr);
82340266059SGregory Neil Shapiro 					else
82440266059SGregory Neil Shapiro 					{
825605302a5SGregory Neil Shapiro 						if (bitset(SM_LDAP_SINGLEMATCH,
826605302a5SGregory Neil Shapiro 							   flags) &&
827605302a5SGregory Neil Shapiro 						    *result != NULL)
828605302a5SGregory Neil Shapiro 						{
829605302a5SGregory Neil Shapiro 							/* only wanted one match */
830605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
831605302a5SGregory Neil Shapiro 							errno = ENOENT;
832605302a5SGregory Neil Shapiro 							return EX_NOTFOUND;
833605302a5SGregory Neil Shapiro 						}
834605302a5SGregory Neil Shapiro 
83540266059SGregory Neil Shapiro 						vsize = strlen(*result) +
83640266059SGregory Neil Shapiro 							strlen(attr) + 2;
83740266059SGregory Neil Shapiro 						tmp = sm_rpool_malloc_x(rpool,
83840266059SGregory Neil Shapiro 									vsize);
83940266059SGregory Neil Shapiro 						(void) sm_snprintf(tmp,
84040266059SGregory Neil Shapiro 							vsize, "%s%c%s",
841605302a5SGregory Neil Shapiro 							*result, (char) delim,
84240266059SGregory Neil Shapiro 							attr);
84340266059SGregory Neil Shapiro 						*result = tmp;
84440266059SGregory Neil Shapiro 					}
84540266059SGregory Neil Shapiro 					ldap_memfree(attr);
84640266059SGregory Neil Shapiro 					continue;
84740266059SGregory Neil Shapiro 				}
84840266059SGregory Neil Shapiro 
84940266059SGregory Neil Shapiro 				/*
850605302a5SGregory Neil Shapiro 				**  If there is more than one, munge then
851605302a5SGregory Neil Shapiro 				**  into a map_coldelim separated string.
852605302a5SGregory Neil Shapiro 				**  If we are recursing we may have an entry
853605302a5SGregory Neil Shapiro 				**  with no 'normal' values to put in the
854605302a5SGregory Neil Shapiro 				**  string.
855605302a5SGregory Neil Shapiro 				**  This is not an error.
85640266059SGregory Neil Shapiro 				*/
85740266059SGregory Neil Shapiro 
858605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL &&
859605302a5SGregory Neil Shapiro 				    bitset(SM_LDAP_SINGLEMATCH, flags) &&
860605302a5SGregory Neil Shapiro 				    *result != NULL)
861605302a5SGregory Neil Shapiro 				{
862605302a5SGregory Neil Shapiro 					/* only wanted one match */
863605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
864605302a5SGregory Neil Shapiro 					errno = ENOENT;
865605302a5SGregory Neil Shapiro 					return EX_NOTFOUND;
866605302a5SGregory Neil Shapiro 				}
867605302a5SGregory Neil Shapiro 
86840266059SGregory Neil Shapiro 				vsize = 0;
86940266059SGregory Neil Shapiro 				for (i = 0; vals[i] != NULL; i++)
87040266059SGregory Neil Shapiro 				{
871605302a5SGregory Neil Shapiro 					if (type == SM_LDAP_ATTR_DN ||
872605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_FILTER ||
873605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_URL)
87440266059SGregory Neil Shapiro 					{
875605302a5SGregory Neil Shapiro 						/* add to recursion */
876605302a5SGregory Neil Shapiro 						if (sm_ldap_add_recurse(&recurse,
87740266059SGregory Neil Shapiro 									vals[i],
878605302a5SGregory Neil Shapiro 									type,
879605302a5SGregory Neil Shapiro 									rpool) == NULL)
88040266059SGregory Neil Shapiro 						{
881605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
88240266059SGregory Neil Shapiro 							errno = ENOMEM;
88340266059SGregory Neil Shapiro 							return EX_OSERR;
88440266059SGregory Neil Shapiro 						}
88540266059SGregory Neil Shapiro 						continue;
88640266059SGregory Neil Shapiro 					}
887605302a5SGregory Neil Shapiro 
88840266059SGregory Neil Shapiro 					vsize += strlen(vals[i]) + 1;
88940266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
89040266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
89140266059SGregory Neil Shapiro 				}
892605302a5SGregory Neil Shapiro 
893605302a5SGregory Neil Shapiro 				/*
894605302a5SGregory Neil Shapiro 				**  Create/Append to string any normal
895605302a5SGregory Neil Shapiro 				**  attribute values.  Otherwise, just free
896605302a5SGregory Neil Shapiro 				**  memory and move on to the next
897605302a5SGregory Neil Shapiro 				**  attribute in this entry.
898605302a5SGregory Neil Shapiro 				*/
899605302a5SGregory Neil Shapiro 
900605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
901605302a5SGregory Neil Shapiro 				{
902605302a5SGregory Neil Shapiro 					char *pe;
903605302a5SGregory Neil Shapiro 
904605302a5SGregory Neil Shapiro 					/* Grow result string if needed */
905605302a5SGregory Neil Shapiro 					if ((*resultln + vsize) >= *resultsz)
906605302a5SGregory Neil Shapiro 					{
907605302a5SGregory Neil Shapiro 						while ((*resultln + vsize) >= *resultsz)
908605302a5SGregory Neil Shapiro 						{
909605302a5SGregory Neil Shapiro 							if (*resultsz == 0)
910605302a5SGregory Neil Shapiro 								*resultsz = 1024;
911605302a5SGregory Neil Shapiro 							else
912605302a5SGregory Neil Shapiro 								*resultsz *= 2;
913605302a5SGregory Neil Shapiro 						}
914605302a5SGregory Neil Shapiro 
915605302a5SGregory Neil Shapiro 						vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
91640266059SGregory Neil Shapiro 						*vp_tmp = '\0';
91740266059SGregory Neil Shapiro 
918605302a5SGregory Neil Shapiro 						if (*result != NULL)
919605302a5SGregory Neil Shapiro 							sm_strlcpy(vp_tmp,
920605302a5SGregory Neil Shapiro 								   *result,
921605302a5SGregory Neil Shapiro 								   *resultsz);
922605302a5SGregory Neil Shapiro 						*result = vp_tmp;
923605302a5SGregory Neil Shapiro 					}
924605302a5SGregory Neil Shapiro 
925605302a5SGregory Neil Shapiro 					p = *result + *resultln;
926605302a5SGregory Neil Shapiro 					pe = *result + *resultsz;
927605302a5SGregory Neil Shapiro 
92840266059SGregory Neil Shapiro 					for (i = 0; vals[i] != NULL; i++)
92940266059SGregory Neil Shapiro 					{
930959366dcSGregory Neil Shapiro 						if (*resultln > 0 &&
931959366dcSGregory Neil Shapiro 						    p < pe)
932605302a5SGregory Neil Shapiro 							*p++ = (char) delim;
933605302a5SGregory Neil Shapiro 
93440266059SGregory Neil Shapiro 						if (lmap->ldap_attrsep != '\0')
93540266059SGregory Neil Shapiro 						{
93640266059SGregory Neil Shapiro 							p += sm_strlcpy(p, attr,
937605302a5SGregory Neil Shapiro 									pe - p);
938605302a5SGregory Neil Shapiro 							if (p < pe)
93940266059SGregory Neil Shapiro 								*p++ = lmap->ldap_attrsep;
94040266059SGregory Neil Shapiro 						}
941605302a5SGregory Neil Shapiro 
94240266059SGregory Neil Shapiro 						p += sm_strlcpy(p, vals[i],
943605302a5SGregory Neil Shapiro 								pe - p);
944605302a5SGregory Neil Shapiro 						*resultln = p - (*result);
945605302a5SGregory Neil Shapiro 						if (p >= pe)
94640266059SGregory Neil Shapiro 						{
94740266059SGregory Neil Shapiro 							/* Internal error: buffer too small for LDAP values */
948605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
94940266059SGregory Neil Shapiro 							errno = ENOMEM;
95040266059SGregory Neil Shapiro 							return EX_OSERR;
95140266059SGregory Neil Shapiro 						}
952605302a5SGregory Neil Shapiro 					}
95340266059SGregory Neil Shapiro 				}
95440266059SGregory Neil Shapiro 
95540266059SGregory Neil Shapiro 				ldap_value_free(vals);
95640266059SGregory Neil Shapiro 				ldap_memfree(attr);
95740266059SGregory Neil Shapiro 			}
95840266059SGregory Neil Shapiro 			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
95940266059SGregory Neil Shapiro 
96040266059SGregory Neil Shapiro 			/*
96140266059SGregory Neil Shapiro 			**  We check save_errno != LDAP_DECODING_ERROR since
96240266059SGregory Neil Shapiro 			**  OpenLDAP 1.X has a very ugly *undocumented*
96340266059SGregory Neil Shapiro 			**  hack of returning this error code from
96440266059SGregory Neil Shapiro 			**  ldap_next_attribute() if the library freed the
96540266059SGregory Neil Shapiro 			**  ber attribute.  See:
96640266059SGregory Neil Shapiro 			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
96740266059SGregory Neil Shapiro 			*/
96840266059SGregory Neil Shapiro 
96940266059SGregory Neil Shapiro 			if (save_errno != LDAP_SUCCESS &&
97040266059SGregory Neil Shapiro 			    save_errno != LDAP_DECODING_ERROR)
97140266059SGregory Neil Shapiro 			{
97240266059SGregory Neil Shapiro 				/* Must be an error */
97340266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
974605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
97540266059SGregory Neil Shapiro 				errno = save_errno;
97640266059SGregory Neil Shapiro 				return EX_TEMPFAIL;
97740266059SGregory Neil Shapiro 			}
97840266059SGregory Neil Shapiro 
979605302a5SGregory Neil Shapiro 			/* mark this DN as done */
980605302a5SGregory Neil Shapiro 			rl->lr_done = true;
981e92d3f3fSGregory Neil Shapiro 			if (rl->lr_ludp != NULL)
982e92d3f3fSGregory Neil Shapiro 			{
983e92d3f3fSGregory Neil Shapiro 				ldap_free_urldesc(rl->lr_ludp);
984e92d3f3fSGregory Neil Shapiro 				rl->lr_ludp = NULL;
985e92d3f3fSGregory Neil Shapiro 			}
986e92d3f3fSGregory Neil Shapiro 			if (rl->lr_attrs != NULL)
987e92d3f3fSGregory Neil Shapiro 			{
988e92d3f3fSGregory Neil Shapiro 				free(rl->lr_attrs);
989e92d3f3fSGregory Neil Shapiro 				rl->lr_attrs = NULL;
990e92d3f3fSGregory Neil Shapiro 			}
991605302a5SGregory Neil Shapiro 
99240266059SGregory Neil Shapiro 			/* We don't want multiple values and we have one */
99313d88268SGregory Neil Shapiro 			if ((char) delim == '\0' &&
99413d88268SGregory Neil Shapiro 			    !bitset(SM_LDAP_SINGLEMATCH, flags) &&
99513d88268SGregory Neil Shapiro 			    *result != NULL)
99640266059SGregory Neil Shapiro 				break;
99740266059SGregory Neil Shapiro 		}
99840266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
99940266059SGregory Neil Shapiro 		if (save_errno != LDAP_SUCCESS &&
100040266059SGregory Neil Shapiro 		    save_errno != LDAP_DECODING_ERROR)
100140266059SGregory Neil Shapiro 		{
100240266059SGregory Neil Shapiro 			/* Must be an error */
100340266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
1004605302a5SGregory Neil Shapiro 			SM_LDAP_ERROR_CLEANUP();
100540266059SGregory Neil Shapiro 			errno = save_errno;
100640266059SGregory Neil Shapiro 			return EX_TEMPFAIL;
100740266059SGregory Neil Shapiro 		}
100840266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
100940266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
101040266059SGregory Neil Shapiro 	}
101140266059SGregory Neil Shapiro 
101240266059SGregory Neil Shapiro 	if (ret == 0)
101340266059SGregory Neil Shapiro 		save_errno = ETIMEDOUT;
101440266059SGregory Neil Shapiro 	else
101540266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
101640266059SGregory Neil Shapiro 	if (save_errno != LDAP_SUCCESS)
101740266059SGregory Neil Shapiro 	{
101840266059SGregory Neil Shapiro 		statp = EX_TEMPFAIL;
101940266059SGregory Neil Shapiro 		if (ret != 0)
102040266059SGregory Neil Shapiro 		{
102140266059SGregory Neil Shapiro 			switch (save_errno)
102240266059SGregory Neil Shapiro 			{
102340266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
102440266059SGregory Neil Shapiro 			  case LDAP_SERVER_DOWN:
102540266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
102640266059SGregory Neil Shapiro 			  case LDAP_TIMEOUT:
102740266059SGregory Neil Shapiro 			  case LDAP_UNAVAILABLE:
1028605302a5SGregory Neil Shapiro 
1029605302a5SGregory Neil Shapiro 				/*
1030605302a5SGregory Neil Shapiro 				**  server disappeared,
1031605302a5SGregory Neil Shapiro 				**  try reopen on next search
1032605302a5SGregory Neil Shapiro 				*/
1033605302a5SGregory Neil Shapiro 
103440266059SGregory Neil Shapiro 				statp = EX_RESTART;
103540266059SGregory Neil Shapiro 				break;
103640266059SGregory Neil Shapiro 			}
103740266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
103840266059SGregory Neil Shapiro 		}
1039605302a5SGregory Neil Shapiro 		SM_LDAP_ERROR_CLEANUP();
104040266059SGregory Neil Shapiro 		errno = save_errno;
104140266059SGregory Neil Shapiro 		return statp;
104240266059SGregory Neil Shapiro 	}
104340266059SGregory Neil Shapiro 
104440266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)
104540266059SGregory Neil Shapiro 	{
104640266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
104740266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
104840266059SGregory Neil Shapiro 	}
104940266059SGregory Neil Shapiro 
105040266059SGregory Neil Shapiro 	if (toplevel)
105140266059SGregory Neil Shapiro 	{
1052605302a5SGregory Neil Shapiro 		int rlidx;
105340266059SGregory Neil Shapiro 
105440266059SGregory Neil Shapiro 		/*
105540266059SGregory Neil Shapiro 		**  Spin through the built-up recurse list at the top
105640266059SGregory Neil Shapiro 		**  of the recursion.  Since new items are added at the
105740266059SGregory Neil Shapiro 		**  end of the shared list, we actually only ever get
105840266059SGregory Neil Shapiro 		**  one level of recursion before things pop back to the
105940266059SGregory Neil Shapiro 		**  top.  Any items added to the list during that recursion
106040266059SGregory Neil Shapiro 		**  will be expanded by the top level.
106140266059SGregory Neil Shapiro 		*/
106240266059SGregory Neil Shapiro 
1063605302a5SGregory Neil Shapiro 		for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)
106440266059SGregory Neil Shapiro 		{
1065605302a5SGregory Neil Shapiro 			int newflags;
106640266059SGregory Neil Shapiro 			int sid;
106740266059SGregory Neil Shapiro 			int status;
106840266059SGregory Neil Shapiro 
1069605302a5SGregory Neil Shapiro 			rl = recurse->lr_data[rlidx];
1070605302a5SGregory Neil Shapiro 
1071605302a5SGregory Neil Shapiro 			newflags = flags;
1072605302a5SGregory Neil Shapiro 			if (rl->lr_done)
107340266059SGregory Neil Shapiro 			{
107440266059SGregory Neil Shapiro 				/* already expanded */
107540266059SGregory Neil Shapiro 				continue;
107640266059SGregory Neil Shapiro 			}
1077605302a5SGregory Neil Shapiro 
1078605302a5SGregory Neil Shapiro 			if (rl->lr_type == SM_LDAP_ATTR_DN)
107940266059SGregory Neil Shapiro 			{
108040266059SGregory Neil Shapiro 				/* do DN search */
108140266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
108240266059SGregory Neil Shapiro 						  rl->lr_search,
108340266059SGregory Neil Shapiro 						  lmap->ldap_scope,
108440266059SGregory Neil Shapiro 						  "(objectClass=*)",
1085605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1086605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
108740266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
108840266059SGregory Neil Shapiro 			}
1089605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
109040266059SGregory Neil Shapiro 			{
109140266059SGregory Neil Shapiro 				/* do new search */
109240266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
109340266059SGregory Neil Shapiro 						  lmap->ldap_base,
109440266059SGregory Neil Shapiro 						  lmap->ldap_scope,
109540266059SGregory Neil Shapiro 						  rl->lr_search,
1096605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1097605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
109840266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
109940266059SGregory Neil Shapiro 			}
1100605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_URL)
110140266059SGregory Neil Shapiro 			{
1102e92d3f3fSGregory Neil Shapiro 				/* Parse URL */
1103e92d3f3fSGregory Neil Shapiro 				sid = ldap_url_parse(rl->lr_search,
1104e92d3f3fSGregory Neil Shapiro 						     &rl->lr_ludp);
1105e92d3f3fSGregory Neil Shapiro 
1106e92d3f3fSGregory Neil Shapiro 				if (sid != 0)
1107e92d3f3fSGregory Neil Shapiro 				{
1108e92d3f3fSGregory Neil Shapiro 					errno = sid + E_LDAPURLBASE;
1109e92d3f3fSGregory Neil Shapiro 					return EX_TEMPFAIL;
1110e92d3f3fSGregory Neil Shapiro 				}
1111e92d3f3fSGregory Neil Shapiro 
1112e92d3f3fSGregory Neil Shapiro 				/* We need to add objectClass */
1113e92d3f3fSGregory Neil Shapiro 				if (rl->lr_ludp->lud_attrs != NULL)
1114e92d3f3fSGregory Neil Shapiro 				{
1115e92d3f3fSGregory Neil Shapiro 					int attrnum = 0;
1116e92d3f3fSGregory Neil Shapiro 
1117e92d3f3fSGregory Neil Shapiro 					while (rl->lr_ludp->lud_attrs[attrnum] != NULL)
1118e92d3f3fSGregory Neil Shapiro 					{
1119e92d3f3fSGregory Neil Shapiro 						if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum],
1120e92d3f3fSGregory Neil Shapiro 							       "objectClass") == 0)
1121e92d3f3fSGregory Neil Shapiro 						{
1122e92d3f3fSGregory Neil Shapiro 							/* already requested */
1123e92d3f3fSGregory Neil Shapiro 							attrnum = -1;
1124e92d3f3fSGregory Neil Shapiro 							break;
1125e92d3f3fSGregory Neil Shapiro 						}
1126e92d3f3fSGregory Neil Shapiro 						attrnum++;
1127e92d3f3fSGregory Neil Shapiro 					}
1128e92d3f3fSGregory Neil Shapiro 
1129e92d3f3fSGregory Neil Shapiro 					if (attrnum >= 0)
1130e92d3f3fSGregory Neil Shapiro 					{
1131e92d3f3fSGregory Neil Shapiro 						int i;
1132e92d3f3fSGregory Neil Shapiro 
1133e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2));
1134e92d3f3fSGregory Neil Shapiro 						if (rl->lr_attrs == NULL)
1135e92d3f3fSGregory Neil Shapiro 						{
1136e92d3f3fSGregory Neil Shapiro 							save_errno = errno;
1137e92d3f3fSGregory Neil Shapiro 							ldap_free_urldesc(rl->lr_ludp);
1138e92d3f3fSGregory Neil Shapiro 							errno = save_errno;
1139e92d3f3fSGregory Neil Shapiro 							return EX_TEMPFAIL;
1140e92d3f3fSGregory Neil Shapiro 						}
1141e92d3f3fSGregory Neil Shapiro 						for (i = 0 ; i < attrnum; i++)
1142e92d3f3fSGregory Neil Shapiro 						{
1143e92d3f3fSGregory Neil Shapiro 							rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i];
1144e92d3f3fSGregory Neil Shapiro 						}
1145e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs[i++] = "objectClass";
1146e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs[i++] = NULL;
1147e92d3f3fSGregory Neil Shapiro 					}
1148e92d3f3fSGregory Neil Shapiro 				}
1149e92d3f3fSGregory Neil Shapiro 
1150e92d3f3fSGregory Neil Shapiro 				/*
1151e92d3f3fSGregory Neil Shapiro 				**  Use the existing connection
1152e92d3f3fSGregory Neil Shapiro 				**  for this search.  It really
1153e92d3f3fSGregory Neil Shapiro 				**  should use lud_scheme://lud_host:lud_port/
1154e92d3f3fSGregory Neil Shapiro 				**  instead but that would require
1155e92d3f3fSGregory Neil Shapiro 				**  opening a new connection.
1156e92d3f3fSGregory Neil Shapiro 				**  This should be fixed ASAP.
1157e92d3f3fSGregory Neil Shapiro 				*/
1158e92d3f3fSGregory Neil Shapiro 
1159e92d3f3fSGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
1160e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_dn,
1161e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_scope,
1162e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_filter,
1163e92d3f3fSGregory Neil Shapiro 						  rl->lr_attrs,
116440266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
1165e92d3f3fSGregory Neil Shapiro 
1166e92d3f3fSGregory Neil Shapiro 				/* Use the attributes specified by URL */
1167605302a5SGregory Neil Shapiro 				newflags |= SM_LDAP_USE_ALLATTR;
116840266059SGregory Neil Shapiro 			}
116940266059SGregory Neil Shapiro 			else
117040266059SGregory Neil Shapiro 			{
117140266059SGregory Neil Shapiro 				/* unknown or illegal attribute type */
117240266059SGregory Neil Shapiro 				errno = EFAULT;
117340266059SGregory Neil Shapiro 				return EX_SOFTWARE;
117440266059SGregory Neil Shapiro 			}
117540266059SGregory Neil Shapiro 
117640266059SGregory Neil Shapiro 			/* Collect results */
117740266059SGregory Neil Shapiro 			if (sid == -1)
117840266059SGregory Neil Shapiro 			{
117940266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
118040266059SGregory Neil Shapiro 				statp = EX_TEMPFAIL;
118140266059SGregory Neil Shapiro 				switch (save_errno)
118240266059SGregory Neil Shapiro 				{
118340266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
118440266059SGregory Neil Shapiro 				  case LDAP_SERVER_DOWN:
118540266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
118640266059SGregory Neil Shapiro 				  case LDAP_TIMEOUT:
118740266059SGregory Neil Shapiro 				  case LDAP_UNAVAILABLE:
1188605302a5SGregory Neil Shapiro 
1189605302a5SGregory Neil Shapiro 					/*
1190605302a5SGregory Neil Shapiro 					**  server disappeared,
1191605302a5SGregory Neil Shapiro 					**  try reopen on next search
1192605302a5SGregory Neil Shapiro 					*/
1193605302a5SGregory Neil Shapiro 
119440266059SGregory Neil Shapiro 					statp = EX_RESTART;
119540266059SGregory Neil Shapiro 					break;
119640266059SGregory Neil Shapiro 				}
119740266059SGregory Neil Shapiro 				errno = save_errno + E_LDAPBASE;
119840266059SGregory Neil Shapiro 				return statp;
119940266059SGregory Neil Shapiro 			}
120040266059SGregory Neil Shapiro 
1201605302a5SGregory Neil Shapiro 			status = sm_ldap_results(lmap, sid, newflags, delim,
1202605302a5SGregory Neil Shapiro 						 rpool, result, resultln,
1203605302a5SGregory Neil Shapiro 						 resultsz, recurse);
120440266059SGregory Neil Shapiro 			save_errno = errno;
120540266059SGregory Neil Shapiro 			if (status != EX_OK && status != EX_NOTFOUND)
120640266059SGregory Neil Shapiro 			{
120740266059SGregory Neil Shapiro 				errno = save_errno;
120840266059SGregory Neil Shapiro 				return status;
120940266059SGregory Neil Shapiro 			}
121040266059SGregory Neil Shapiro 
121140266059SGregory Neil Shapiro 			/* Mark as done */
1212605302a5SGregory Neil Shapiro 			rl->lr_done = true;
1213e92d3f3fSGregory Neil Shapiro 			if (rl->lr_ludp != NULL)
1214e92d3f3fSGregory Neil Shapiro 			{
1215e92d3f3fSGregory Neil Shapiro 				ldap_free_urldesc(rl->lr_ludp);
1216e92d3f3fSGregory Neil Shapiro 				rl->lr_ludp = NULL;
1217e92d3f3fSGregory Neil Shapiro 			}
1218e92d3f3fSGregory Neil Shapiro 			if (rl->lr_attrs != NULL)
1219e92d3f3fSGregory Neil Shapiro 			{
1220e92d3f3fSGregory Neil Shapiro 				free(rl->lr_attrs);
1221e92d3f3fSGregory Neil Shapiro 				rl->lr_attrs = NULL;
1222e92d3f3fSGregory Neil Shapiro 			}
1223605302a5SGregory Neil Shapiro 
1224605302a5SGregory Neil Shapiro 			/* Reset rlidx as new items may have been added */
1225605302a5SGregory Neil Shapiro 			rlidx = -1;
122640266059SGregory Neil Shapiro 		}
122740266059SGregory Neil Shapiro 	}
122840266059SGregory Neil Shapiro 	return statp;
122940266059SGregory Neil Shapiro }
123040266059SGregory Neil Shapiro 
123140266059SGregory Neil Shapiro /*
123240266059SGregory Neil Shapiro **  SM_LDAP_CLOSE -- close LDAP connection
123340266059SGregory Neil Shapiro **
123440266059SGregory Neil Shapiro **	Parameters:
123540266059SGregory Neil Shapiro **		lmap -- LDAP map information
123640266059SGregory Neil Shapiro **
123740266059SGregory Neil Shapiro **	Returns:
123840266059SGregory Neil Shapiro **		None.
123940266059SGregory Neil Shapiro **
124040266059SGregory Neil Shapiro */
124140266059SGregory Neil Shapiro 
124240266059SGregory Neil Shapiro void
124340266059SGregory Neil Shapiro sm_ldap_close(lmap)
124440266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
124540266059SGregory Neil Shapiro {
124640266059SGregory Neil Shapiro 	if (lmap->ldap_ld == NULL)
124740266059SGregory Neil Shapiro 		return;
124840266059SGregory Neil Shapiro 
124940266059SGregory Neil Shapiro 	if (lmap->ldap_pid == getpid())
125040266059SGregory Neil Shapiro 		ldap_unbind(lmap->ldap_ld);
125140266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
125240266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
125340266059SGregory Neil Shapiro }
125440266059SGregory Neil Shapiro 
125540266059SGregory Neil Shapiro /*
125640266059SGregory Neil Shapiro **  SM_LDAP_SETOPTS -- set LDAP options
125740266059SGregory Neil Shapiro **
125840266059SGregory Neil Shapiro **	Parameters:
125940266059SGregory Neil Shapiro **		ld -- LDAP session handle
126040266059SGregory Neil Shapiro **		lmap -- LDAP map information
126140266059SGregory Neil Shapiro **
126240266059SGregory Neil Shapiro **	Returns:
126340266059SGregory Neil Shapiro **		None.
126440266059SGregory Neil Shapiro **
126540266059SGregory Neil Shapiro */
126640266059SGregory Neil Shapiro 
126740266059SGregory Neil Shapiro void
126840266059SGregory Neil Shapiro sm_ldap_setopts(ld, lmap)
126940266059SGregory Neil Shapiro 	LDAP *ld;
127040266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
127140266059SGregory Neil Shapiro {
127240266059SGregory Neil Shapiro # if USE_LDAP_SET_OPTION
1273605302a5SGregory Neil Shapiro 	if (lmap->ldap_version != 0)
1274605302a5SGregory Neil Shapiro 	{
1275605302a5SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
1276605302a5SGregory Neil Shapiro 				&lmap->ldap_version);
1277605302a5SGregory Neil Shapiro 	}
127840266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
127940266059SGregory Neil Shapiro 	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
128040266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
128140266059SGregory Neil Shapiro 	else
128240266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
128340266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
128440266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
1285959366dcSGregory Neil Shapiro #  ifdef LDAP_OPT_RESTART
1286959366dcSGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1287959366dcSGregory Neil Shapiro #  endif /* LDAP_OPT_RESTART */
128840266059SGregory Neil Shapiro # else /* USE_LDAP_SET_OPTION */
128940266059SGregory Neil Shapiro 	/* From here on in we can use ldap internal timelimits */
129040266059SGregory Neil Shapiro 	ld->ld_deref = lmap->ldap_deref;
129140266059SGregory Neil Shapiro 	ld->ld_options = lmap->ldap_options;
129240266059SGregory Neil Shapiro 	ld->ld_sizelimit = lmap->ldap_sizelimit;
129340266059SGregory Neil Shapiro 	ld->ld_timelimit = lmap->ldap_timelimit;
129440266059SGregory Neil Shapiro # endif /* USE_LDAP_SET_OPTION */
129540266059SGregory Neil Shapiro }
129640266059SGregory Neil Shapiro 
129740266059SGregory Neil Shapiro /*
129840266059SGregory Neil Shapiro **  SM_LDAP_GETERRNO -- get ldap errno value
129940266059SGregory Neil Shapiro **
130040266059SGregory Neil Shapiro **	Parameters:
130140266059SGregory Neil Shapiro **		ld -- LDAP session handle
130240266059SGregory Neil Shapiro **
130340266059SGregory Neil Shapiro **	Returns:
130440266059SGregory Neil Shapiro **		LDAP errno.
130540266059SGregory Neil Shapiro **
130640266059SGregory Neil Shapiro */
130740266059SGregory Neil Shapiro 
130840266059SGregory Neil Shapiro int
130940266059SGregory Neil Shapiro sm_ldap_geterrno(ld)
131040266059SGregory Neil Shapiro 	LDAP *ld;
131140266059SGregory Neil Shapiro {
131240266059SGregory Neil Shapiro 	int err = LDAP_SUCCESS;
131340266059SGregory Neil Shapiro 
131440266059SGregory Neil Shapiro # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
131540266059SGregory Neil Shapiro 	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
131640266059SGregory Neil Shapiro # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
131740266059SGregory Neil Shapiro #  ifdef LDAP_OPT_SIZELIMIT
131840266059SGregory Neil Shapiro 	err = ldap_get_lderrno(ld, NULL, NULL);
131940266059SGregory Neil Shapiro #  else /* LDAP_OPT_SIZELIMIT */
132040266059SGregory Neil Shapiro 	err = ld->ld_errno;
132140266059SGregory Neil Shapiro 
132240266059SGregory Neil Shapiro 	/*
132340266059SGregory Neil Shapiro 	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
132440266059SGregory Neil Shapiro 	**  OpenLDAP 1.X's hack (see above)
132540266059SGregory Neil Shapiro 	*/
132640266059SGregory Neil Shapiro 
132740266059SGregory Neil Shapiro 	ld->ld_errno = LDAP_SUCCESS;
132840266059SGregory Neil Shapiro #  endif /* LDAP_OPT_SIZELIMIT */
132940266059SGregory Neil Shapiro # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
133040266059SGregory Neil Shapiro 	return err;
133140266059SGregory Neil Shapiro }
133240266059SGregory Neil Shapiro # endif /* LDAPMAP */
1333