xref: /freebsd/contrib/sendmail/libsm/ldap.c (revision 5b0945b57059d1cde0831d3afea7ec56c7d79508)
140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 2001-2009 Proofpoint, 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 
10d0cef73dSGregory Neil Shapiro /* some "deprecated" calls are used, e.g., ldap_get_values() */
11d0cef73dSGregory Neil Shapiro #define LDAP_DEPRECATED	1
12d0cef73dSGregory Neil Shapiro 
1340266059SGregory Neil Shapiro #include <sm/gen.h>
144313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: ldap.c,v 1.86 2013-11-22 20:51:43 ca Exp $")
1540266059SGregory Neil Shapiro 
1640266059SGregory Neil Shapiro #if LDAPMAP
1740266059SGregory Neil Shapiro # include <sys/types.h>
1840266059SGregory Neil Shapiro # include <errno.h>
1940266059SGregory Neil Shapiro # include <setjmp.h>
2040266059SGregory Neil Shapiro # include <stdlib.h>
2140266059SGregory Neil Shapiro # include <unistd.h>
2240266059SGregory Neil Shapiro 
2340266059SGregory Neil Shapiro # include <sm/bitops.h>
2440266059SGregory Neil Shapiro # include <sm/clock.h>
2540266059SGregory Neil Shapiro # include <sm/conf.h>
2640266059SGregory Neil Shapiro # include <sm/debug.h>
2740266059SGregory Neil Shapiro # include <sm/errstring.h>
2840266059SGregory Neil Shapiro # include <sm/ldap.h>
2940266059SGregory Neil Shapiro # include <sm/string.h>
30605302a5SGregory Neil Shapiro #  ifdef EX_OK
31605302a5SGregory Neil Shapiro #   undef EX_OK			/* for SVr4.2 SMP */
32*5b0945b5SGregory Neil Shapiro #  endif
3340266059SGregory Neil Shapiro # include <sm/sysexits.h>
3440266059SGregory Neil Shapiro 
3540266059SGregory Neil Shapiro SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
3640266059SGregory Neil Shapiro 	"@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
3740266059SGregory Neil Shapiro 
38b6bacd31SGregory Neil Shapiro static bool	sm_ldap_has_objectclass __P((SM_LDAP_STRUCT *, LDAPMessage *, char *));
39b6bacd31SGregory Neil Shapiro static SM_LDAP_RECURSE_ENTRY *sm_ldap_add_recurse __P((SM_LDAP_RECURSE_LIST **, char *, int, SM_RPOOL_T *));
4040266059SGregory Neil Shapiro 
4140266059SGregory Neil Shapiro /*
4240266059SGregory Neil Shapiro **  SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
4340266059SGregory Neil Shapiro **
4440266059SGregory Neil Shapiro **	Parameters:
4540266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT to clear
4640266059SGregory Neil Shapiro **
4740266059SGregory Neil Shapiro **	Returns:
4840266059SGregory Neil Shapiro **		None.
4940266059SGregory Neil Shapiro **
5040266059SGregory Neil Shapiro */
5140266059SGregory Neil Shapiro 
524e4196cbSGregory Neil Shapiro #if _FFR_LDAP_VERSION
534e4196cbSGregory Neil Shapiro # if defined(LDAP_VERSION_MAX) && _FFR_LDAP_VERSION > LDAP_VERSION_MAX
544e4196cbSGregory Neil Shapiro     ERROR FFR_LDAP_VERSION > _LDAP_VERSION_MAX
55*5b0945b5SGregory Neil Shapiro # endif
564e4196cbSGregory Neil Shapiro # if defined(LDAP_VERSION_MIN) && _FFR_LDAP_VERSION < LDAP_VERSION_MIN
574e4196cbSGregory Neil Shapiro     ERROR FFR_LDAP_VERSION < _LDAP_VERSION_MIN
58*5b0945b5SGregory Neil Shapiro # endif
594e4196cbSGregory Neil Shapiro # define SM_LDAP_VERSION_DEFAULT	_FFR_LDAP_VERSION
604e4196cbSGregory Neil Shapiro #else /* _FFR_LDAP_VERSION */
614e4196cbSGregory Neil Shapiro # define SM_LDAP_VERSION_DEFAULT	0
624e4196cbSGregory Neil Shapiro #endif /* _FFR_LDAP_VERSION */
634e4196cbSGregory Neil Shapiro 
6440266059SGregory Neil Shapiro void
6540266059SGregory Neil Shapiro sm_ldap_clear(lmap)
6640266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
6740266059SGregory Neil Shapiro {
6840266059SGregory Neil Shapiro 	if (lmap == NULL)
6940266059SGregory Neil Shapiro 		return;
7040266059SGregory Neil Shapiro 
71e92d3f3fSGregory Neil Shapiro 	lmap->ldap_host = NULL;
7240266059SGregory Neil Shapiro 	lmap->ldap_port = LDAP_PORT;
73e92d3f3fSGregory Neil Shapiro 	lmap->ldap_uri = NULL;
744e4196cbSGregory Neil Shapiro 	lmap->ldap_version = SM_LDAP_VERSION_DEFAULT;
7540266059SGregory Neil Shapiro 	lmap->ldap_deref = LDAP_DEREF_NEVER;
7640266059SGregory Neil Shapiro 	lmap->ldap_timelimit = LDAP_NO_LIMIT;
7740266059SGregory Neil Shapiro 	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
7840266059SGregory Neil Shapiro # ifdef LDAP_REFERRALS
7940266059SGregory Neil Shapiro 	lmap->ldap_options = LDAP_OPT_REFERRALS;
80*5b0945b5SGregory Neil Shapiro # else
8140266059SGregory Neil Shapiro 	lmap->ldap_options = 0;
82*5b0945b5SGregory Neil Shapiro # endif
8340266059SGregory Neil Shapiro 	lmap->ldap_attrsep = '\0';
8440266059SGregory Neil Shapiro 	lmap->ldap_binddn = NULL;
8540266059SGregory Neil Shapiro 	lmap->ldap_secret = NULL;
8640266059SGregory Neil Shapiro 	lmap->ldap_method = LDAP_AUTH_SIMPLE;
8740266059SGregory Neil Shapiro 	lmap->ldap_base = NULL;
8840266059SGregory Neil Shapiro 	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
8940266059SGregory Neil Shapiro 	lmap->ldap_attrsonly = LDAPMAP_FALSE;
9040266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_sec = 0;
9140266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_usec = 0;
9240266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
9340266059SGregory Neil Shapiro 	lmap->ldap_filter = NULL;
9440266059SGregory Neil Shapiro 	lmap->ldap_attr[0] = NULL;
95605302a5SGregory Neil Shapiro 	lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE;
96605302a5SGregory Neil Shapiro 	lmap->ldap_attr_needobjclass[0] = NULL;
9740266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
9840266059SGregory Neil Shapiro 	lmap->ldap_next = NULL;
9940266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
100d0cef73dSGregory Neil Shapiro 	lmap->ldap_multi_args = false;
10140266059SGregory Neil Shapiro }
10240266059SGregory Neil Shapiro 
103*5b0945b5SGregory Neil Shapiro #  if _FFR_SM_LDAP_DBG && defined(LBER_OPT_LOG_PRINT_FN)
104*5b0945b5SGregory Neil Shapiro static void ldap_debug_cb __P((const char *msg));
105*5b0945b5SGregory Neil Shapiro 
106*5b0945b5SGregory Neil Shapiro static void
107*5b0945b5SGregory Neil Shapiro ldap_debug_cb(msg)
108*5b0945b5SGregory Neil Shapiro 	const char *msg;
109*5b0945b5SGregory Neil Shapiro {
110*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 4))
111*5b0945b5SGregory Neil Shapiro 		sm_dprintf("%s", msg);
112*5b0945b5SGregory Neil Shapiro }
113*5b0945b5SGregory Neil Shapiro #  endif /* _FFR_SM_LDAP_DBG && defined(LBER_OPT_LOG_PRINT_FN) */
114*5b0945b5SGregory Neil Shapiro 
115*5b0945b5SGregory Neil Shapiro 
116*5b0945b5SGregory Neil Shapiro # if LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT)
117*5b0945b5SGregory Neil Shapiro #  define SET_LDAP_TMO(ld, lmap)					\
118*5b0945b5SGregory Neil Shapiro 	do								\
119*5b0945b5SGregory Neil Shapiro 	{								\
120*5b0945b5SGregory Neil Shapiro 		if (lmap->ldap_networktmo > 0)				\
121*5b0945b5SGregory Neil Shapiro 		{							\
122*5b0945b5SGregory Neil Shapiro 			struct timeval tmo;				\
123*5b0945b5SGregory Neil Shapiro 									\
124*5b0945b5SGregory Neil Shapiro 			if (sm_debug_active(&SmLDAPTrace, 9))		\
125*5b0945b5SGregory Neil Shapiro 				sm_dprintf("ldap_networktmo=%d\n",	\
126*5b0945b5SGregory Neil Shapiro 					lmap->ldap_networktmo);		\
127*5b0945b5SGregory Neil Shapiro 			tmo.tv_sec = lmap->ldap_networktmo;		\
128*5b0945b5SGregory Neil Shapiro 			tmo.tv_usec = 0;				\
129*5b0945b5SGregory Neil Shapiro 			ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tmo); \
130*5b0945b5SGregory Neil Shapiro 		}	\
131*5b0945b5SGregory Neil Shapiro 	} while (0)
132*5b0945b5SGregory Neil Shapiro # else /* LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT) */
133*5b0945b5SGregory Neil Shapiro #  define SET_LDAP_TMO(ld, lmap)
134*5b0945b5SGregory Neil Shapiro # endif /* LDAP_NETWORK_TIMEOUT && defined(LDAP_OPT_NETWORK_TIMEOUT) */
135*5b0945b5SGregory Neil Shapiro 
136*5b0945b5SGregory Neil Shapiro /*
137*5b0945b5SGregory Neil Shapiro **  SM_LDAP_SETOPTSG -- set some (global) LDAP options
138*5b0945b5SGregory Neil Shapiro **
139*5b0945b5SGregory Neil Shapiro **	Parameters:
140*5b0945b5SGregory Neil Shapiro **		lmap -- LDAP map information
141*5b0945b5SGregory Neil Shapiro **
142*5b0945b5SGregory Neil Shapiro **	Returns:
143*5b0945b5SGregory Neil Shapiro **		None.
144*5b0945b5SGregory Neil Shapiro **
145*5b0945b5SGregory Neil Shapiro */
146*5b0945b5SGregory Neil Shapiro 
147*5b0945b5SGregory Neil Shapiro # if _FFR_SM_LDAP_DBG
148*5b0945b5SGregory Neil Shapiro static bool dbg_init = false;
149*5b0945b5SGregory Neil Shapiro # endif
150*5b0945b5SGregory Neil Shapiro # if SM_CONF_LDAP_INITIALIZE
151*5b0945b5SGregory Neil Shapiro static void sm_ldap_setoptsg __P((SM_LDAP_STRUCT *lmap));
152*5b0945b5SGregory Neil Shapiro static void
153*5b0945b5SGregory Neil Shapiro sm_ldap_setoptsg(lmap)
154*5b0945b5SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
155*5b0945b5SGregory Neil Shapiro {
156*5b0945b5SGregory Neil Shapiro #  if USE_LDAP_SET_OPTION
157*5b0945b5SGregory Neil Shapiro 
158*5b0945b5SGregory Neil Shapiro 	SET_LDAP_TMO(NULL, lmap);
159*5b0945b5SGregory Neil Shapiro 
160*5b0945b5SGregory Neil Shapiro #   if _FFR_SM_LDAP_DBG
161*5b0945b5SGregory Neil Shapiro 	if (!dbg_init && sm_debug_active(&SmLDAPTrace, 1) &&
162*5b0945b5SGregory Neil Shapiro 	    lmap->ldap_debug != 0)
163*5b0945b5SGregory Neil Shapiro 	{
164*5b0945b5SGregory Neil Shapiro 		int r;
165*5b0945b5SGregory Neil Shapiro #    if defined(LBER_OPT_LOG_PRINT_FN)
166*5b0945b5SGregory Neil Shapiro 		r = ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN, ldap_debug_cb);
167*5b0945b5SGregory Neil Shapiro #    endif
168*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
169*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_debug0=%d\n", lmap->ldap_debug);
170*5b0945b5SGregory Neil Shapiro 		r = ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
171*5b0945b5SGregory Neil Shapiro 				&(lmap->ldap_debug));
172*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9) && r != LDAP_OPT_SUCCESS)
173*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ber_set_option=%d\n", r);
174*5b0945b5SGregory Neil Shapiro 		r = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
175*5b0945b5SGregory Neil Shapiro 				&(lmap->ldap_debug));
176*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9) && r != LDAP_OPT_SUCCESS)
177*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_set_option=%d\n", r);
178*5b0945b5SGregory Neil Shapiro 		dbg_init = true;
179*5b0945b5SGregory Neil Shapiro 	}
180*5b0945b5SGregory Neil Shapiro #   endif /* _FFR_SM_LDAP_DBG */
181*5b0945b5SGregory Neil Shapiro #  endif /* USE_LDAP_SET_OPTION */
182*5b0945b5SGregory Neil Shapiro }
183*5b0945b5SGregory Neil Shapiro # endif /* SM_CONF_LDAP_INITIALIZE */
184*5b0945b5SGregory Neil Shapiro 
185*5b0945b5SGregory Neil Shapiro /*
186*5b0945b5SGregory Neil Shapiro **  SM_LDAP_SETOPTS -- set LDAP options
187*5b0945b5SGregory Neil Shapiro **
188*5b0945b5SGregory Neil Shapiro **	Parameters:
189*5b0945b5SGregory Neil Shapiro **		ld -- LDAP session handle
190*5b0945b5SGregory Neil Shapiro **		lmap -- LDAP map information
191*5b0945b5SGregory Neil Shapiro **
192*5b0945b5SGregory Neil Shapiro **	Returns:
193*5b0945b5SGregory Neil Shapiro **		None.
194*5b0945b5SGregory Neil Shapiro **
195*5b0945b5SGregory Neil Shapiro */
196*5b0945b5SGregory Neil Shapiro 
197*5b0945b5SGregory Neil Shapiro void
198*5b0945b5SGregory Neil Shapiro sm_ldap_setopts(ld, lmap)
199*5b0945b5SGregory Neil Shapiro 	LDAP *ld;
200*5b0945b5SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
201*5b0945b5SGregory Neil Shapiro {
202*5b0945b5SGregory Neil Shapiro # if USE_LDAP_SET_OPTION
203*5b0945b5SGregory Neil Shapiro 	if (lmap->ldap_version != 0)
204*5b0945b5SGregory Neil Shapiro 	{
205*5b0945b5SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
206*5b0945b5SGregory Neil Shapiro 				&lmap->ldap_version);
207*5b0945b5SGregory Neil Shapiro 	}
208*5b0945b5SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
209*5b0945b5SGregory Neil Shapiro 	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
210*5b0945b5SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
211*5b0945b5SGregory Neil Shapiro 	else
212*5b0945b5SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
213*5b0945b5SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
214*5b0945b5SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
215*5b0945b5SGregory Neil Shapiro 	SET_LDAP_TMO(ld, lmap);
216*5b0945b5SGregory Neil Shapiro #  if _FFR_SM_LDAP_DBG
217*5b0945b5SGregory Neil Shapiro 	if ((!dbg_init || ld != NULL) && sm_debug_active(&SmLDAPTrace, 1)
218*5b0945b5SGregory Neil Shapiro 	    && lmap->ldap_debug > 0)
219*5b0945b5SGregory Neil Shapiro 	{
220*5b0945b5SGregory Neil Shapiro 		int r;
221*5b0945b5SGregory Neil Shapiro 
222*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
223*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_debug=%d, dbg_init=%d\n",
224*5b0945b5SGregory Neil Shapiro 				lmap->ldap_debug, dbg_init);
225*5b0945b5SGregory Neil Shapiro 		r = ldap_set_option(ld, LDAP_OPT_DEBUG_LEVEL,
226*5b0945b5SGregory Neil Shapiro 				&(lmap->ldap_debug));
227*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9) && r != LDAP_OPT_SUCCESS)
228*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_set_option=%d\n", r);
229*5b0945b5SGregory Neil Shapiro 	}
230*5b0945b5SGregory Neil Shapiro #  endif /* _FFR_SM_LDAP_DBG */
231*5b0945b5SGregory Neil Shapiro #  ifdef LDAP_OPT_RESTART
232*5b0945b5SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
233*5b0945b5SGregory Neil Shapiro #  endif
234*5b0945b5SGregory Neil Shapiro 
235*5b0945b5SGregory Neil Shapiro # else /* USE_LDAP_SET_OPTION */
236*5b0945b5SGregory Neil Shapiro 	/* From here on in we can use ldap internal timelimits */
237*5b0945b5SGregory Neil Shapiro 	ld->ld_deref = lmap->ldap_deref;
238*5b0945b5SGregory Neil Shapiro 	ld->ld_options = lmap->ldap_options;
239*5b0945b5SGregory Neil Shapiro 	ld->ld_sizelimit = lmap->ldap_sizelimit;
240*5b0945b5SGregory Neil Shapiro 	ld->ld_timelimit = lmap->ldap_timelimit;
241*5b0945b5SGregory Neil Shapiro # endif /* USE_LDAP_SET_OPTION */
242*5b0945b5SGregory Neil Shapiro }
243*5b0945b5SGregory Neil Shapiro 
24440266059SGregory Neil Shapiro /*
24540266059SGregory Neil Shapiro **  SM_LDAP_START -- actually connect to an LDAP server
24640266059SGregory Neil Shapiro **
24740266059SGregory Neil Shapiro **	Parameters:
24840266059SGregory Neil Shapiro **		name -- name of map for debug output.
24940266059SGregory Neil Shapiro **		lmap -- the LDAP map being opened.
25040266059SGregory Neil Shapiro **
25140266059SGregory Neil Shapiro **	Returns:
25240266059SGregory Neil Shapiro **		true if connection is successful, false otherwise.
25340266059SGregory Neil Shapiro **
25440266059SGregory Neil Shapiro **	Side Effects:
25540266059SGregory Neil Shapiro **		Populates lmap->ldap_ld.
25640266059SGregory Neil Shapiro */
25740266059SGregory Neil Shapiro 
258*5b0945b5SGregory Neil Shapiro # if !USE_LDAP_INIT || !LDAP_NETWORK_TIMEOUT
25940266059SGregory Neil Shapiro static jmp_buf	LDAPTimeout;
260*5b0945b5SGregory Neil Shapiro static void	ldaptimeout __P((int));
26140266059SGregory Neil Shapiro 
262*5b0945b5SGregory Neil Shapiro /* ARGSUSED */
263*5b0945b5SGregory Neil Shapiro static void
264*5b0945b5SGregory Neil Shapiro ldaptimeout(unused)
265*5b0945b5SGregory Neil Shapiro 	int unused;
266*5b0945b5SGregory Neil Shapiro {
267*5b0945b5SGregory Neil Shapiro 	/*
268*5b0945b5SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
269*5b0945b5SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
270*5b0945b5SGregory Neil Shapiro 	**	DOING.
271*5b0945b5SGregory Neil Shapiro 	*/
272*5b0945b5SGregory Neil Shapiro 
273*5b0945b5SGregory Neil Shapiro 	errno = ETIMEDOUT;
274*5b0945b5SGregory Neil Shapiro 	longjmp(LDAPTimeout, 1);
275*5b0945b5SGregory Neil Shapiro }
276*5b0945b5SGregory Neil Shapiro 
277*5b0945b5SGregory Neil Shapiro 
278*5b0945b5SGregory Neil Shapiro #define SM_LDAP_SETTIMEOUT(to, where)					\
27940266059SGregory Neil Shapiro do									\
28040266059SGregory Neil Shapiro {									\
28140266059SGregory Neil Shapiro 	if (to != 0)							\
28240266059SGregory Neil Shapiro 	{								\
28340266059SGregory Neil Shapiro 		if (setjmp(LDAPTimeout) != 0)				\
28440266059SGregory Neil Shapiro 		{							\
285*5b0945b5SGregory Neil Shapiro 			if (sm_debug_active(&SmLDAPTrace, 9))		\
286*5b0945b5SGregory Neil Shapiro 				sm_dprintf("ldap_settimeout(%s)=triggered\n",\
287*5b0945b5SGregory Neil Shapiro 					where);				\
28840266059SGregory Neil Shapiro 			errno = ETIMEDOUT;				\
28940266059SGregory Neil Shapiro 			return false;					\
29040266059SGregory Neil Shapiro 		}							\
29140266059SGregory Neil Shapiro 		ev = sm_setevent(to, ldaptimeout, 0);			\
29240266059SGregory Neil Shapiro 	}								\
29340266059SGregory Neil Shapiro } while (0)
29440266059SGregory Neil Shapiro 
29540266059SGregory Neil Shapiro #define SM_LDAP_CLEARTIMEOUT()						\
29640266059SGregory Neil Shapiro do									\
29740266059SGregory Neil Shapiro {									\
29840266059SGregory Neil Shapiro 	if (ev != NULL)							\
29940266059SGregory Neil Shapiro 		sm_clrevent(ev);					\
30040266059SGregory Neil Shapiro } while (0)
301*5b0945b5SGregory Neil Shapiro #endif /* !USE_LDAP_INIT || !LDAP_NETWORK_TIMEOUT */
30240266059SGregory Neil Shapiro 
30340266059SGregory Neil Shapiro bool
30440266059SGregory Neil Shapiro sm_ldap_start(name, lmap)
30540266059SGregory Neil Shapiro 	char *name;
30640266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
30740266059SGregory Neil Shapiro {
308b6bacd31SGregory Neil Shapiro 	int save_errno = 0;
309e92d3f3fSGregory Neil Shapiro 	char *id;
310*5b0945b5SGregory Neil Shapiro # if !USE_LDAP_INIT || !LDAP_NETWORK_TIMEOUT
31140266059SGregory Neil Shapiro 	SM_EVENT *ev = NULL;
312*5b0945b5SGregory Neil Shapiro # endif
313e92d3f3fSGregory Neil Shapiro 	LDAP *ld = NULL;
314*5b0945b5SGregory Neil Shapiro 	struct timeval tmo;
315*5b0945b5SGregory Neil Shapiro 	int msgid, err, r;
31640266059SGregory Neil Shapiro 
31740266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 2))
31840266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
31940266059SGregory Neil Shapiro 
320e92d3f3fSGregory Neil Shapiro 	if (lmap->ldap_host != NULL)
321e92d3f3fSGregory Neil Shapiro 		id = lmap->ldap_host;
322e92d3f3fSGregory Neil Shapiro 	else if (lmap->ldap_uri != NULL)
323e92d3f3fSGregory Neil Shapiro 		id = lmap->ldap_uri;
324605302a5SGregory Neil Shapiro 	else
325e92d3f3fSGregory Neil Shapiro 		id = "localhost";
326e92d3f3fSGregory Neil Shapiro 
327e92d3f3fSGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
328e92d3f3fSGregory Neil Shapiro 	{
329e92d3f3fSGregory Neil Shapiro 		/* Don't print a port number for LDAP URIs */
330e92d3f3fSGregory Neil Shapiro 		if (lmap->ldap_uri != NULL)
331e92d3f3fSGregory Neil Shapiro 			sm_dprintf("ldapmap_start(%s)\n", id);
332e92d3f3fSGregory Neil Shapiro 		else
333e92d3f3fSGregory Neil Shapiro 			sm_dprintf("ldapmap_start(%s, %d)\n", id,
334e92d3f3fSGregory Neil Shapiro 				   lmap->ldap_port);
335e92d3f3fSGregory Neil Shapiro 	}
336e92d3f3fSGregory Neil Shapiro 
337e92d3f3fSGregory Neil Shapiro 	if (lmap->ldap_uri != NULL)
338e92d3f3fSGregory Neil Shapiro 	{
339e92d3f3fSGregory Neil Shapiro #if SM_CONF_LDAP_INITIALIZE
340*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
341*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_initialize(%s)\n", lmap->ldap_uri);
342e92d3f3fSGregory Neil Shapiro 		/* LDAP server supports URIs so use them directly */
343e92d3f3fSGregory Neil Shapiro 		save_errno = ldap_initialize(&ld, lmap->ldap_uri);
344*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
345*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_initialize(%s)=%d, ld=%p\n", lmap->ldap_uri, save_errno, ld);
346*5b0945b5SGregory Neil Shapiro 		sm_ldap_setoptsg(lmap);
347*5b0945b5SGregory Neil Shapiro 
348e92d3f3fSGregory Neil Shapiro #else /* SM_CONF_LDAP_INITIALIZE */
349e92d3f3fSGregory Neil Shapiro 		LDAPURLDesc *ludp = NULL;
350e92d3f3fSGregory Neil Shapiro 
351e92d3f3fSGregory Neil Shapiro 		/* Blast apart URL and use the ldap_init/ldap_open below */
352e92d3f3fSGregory Neil Shapiro 		err = ldap_url_parse(lmap->ldap_uri, &ludp);
353e92d3f3fSGregory Neil Shapiro 		if (err != 0)
354e92d3f3fSGregory Neil Shapiro 		{
355e92d3f3fSGregory Neil Shapiro 			errno = err + E_LDAPURLBASE;
356e92d3f3fSGregory Neil Shapiro 			return false;
357e92d3f3fSGregory Neil Shapiro 		}
358e92d3f3fSGregory Neil Shapiro 		lmap->ldap_host = sm_strdup_x(ludp->lud_host);
359e92d3f3fSGregory Neil Shapiro 		if (lmap->ldap_host == NULL)
360e92d3f3fSGregory Neil Shapiro 		{
361e92d3f3fSGregory Neil Shapiro 			save_errno = errno;
362e92d3f3fSGregory Neil Shapiro 			ldap_free_urldesc(ludp);
363e92d3f3fSGregory Neil Shapiro 			errno = save_errno;
364e92d3f3fSGregory Neil Shapiro 			return false;
365e92d3f3fSGregory Neil Shapiro 		}
366e92d3f3fSGregory Neil Shapiro 		lmap->ldap_port = ludp->lud_port;
367e92d3f3fSGregory Neil Shapiro 		ldap_free_urldesc(ludp);
368e92d3f3fSGregory Neil Shapiro #endif /* SM_CONF_LDAP_INITIALIZE */
369e92d3f3fSGregory Neil Shapiro 	}
370e92d3f3fSGregory Neil Shapiro 
371e92d3f3fSGregory Neil Shapiro 	if (ld == NULL)
372e92d3f3fSGregory Neil Shapiro 	{
373e92d3f3fSGregory Neil Shapiro # if USE_LDAP_INIT
374*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
375*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_init(%s, %d)\n", lmap->ldap_host, lmap->ldap_port);
376e92d3f3fSGregory Neil Shapiro 		ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
37740266059SGregory Neil Shapiro 		save_errno = errno;
378*5b0945b5SGregory Neil Shapiro 
37940266059SGregory Neil Shapiro # else /* USE_LDAP_INIT */
38040266059SGregory Neil Shapiro 		/*
38140266059SGregory Neil Shapiro 		**  If using ldap_open(), the actual connection to the server
38240266059SGregory Neil Shapiro 		**  happens now so we need the timeout here.  For ldap_init(),
38340266059SGregory Neil Shapiro 		**  the connection happens at bind time.
38440266059SGregory Neil Shapiro 		*/
38540266059SGregory Neil Shapiro 
386*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 9))
387*5b0945b5SGregory Neil Shapiro 			sm_dprintf("ldap_open(%s, %d)\n", lmap->ldap_host, lmap->ldap_port);
388*5b0945b5SGregory Neil Shapiro 
389*5b0945b5SGregory Neil Shapiro 		SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec, "ldap_open");
390e92d3f3fSGregory Neil Shapiro 		ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
39140266059SGregory Neil Shapiro 		save_errno = errno;
39240266059SGregory Neil Shapiro 
39340266059SGregory Neil Shapiro 		/* clear the event if it has not sprung */
39440266059SGregory Neil Shapiro 		SM_LDAP_CLEARTIMEOUT();
39540266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
396e92d3f3fSGregory Neil Shapiro 	}
39740266059SGregory Neil Shapiro 
39840266059SGregory Neil Shapiro 	errno = save_errno;
39940266059SGregory Neil Shapiro 	if (ld == NULL)
400*5b0945b5SGregory Neil Shapiro 	{
401*5b0945b5SGregory Neil Shapiro 		if (sm_debug_active(&SmLDAPTrace, 7))
402*5b0945b5SGregory Neil Shapiro 			sm_dprintf("FAIL: ldap_open(%s, %d)=%d\n", lmap->ldap_host, lmap->ldap_port, save_errno);
40340266059SGregory Neil Shapiro 		return false;
404*5b0945b5SGregory Neil Shapiro 	}
40540266059SGregory Neil Shapiro 
40640266059SGregory Neil Shapiro 	sm_ldap_setopts(ld, lmap);
407*5b0945b5SGregory Neil Shapiro # if USE_LDAP_INIT && !LDAP_NETWORK_TIMEOUT
40840266059SGregory Neil Shapiro 	/*
40940266059SGregory Neil Shapiro 	**  If using ldap_init(), the actual connection to the server
41040266059SGregory Neil Shapiro 	**  happens at ldap_bind_s() so we need the timeout here.
41140266059SGregory Neil Shapiro 	*/
41240266059SGregory Neil Shapiro 
413*5b0945b5SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec, "ldap_bind");
414*5b0945b5SGregory Neil Shapiro # endif /* USE_LDAP_INIT && !LDAP_NETWORK_TIMEOUT */
41540266059SGregory Neil Shapiro 
41640266059SGregory Neil Shapiro # ifdef LDAP_AUTH_KRBV4
41740266059SGregory Neil Shapiro 	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
41840266059SGregory Neil Shapiro 	    lmap->ldap_secret != NULL)
41940266059SGregory Neil Shapiro 	{
42040266059SGregory Neil Shapiro 		/*
42140266059SGregory Neil Shapiro 		**  Need to put ticket in environment here instead of
42240266059SGregory Neil Shapiro 		**  during parseargs as there may be different tickets
42340266059SGregory Neil Shapiro 		**  for different LDAP connections.
42440266059SGregory Neil Shapiro 		*/
42540266059SGregory Neil Shapiro 
42640266059SGregory Neil Shapiro 		(void) putenv(lmap->ldap_secret);
42740266059SGregory Neil Shapiro 	}
42840266059SGregory Neil Shapiro # endif /* LDAP_AUTH_KRBV4 */
42940266059SGregory Neil Shapiro 
430*5b0945b5SGregory Neil Shapiro # if LDAP_NETWORK_TIMEOUT
431*5b0945b5SGregory Neil Shapiro 	tmo.tv_sec = lmap->ldap_networktmo;
432*5b0945b5SGregory Neil Shapiro # else
433*5b0945b5SGregory Neil Shapiro 	tmo.tv_sec = lmap->ldap_timeout.tv_sec;
434*5b0945b5SGregory Neil Shapiro # endif
435*5b0945b5SGregory Neil Shapiro 	tmo.tv_usec = 0;
43640266059SGregory Neil Shapiro 
437*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
438*5b0945b5SGregory Neil Shapiro 		sm_dprintf("ldap_bind(%s)\n", lmap->ldap_uri);
439*5b0945b5SGregory Neil Shapiro 	errno = 0;
440*5b0945b5SGregory Neil Shapiro 	msgid = ldap_bind(ld, lmap->ldap_binddn, lmap->ldap_secret,
441*5b0945b5SGregory Neil Shapiro 			lmap->ldap_method);
442*5b0945b5SGregory Neil Shapiro 	save_errno = errno;
443*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
444*5b0945b5SGregory Neil Shapiro 		sm_dprintf("ldap_bind(%s)=%d, errno=%d, tmo=%ld\n",
445*5b0945b5SGregory Neil Shapiro 			lmap->ldap_uri, msgid, save_errno,
446*5b0945b5SGregory Neil Shapiro 			(long) tmo.tv_sec);
447*5b0945b5SGregory Neil Shapiro 	if (-1 == msgid)
448*5b0945b5SGregory Neil Shapiro 	{
449*5b0945b5SGregory Neil Shapiro 		r = -1;
450*5b0945b5SGregory Neil Shapiro 		goto fail;
451*5b0945b5SGregory Neil Shapiro 	}
452*5b0945b5SGregory Neil Shapiro 
453*5b0945b5SGregory Neil Shapiro 	errno = 0;
454*5b0945b5SGregory Neil Shapiro 	r = ldap_result(ld, msgid, LDAP_MSG_ALL,
455*5b0945b5SGregory Neil Shapiro 			tmo.tv_sec == 0 ? NULL : &(tmo), &(lmap->ldap_res));
456*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
457*5b0945b5SGregory Neil Shapiro 		sm_dprintf("ldap_result(%s)=%d, errno=%d\n", lmap->ldap_uri, r, errno);
458*5b0945b5SGregory Neil Shapiro 	if (-1 == r)
459*5b0945b5SGregory Neil Shapiro 		goto fail;
460*5b0945b5SGregory Neil Shapiro 	if (0 == r)
461*5b0945b5SGregory Neil Shapiro 	{
462*5b0945b5SGregory Neil Shapiro 		save_errno = ETIMEDOUT;
463*5b0945b5SGregory Neil Shapiro 		r = -1;
464*5b0945b5SGregory Neil Shapiro 		goto fail;
465*5b0945b5SGregory Neil Shapiro 	}
466*5b0945b5SGregory Neil Shapiro 	r = ldap_parse_result(ld, lmap->ldap_res, &err, NULL, NULL, NULL, NULL,
467*5b0945b5SGregory Neil Shapiro 				1);
468*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
469*5b0945b5SGregory Neil Shapiro 		sm_dprintf("ldap_parse_result(%s)=%d, err=%d\n", lmap->ldap_uri, r, err);
470*5b0945b5SGregory Neil Shapiro 	if (r != LDAP_SUCCESS)
471*5b0945b5SGregory Neil Shapiro 		goto fail;
472*5b0945b5SGregory Neil Shapiro 	if (err != LDAP_SUCCESS)
473*5b0945b5SGregory Neil Shapiro 	{
474*5b0945b5SGregory Neil Shapiro 		r = -1;
475*5b0945b5SGregory Neil Shapiro 		goto fail;
476*5b0945b5SGregory Neil Shapiro 	}
477*5b0945b5SGregory Neil Shapiro 
478*5b0945b5SGregory Neil Shapiro # if USE_LDAP_INIT && !LDAP_NETWORK_TIMEOUT
47940266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
48040266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
481*5b0945b5SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
482*5b0945b5SGregory Neil Shapiro 		sm_dprintf("ldap_cleartimeout(%s)\n", lmap->ldap_uri);
483*5b0945b5SGregory Neil Shapiro # endif /* USE_LDAP_INIT && !LDAP_NETWORK_TIMEOUT */
48440266059SGregory Neil Shapiro 
485*5b0945b5SGregory Neil Shapiro 	if (r != LDAP_SUCCESS)
48640266059SGregory Neil Shapiro 	{
487*5b0945b5SGregory Neil Shapiro   fail:
488*5b0945b5SGregory Neil Shapiro 		if (-1 == r)
489*5b0945b5SGregory Neil Shapiro 			errno = save_errno;
490*5b0945b5SGregory Neil Shapiro 		else
491*5b0945b5SGregory Neil Shapiro 			errno = r + E_LDAPBASE;
49240266059SGregory Neil Shapiro 		return false;
49340266059SGregory Neil Shapiro 	}
49440266059SGregory Neil Shapiro 
49540266059SGregory Neil Shapiro 	/* Save PID to make sure only this PID closes the LDAP connection */
49640266059SGregory Neil Shapiro 	lmap->ldap_pid = getpid();
49740266059SGregory Neil Shapiro 	lmap->ldap_ld = ld;
49840266059SGregory Neil Shapiro 	return true;
49940266059SGregory Neil Shapiro }
50040266059SGregory Neil Shapiro 
50140266059SGregory Neil Shapiro /*
502d0cef73dSGregory Neil Shapiro **  SM_LDAP_SEARCH_M -- initiate multi-key LDAP search
50340266059SGregory Neil Shapiro **
50440266059SGregory Neil Shapiro **	Initiate an LDAP search, return the msgid.
50540266059SGregory Neil Shapiro **	The calling function must collect the results.
50640266059SGregory Neil Shapiro **
50740266059SGregory Neil Shapiro **	Parameters:
50840266059SGregory Neil Shapiro **		lmap -- LDAP map information
509d0cef73dSGregory Neil Shapiro **		argv -- key vector of substitutions in LDAP filter
510d0cef73dSGregory Neil Shapiro **			NOTE: argv must have SM_LDAP_ARGS elements to prevent
511d0cef73dSGregory Neil Shapiro **			      out of bound array references
51240266059SGregory Neil Shapiro **
51340266059SGregory Neil Shapiro **	Returns:
514d0cef73dSGregory Neil Shapiro **		<0 on failure (SM_LDAP_ERR*), msgid on success
51540266059SGregory Neil Shapiro **
51640266059SGregory Neil Shapiro */
51740266059SGregory Neil Shapiro 
51840266059SGregory Neil Shapiro int
519d0cef73dSGregory Neil Shapiro sm_ldap_search_m(lmap, argv)
52040266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
521d0cef73dSGregory Neil Shapiro 	char **argv;
52240266059SGregory Neil Shapiro {
52340266059SGregory Neil Shapiro 	int msgid;
52440266059SGregory Neil Shapiro 	char *fp, *p, *q;
52540266059SGregory Neil Shapiro 	char filter[LDAPMAP_MAX_FILTER + 1];
52640266059SGregory Neil Shapiro 
527d0cef73dSGregory Neil Shapiro 	SM_REQUIRE(lmap != NULL);
528d0cef73dSGregory Neil Shapiro 	SM_REQUIRE(argv != NULL);
529d0cef73dSGregory Neil Shapiro 	SM_REQUIRE(argv[0] != NULL);
530d0cef73dSGregory Neil Shapiro 
53140266059SGregory Neil Shapiro 	memset(filter, '\0', sizeof filter);
53240266059SGregory Neil Shapiro 	fp = filter;
53340266059SGregory Neil Shapiro 	p = lmap->ldap_filter;
53440266059SGregory Neil Shapiro 	while ((q = strchr(p, '%')) != NULL)
53540266059SGregory Neil Shapiro 	{
536d0cef73dSGregory Neil Shapiro 		char *key;
537d0cef73dSGregory Neil Shapiro 
538d0cef73dSGregory Neil Shapiro 		if (lmap->ldap_multi_args)
539d0cef73dSGregory Neil Shapiro 		{
540d0cef73dSGregory Neil Shapiro #if SM_LDAP_ARGS < 10
541d0cef73dSGregory Neil Shapiro # ERROR _SM_LDAP_ARGS must be 10
542d0cef73dSGregory Neil Shapiro #endif /* SM_LDAP_ARGS < 10 */
543d0cef73dSGregory Neil Shapiro 			if (q[1] == 's')
544d0cef73dSGregory Neil Shapiro 				key = argv[0];
545d0cef73dSGregory Neil Shapiro 			else if (q[1] >= '0' && q[1] <= '9')
546d0cef73dSGregory Neil Shapiro 			{
547d0cef73dSGregory Neil Shapiro 				key = argv[q[1] - '0'];
548d0cef73dSGregory Neil Shapiro 				if (key == NULL)
549d0cef73dSGregory Neil Shapiro 				{
550d0cef73dSGregory Neil Shapiro # if SM_LDAP_ERROR_ON_MISSING_ARGS
551d0cef73dSGregory Neil Shapiro 					return SM_LDAP_ERR_ARG_MISS;
552d0cef73dSGregory Neil Shapiro # else /* SM_LDAP_ERROR_ON_MISSING_ARGS */
553d0cef73dSGregory Neil Shapiro 					key = "";
554d0cef73dSGregory Neil Shapiro # endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
555d0cef73dSGregory Neil Shapiro 				}
556d0cef73dSGregory Neil Shapiro 			}
557d0cef73dSGregory Neil Shapiro 			else
558d0cef73dSGregory Neil Shapiro 				key = NULL;
559d0cef73dSGregory Neil Shapiro 		}
560d0cef73dSGregory Neil Shapiro 		else
561d0cef73dSGregory Neil Shapiro 			key = argv[0];
562d0cef73dSGregory Neil Shapiro 
56340266059SGregory Neil Shapiro 		if (q[1] == 's')
56440266059SGregory Neil Shapiro 		{
56540266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
56640266059SGregory Neil Shapiro 					   "%.*s%s", (int) (q - p), p, key);
56740266059SGregory Neil Shapiro 			fp += strlen(fp);
56840266059SGregory Neil Shapiro 			p = q + 2;
56940266059SGregory Neil Shapiro 		}
570d0cef73dSGregory Neil Shapiro 		else if (q[1] == '0' ||
571d0cef73dSGregory Neil Shapiro 			 (lmap->ldap_multi_args && q[1] >= '0' && q[1] <= '9'))
57240266059SGregory Neil Shapiro 		{
57340266059SGregory Neil Shapiro 			char *k = key;
57440266059SGregory Neil Shapiro 
57540266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
57640266059SGregory Neil Shapiro 					   "%.*s", (int) (q - p), p);
57740266059SGregory Neil Shapiro 			fp += strlen(fp);
57840266059SGregory Neil Shapiro 			p = q + 2;
57940266059SGregory Neil Shapiro 
58040266059SGregory Neil Shapiro 			/* Properly escape LDAP special characters */
58140266059SGregory Neil Shapiro 			while (SPACELEFT(filter, fp) > 0 &&
58240266059SGregory Neil Shapiro 			       *k != '\0')
58340266059SGregory Neil Shapiro 			{
58440266059SGregory Neil Shapiro 				if (*k == '*' || *k == '(' ||
58540266059SGregory Neil Shapiro 				    *k == ')' || *k == '\\')
58640266059SGregory Neil Shapiro 				{
58740266059SGregory Neil Shapiro 					(void) sm_strlcat(fp,
58840266059SGregory Neil Shapiro 						       (*k == '*' ? "\\2A" :
58940266059SGregory Neil Shapiro 							(*k == '(' ? "\\28" :
59040266059SGregory Neil Shapiro 							 (*k == ')' ? "\\29" :
59140266059SGregory Neil Shapiro 							  (*k == '\\' ? "\\5C" :
59240266059SGregory Neil Shapiro 							   "\00")))),
59340266059SGregory Neil Shapiro 						SPACELEFT(filter, fp));
59440266059SGregory Neil Shapiro 					fp += strlen(fp);
59540266059SGregory Neil Shapiro 					k++;
59640266059SGregory Neil Shapiro 				}
59740266059SGregory Neil Shapiro 				else
59840266059SGregory Neil Shapiro 					*fp++ = *k++;
59940266059SGregory Neil Shapiro 			}
60040266059SGregory Neil Shapiro 		}
60140266059SGregory Neil Shapiro 		else
60240266059SGregory Neil Shapiro 		{
60340266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
60440266059SGregory Neil Shapiro 				"%.*s", (int) (q - p + 1), p);
60540266059SGregory Neil Shapiro 			p = q + (q[1] == '%' ? 2 : 1);
60640266059SGregory Neil Shapiro 			fp += strlen(fp);
60740266059SGregory Neil Shapiro 		}
60840266059SGregory Neil Shapiro 	}
60940266059SGregory Neil Shapiro 	(void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
61040266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 20))
61140266059SGregory Neil Shapiro 		sm_dprintf("ldap search filter=%s\n", filter);
61240266059SGregory Neil Shapiro 
61340266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
614605302a5SGregory Neil Shapiro 	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base,
615605302a5SGregory Neil Shapiro 			    lmap->ldap_scope, filter,
61640266059SGregory Neil Shapiro 			    (lmap->ldap_attr[0] == NULL ? NULL :
61740266059SGregory Neil Shapiro 			     lmap->ldap_attr),
61840266059SGregory Neil Shapiro 			    lmap->ldap_attrsonly);
61940266059SGregory Neil Shapiro 	return msgid;
62040266059SGregory Neil Shapiro }
62140266059SGregory Neil Shapiro 
62240266059SGregory Neil Shapiro /*
623d0cef73dSGregory Neil Shapiro **  SM_LDAP_SEARCH -- initiate LDAP search
624d0cef73dSGregory Neil Shapiro **
625d0cef73dSGregory Neil Shapiro **	Initiate an LDAP search, return the msgid.
626d0cef73dSGregory Neil Shapiro **	The calling function must collect the results.
627d0cef73dSGregory Neil Shapiro **	Note this is just a wrapper into sm_ldap_search_m()
628d0cef73dSGregory Neil Shapiro **
629d0cef73dSGregory Neil Shapiro **	Parameters:
630d0cef73dSGregory Neil Shapiro **		lmap -- LDAP map information
631d0cef73dSGregory Neil Shapiro **		key -- key to substitute in LDAP filter
632d0cef73dSGregory Neil Shapiro **
633d0cef73dSGregory Neil Shapiro **	Returns:
634d0cef73dSGregory Neil Shapiro **		<0 on failure, msgid on success
635d0cef73dSGregory Neil Shapiro **
636d0cef73dSGregory Neil Shapiro */
637d0cef73dSGregory Neil Shapiro 
638d0cef73dSGregory Neil Shapiro int
639d0cef73dSGregory Neil Shapiro sm_ldap_search(lmap, key)
640d0cef73dSGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
641d0cef73dSGregory Neil Shapiro 	char *key;
642d0cef73dSGregory Neil Shapiro {
643d0cef73dSGregory Neil Shapiro 	char *argv[SM_LDAP_ARGS];
644d0cef73dSGregory Neil Shapiro 
645d0cef73dSGregory Neil Shapiro 	memset(argv, '\0', sizeof argv);
646d0cef73dSGregory Neil Shapiro 	argv[0] = key;
647d0cef73dSGregory Neil Shapiro 	return sm_ldap_search_m(lmap, argv);
648d0cef73dSGregory Neil Shapiro }
649d0cef73dSGregory Neil Shapiro 
650d0cef73dSGregory Neil Shapiro /*
651605302a5SGregory Neil Shapiro **  SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a
652605302a5SGregory Neil Shapiro **			       particular objectClass
653605302a5SGregory Neil Shapiro **
654605302a5SGregory Neil Shapiro **	Parameters:
655605302a5SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
656605302a5SGregory Neil Shapiro **		entry -- current LDAP entry struct
657605302a5SGregory Neil Shapiro **		ocvalue -- particular objectclass in question.
658605302a5SGregory Neil Shapiro **			   may be of form (fee|foo|fum) meaning
659605302a5SGregory Neil Shapiro **			   any entry can be part of either fee,
660605302a5SGregory Neil Shapiro **			   foo or fum objectclass
661605302a5SGregory Neil Shapiro **
662605302a5SGregory Neil Shapiro **	Returns:
663605302a5SGregory Neil Shapiro **		true if item has that objectClass
664605302a5SGregory Neil Shapiro */
665605302a5SGregory Neil Shapiro 
666605302a5SGregory Neil Shapiro static bool
667605302a5SGregory Neil Shapiro sm_ldap_has_objectclass(lmap, entry, ocvalue)
668605302a5SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
669605302a5SGregory Neil Shapiro 	LDAPMessage *entry;
670605302a5SGregory Neil Shapiro 	char *ocvalue;
671605302a5SGregory Neil Shapiro {
672605302a5SGregory Neil Shapiro 	char **vals = NULL;
673605302a5SGregory Neil Shapiro 	int i;
674605302a5SGregory Neil Shapiro 
675605302a5SGregory Neil Shapiro 	if (ocvalue == NULL)
676605302a5SGregory Neil Shapiro 		return false;
677605302a5SGregory Neil Shapiro 
678605302a5SGregory Neil Shapiro 	vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass");
679605302a5SGregory Neil Shapiro 	if (vals == NULL)
680605302a5SGregory Neil Shapiro 		return false;
681605302a5SGregory Neil Shapiro 
682605302a5SGregory Neil Shapiro 	for (i = 0; vals[i] != NULL; i++)
683605302a5SGregory Neil Shapiro 	{
684605302a5SGregory Neil Shapiro 		char *p;
685605302a5SGregory Neil Shapiro 		char *q;
686605302a5SGregory Neil Shapiro 
687605302a5SGregory Neil Shapiro 		p = q = ocvalue;
688605302a5SGregory Neil Shapiro 		while (*p != '\0')
689605302a5SGregory Neil Shapiro 		{
690605302a5SGregory Neil Shapiro 			while (*p != '\0' && *p != '|')
691605302a5SGregory Neil Shapiro 				p++;
692605302a5SGregory Neil Shapiro 
693605302a5SGregory Neil Shapiro 			if ((p - q) == strlen(vals[i]) &&
694605302a5SGregory Neil Shapiro 			    sm_strncasecmp(vals[i], q, p - q) == 0)
695605302a5SGregory Neil Shapiro 			{
696605302a5SGregory Neil Shapiro 				ldap_value_free(vals);
697605302a5SGregory Neil Shapiro 				return true;
698605302a5SGregory Neil Shapiro 			}
699605302a5SGregory Neil Shapiro 
700605302a5SGregory Neil Shapiro 			while (*p == '|')
701605302a5SGregory Neil Shapiro 				p++;
702605302a5SGregory Neil Shapiro 			q = p;
703605302a5SGregory Neil Shapiro 		}
704605302a5SGregory Neil Shapiro 	}
705605302a5SGregory Neil Shapiro 
706605302a5SGregory Neil Shapiro 	ldap_value_free(vals);
707605302a5SGregory Neil Shapiro 	return false;
708605302a5SGregory Neil Shapiro }
709605302a5SGregory Neil Shapiro 
710605302a5SGregory Neil Shapiro /*
71140266059SGregory Neil Shapiro **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
71240266059SGregory Neil Shapiro **
71340266059SGregory Neil Shapiro **	Parameters:
71440266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
71540266059SGregory Neil Shapiro **		msgid -- msgid returned by sm_ldap_search()
71640266059SGregory Neil Shapiro **		flags -- flags for the lookup
71740266059SGregory Neil Shapiro **		delim -- delimiter for result concatenation
71840266059SGregory Neil Shapiro **		rpool -- memory pool for storage
71940266059SGregory Neil Shapiro **		result -- return string
72040266059SGregory Neil Shapiro **		recurse -- recursion list
72140266059SGregory Neil Shapiro **
72240266059SGregory Neil Shapiro **	Returns:
72340266059SGregory Neil Shapiro **		status (sysexit)
72440266059SGregory Neil Shapiro */
72540266059SGregory Neil Shapiro 
726605302a5SGregory Neil Shapiro # define SM_LDAP_ERROR_CLEANUP()				\
72740266059SGregory Neil Shapiro {								\
72840266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)				\
72940266059SGregory Neil Shapiro 	{							\
73040266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);			\
73140266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;				\
73240266059SGregory Neil Shapiro 	}							\
73340266059SGregory Neil Shapiro 	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
73440266059SGregory Neil Shapiro }
73540266059SGregory Neil Shapiro 
736605302a5SGregory Neil Shapiro static SM_LDAP_RECURSE_ENTRY *
737605302a5SGregory Neil Shapiro sm_ldap_add_recurse(top, item, type, rpool)
73840266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST **top;
73940266059SGregory Neil Shapiro 	char *item;
74040266059SGregory Neil Shapiro 	int type;
74140266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
74240266059SGregory Neil Shapiro {
743605302a5SGregory Neil Shapiro 	int n;
744605302a5SGregory Neil Shapiro 	int m;
745605302a5SGregory Neil Shapiro 	int p;
746605302a5SGregory Neil Shapiro 	int insertat;
747605302a5SGregory Neil Shapiro 	int moveb;
748605302a5SGregory Neil Shapiro 	int oldsizeb;
749605302a5SGregory Neil Shapiro 	int rc;
750605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *newe;
751605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY **olddata;
75240266059SGregory Neil Shapiro 
753605302a5SGregory Neil Shapiro 	/*
754605302a5SGregory Neil Shapiro 	**  This code will maintain a list of
755605302a5SGregory Neil Shapiro 	**  SM_LDAP_RECURSE_ENTRY structures
756605302a5SGregory Neil Shapiro 	**  in ascending order.
757605302a5SGregory Neil Shapiro 	*/
758605302a5SGregory Neil Shapiro 
759605302a5SGregory Neil Shapiro 	if (*top == NULL)
76040266059SGregory Neil Shapiro 	{
761605302a5SGregory Neil Shapiro 		/* Allocate an initial SM_LDAP_RECURSE_LIST struct */
762605302a5SGregory Neil Shapiro 		*top = sm_rpool_malloc_x(rpool, sizeof **top);
763d0cef73dSGregory Neil Shapiro 		(*top)->lrl_cnt = 0;
764d0cef73dSGregory Neil Shapiro 		(*top)->lrl_size = 0;
765d0cef73dSGregory Neil Shapiro 		(*top)->lrl_data = NULL;
76640266059SGregory Neil Shapiro 	}
76740266059SGregory Neil Shapiro 
768d0cef73dSGregory Neil Shapiro 	if ((*top)->lrl_cnt >= (*top)->lrl_size)
769605302a5SGregory Neil Shapiro 	{
770605302a5SGregory Neil Shapiro 		/* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */
771d0cef73dSGregory Neil Shapiro 		olddata = (*top)->lrl_data;
772d0cef73dSGregory Neil Shapiro 		if ((*top)->lrl_size == 0)
773605302a5SGregory Neil Shapiro 		{
774605302a5SGregory Neil Shapiro 			oldsizeb = 0;
775d0cef73dSGregory Neil Shapiro 			(*top)->lrl_size = 256;
776605302a5SGregory Neil Shapiro 		}
77740266059SGregory Neil Shapiro 		else
778605302a5SGregory Neil Shapiro 		{
779d0cef73dSGregory Neil Shapiro 			oldsizeb = (*top)->lrl_size * sizeof *((*top)->lrl_data);
780d0cef73dSGregory Neil Shapiro 			(*top)->lrl_size *= 2;
781605302a5SGregory Neil Shapiro 		}
782d0cef73dSGregory Neil Shapiro 		(*top)->lrl_data = sm_rpool_malloc_x(rpool,
783d0cef73dSGregory Neil Shapiro 						    (*top)->lrl_size * sizeof *((*top)->lrl_data));
784605302a5SGregory Neil Shapiro 		if (oldsizeb > 0)
785d0cef73dSGregory Neil Shapiro 			memcpy((*top)->lrl_data, olddata, oldsizeb);
786605302a5SGregory Neil Shapiro 	}
787605302a5SGregory Neil Shapiro 
788605302a5SGregory Neil Shapiro 	/*
789605302a5SGregory Neil Shapiro 	**  Binary search/insert item:type into list.
790605302a5SGregory Neil Shapiro 	**  Return current entry pointer if already exists.
791605302a5SGregory Neil Shapiro 	*/
792605302a5SGregory Neil Shapiro 
793605302a5SGregory Neil Shapiro 	n = 0;
794d0cef73dSGregory Neil Shapiro 	m = (*top)->lrl_cnt - 1;
795605302a5SGregory Neil Shapiro 	if (m < 0)
796605302a5SGregory Neil Shapiro 		insertat = 0;
797605302a5SGregory Neil Shapiro 	else
798605302a5SGregory Neil Shapiro 		insertat = -1;
799605302a5SGregory Neil Shapiro 
800605302a5SGregory Neil Shapiro 	while (insertat == -1)
801605302a5SGregory Neil Shapiro 	{
802605302a5SGregory Neil Shapiro 		p = (m + n) / 2;
803605302a5SGregory Neil Shapiro 
804d0cef73dSGregory Neil Shapiro 		rc = sm_strcasecmp(item, (*top)->lrl_data[p]->lr_search);
805605302a5SGregory Neil Shapiro 		if (rc == 0)
806d0cef73dSGregory Neil Shapiro 			rc = type - (*top)->lrl_data[p]->lr_type;
807605302a5SGregory Neil Shapiro 
808605302a5SGregory Neil Shapiro 		if (rc < 0)
809605302a5SGregory Neil Shapiro 			m = p - 1;
810605302a5SGregory Neil Shapiro 		else if (rc > 0)
811605302a5SGregory Neil Shapiro 			n = p + 1;
812605302a5SGregory Neil Shapiro 		else
813d0cef73dSGregory Neil Shapiro 			return (*top)->lrl_data[p];
814605302a5SGregory Neil Shapiro 
815605302a5SGregory Neil Shapiro 		if (m == -1)
816605302a5SGregory Neil Shapiro 			insertat = 0;
817d0cef73dSGregory Neil Shapiro 		else if (n >= (*top)->lrl_cnt)
818d0cef73dSGregory Neil Shapiro 			insertat = (*top)->lrl_cnt;
819605302a5SGregory Neil Shapiro 		else if (m < n)
820605302a5SGregory Neil Shapiro 			insertat = m + 1;
821605302a5SGregory Neil Shapiro 	}
822605302a5SGregory Neil Shapiro 
823605302a5SGregory Neil Shapiro 	/*
824605302a5SGregory Neil Shapiro 	** Not found in list, make room
825605302a5SGregory Neil Shapiro 	** at insert point and add it.
826605302a5SGregory Neil Shapiro 	*/
827605302a5SGregory Neil Shapiro 
828605302a5SGregory Neil Shapiro 	newe = sm_rpool_malloc_x(rpool, sizeof *newe);
829605302a5SGregory Neil Shapiro 	if (newe != NULL)
830605302a5SGregory Neil Shapiro 	{
831d0cef73dSGregory Neil Shapiro 		moveb = ((*top)->lrl_cnt - insertat) * sizeof *((*top)->lrl_data);
832605302a5SGregory Neil Shapiro 		if (moveb > 0)
833d0cef73dSGregory Neil Shapiro 			memmove(&((*top)->lrl_data[insertat + 1]),
834d0cef73dSGregory Neil Shapiro 				&((*top)->lrl_data[insertat]),
835605302a5SGregory Neil Shapiro 				moveb);
836605302a5SGregory Neil Shapiro 
837605302a5SGregory Neil Shapiro 		newe->lr_search = sm_rpool_strdup_x(rpool, item);
838605302a5SGregory Neil Shapiro 		newe->lr_type = type;
839e92d3f3fSGregory Neil Shapiro 		newe->lr_ludp = NULL;
840e92d3f3fSGregory Neil Shapiro 		newe->lr_attrs = NULL;
841605302a5SGregory Neil Shapiro 		newe->lr_done = false;
842605302a5SGregory Neil Shapiro 
843d0cef73dSGregory Neil Shapiro 		((*top)->lrl_data)[insertat] = newe;
844d0cef73dSGregory Neil Shapiro 		(*top)->lrl_cnt++;
845605302a5SGregory Neil Shapiro 	}
846605302a5SGregory Neil Shapiro 	return newe;
84740266059SGregory Neil Shapiro }
84840266059SGregory Neil Shapiro 
84940266059SGregory Neil Shapiro int
850605302a5SGregory Neil Shapiro sm_ldap_results(lmap, msgid, flags, delim, rpool, result,
851605302a5SGregory Neil Shapiro 		resultln, resultsz, recurse)
85240266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
85340266059SGregory Neil Shapiro 	int msgid;
85440266059SGregory Neil Shapiro 	int flags;
855605302a5SGregory Neil Shapiro 	int delim;
85640266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
85740266059SGregory Neil Shapiro 	char **result;
858605302a5SGregory Neil Shapiro 	int *resultln;
859605302a5SGregory Neil Shapiro 	int *resultsz;
86040266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *recurse;
86140266059SGregory Neil Shapiro {
86240266059SGregory Neil Shapiro 	bool toplevel;
86340266059SGregory Neil Shapiro 	int i;
86440266059SGregory Neil Shapiro 	int statp;
86540266059SGregory Neil Shapiro 	int vsize;
86640266059SGregory Neil Shapiro 	int ret;
86740266059SGregory Neil Shapiro 	int save_errno;
86840266059SGregory Neil Shapiro 	char *p;
869605302a5SGregory Neil Shapiro 	SM_LDAP_RECURSE_ENTRY *rl;
87040266059SGregory Neil Shapiro 
87140266059SGregory Neil Shapiro 	/* Are we the top top level of the search? */
87240266059SGregory Neil Shapiro 	toplevel = (recurse == NULL);
87340266059SGregory Neil Shapiro 
87440266059SGregory Neil Shapiro 	/* Get results */
87540266059SGregory Neil Shapiro 	statp = EX_NOTFOUND;
87640266059SGregory Neil Shapiro 	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
87740266059SGregory Neil Shapiro 				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
87840266059SGregory Neil Shapiro 				   &(lmap->ldap_timeout)),
87940266059SGregory Neil Shapiro 				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
88040266059SGregory Neil Shapiro 	{
88140266059SGregory Neil Shapiro 		LDAPMessage *entry;
88240266059SGregory Neil Shapiro 
88340266059SGregory Neil Shapiro 		/* If we don't want multiple values and we have one, break */
88413d88268SGregory Neil Shapiro 		if ((char) delim == '\0' &&
88513d88268SGregory Neil Shapiro 		    !bitset(SM_LDAP_SINGLEMATCH, flags) &&
88613d88268SGregory Neil Shapiro 		    *result != NULL)
88740266059SGregory Neil Shapiro 			break;
88840266059SGregory Neil Shapiro 
88940266059SGregory Neil Shapiro 		/* Cycle through all entries */
89040266059SGregory Neil Shapiro 		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
89140266059SGregory Neil Shapiro 		     entry != NULL;
89240266059SGregory Neil Shapiro 		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
89340266059SGregory Neil Shapiro 		{
89440266059SGregory Neil Shapiro 			BerElement *ber;
89540266059SGregory Neil Shapiro 			char *attr;
89640266059SGregory Neil Shapiro 			char **vals = NULL;
89740266059SGregory Neil Shapiro 			char *dn;
89840266059SGregory Neil Shapiro 
89940266059SGregory Neil Shapiro 			/*
90040266059SGregory Neil Shapiro 			**  If matching only and found an entry,
90140266059SGregory Neil Shapiro 			**  no need to spin through attributes
90240266059SGregory Neil Shapiro 			*/
90340266059SGregory Neil Shapiro 
904323f6dcbSGregory Neil Shapiro 			if (bitset(SM_LDAP_MATCHONLY, flags))
905323f6dcbSGregory Neil Shapiro 			{
906323f6dcbSGregory Neil Shapiro 				statp = EX_OK;
90740266059SGregory Neil Shapiro 				continue;
908323f6dcbSGregory Neil Shapiro 			}
90940266059SGregory Neil Shapiro 
9104e4196cbSGregory Neil Shapiro #if _FFR_LDAP_SINGLEDN
9114e4196cbSGregory Neil Shapiro 			if (bitset(SM_LDAP_SINGLEDN, flags) && *result != NULL)
9124e4196cbSGregory Neil Shapiro 			{
9134e4196cbSGregory Neil Shapiro 				/* only wanted one match */
9144e4196cbSGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
9154e4196cbSGregory Neil Shapiro 				errno = ENOENT;
9164e4196cbSGregory Neil Shapiro 				return EX_NOTFOUND;
9174e4196cbSGregory Neil Shapiro 			}
9184e4196cbSGregory Neil Shapiro #endif /* _FFR_LDAP_SINGLEDN */
9194e4196cbSGregory Neil Shapiro 
92040266059SGregory Neil Shapiro 			/* record completed DN's to prevent loops */
92140266059SGregory Neil Shapiro 			dn = ldap_get_dn(lmap->ldap_ld, entry);
92240266059SGregory Neil Shapiro 			if (dn == NULL)
92340266059SGregory Neil Shapiro 			{
92440266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
92540266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
926605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
92740266059SGregory Neil Shapiro 				errno = save_errno;
928a7ec597cSGregory Neil Shapiro 				return EX_TEMPFAIL;
92940266059SGregory Neil Shapiro 			}
93040266059SGregory Neil Shapiro 
931605302a5SGregory Neil Shapiro 			rl = sm_ldap_add_recurse(&recurse, dn,
932605302a5SGregory Neil Shapiro 						 SM_LDAP_ATTR_DN,
933605302a5SGregory Neil Shapiro 						 rpool);
934605302a5SGregory Neil Shapiro 
935605302a5SGregory Neil Shapiro 			if (rl == NULL)
93640266059SGregory Neil Shapiro 			{
93740266059SGregory Neil Shapiro 				ldap_memfree(dn);
938605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
93940266059SGregory Neil Shapiro 				errno = ENOMEM;
94040266059SGregory Neil Shapiro 				return EX_OSERR;
941605302a5SGregory Neil Shapiro 			}
942605302a5SGregory Neil Shapiro 			else if (rl->lr_done)
943605302a5SGregory Neil Shapiro 			{
94440266059SGregory Neil Shapiro 				/* already on list, skip it */
94540266059SGregory Neil Shapiro 				ldap_memfree(dn);
94640266059SGregory Neil Shapiro 				continue;
94740266059SGregory Neil Shapiro 			}
94840266059SGregory Neil Shapiro 			ldap_memfree(dn);
94940266059SGregory Neil Shapiro 
95040266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
95140266059SGregory Neil Shapiro 			/*
95240266059SGregory Neil Shapiro 			**  Reset value to prevent lingering
95340266059SGregory Neil Shapiro 			**  LDAP_DECODING_ERROR due to
95440266059SGregory Neil Shapiro 			**  OpenLDAP 1.X's hack (see below)
95540266059SGregory Neil Shapiro 			*/
95640266059SGregory Neil Shapiro 
95740266059SGregory Neil Shapiro 			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
95840266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
95940266059SGregory Neil Shapiro 
96040266059SGregory Neil Shapiro 			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
96140266059SGregory Neil Shapiro 							 &ber);
96240266059SGregory Neil Shapiro 			     attr != NULL;
96340266059SGregory Neil Shapiro 			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
96440266059SGregory Neil Shapiro 							ber))
96540266059SGregory Neil Shapiro 			{
96640266059SGregory Neil Shapiro 				char *tmp, *vp_tmp;
96740266059SGregory Neil Shapiro 				int type;
968605302a5SGregory Neil Shapiro 				char *needobjclass = NULL;
96940266059SGregory Neil Shapiro 
970605302a5SGregory Neil Shapiro 				type = SM_LDAP_ATTR_NONE;
97140266059SGregory Neil Shapiro 				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
97240266059SGregory Neil Shapiro 				{
97340266059SGregory Neil Shapiro 					if (sm_strcasecmp(lmap->ldap_attr[i],
97440266059SGregory Neil Shapiro 							  attr) == 0)
97540266059SGregory Neil Shapiro 					{
97640266059SGregory Neil Shapiro 						type = lmap->ldap_attr_type[i];
977605302a5SGregory Neil Shapiro 						needobjclass = lmap->ldap_attr_needobjclass[i];
97840266059SGregory Neil Shapiro 						break;
97940266059SGregory Neil Shapiro 					}
98040266059SGregory Neil Shapiro 				}
981605302a5SGregory Neil Shapiro 
982605302a5SGregory Neil Shapiro 				if (bitset(SM_LDAP_USE_ALLATTR, flags) &&
983605302a5SGregory Neil Shapiro 				    type == SM_LDAP_ATTR_NONE)
984605302a5SGregory Neil Shapiro 				{
985605302a5SGregory Neil Shapiro 					/* URL lookups specify attrs to use */
986605302a5SGregory Neil Shapiro 					type = SM_LDAP_ATTR_NORMAL;
987605302a5SGregory Neil Shapiro 					needobjclass = NULL;
988605302a5SGregory Neil Shapiro 				}
989605302a5SGregory Neil Shapiro 
990605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NONE)
99140266059SGregory Neil Shapiro 				{
99240266059SGregory Neil Shapiro 					/* attribute not requested */
99340266059SGregory Neil Shapiro 					ldap_memfree(attr);
994605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
99540266059SGregory Neil Shapiro 					errno = EFAULT;
99640266059SGregory Neil Shapiro 					return EX_SOFTWARE;
99740266059SGregory Neil Shapiro 				}
99840266059SGregory Neil Shapiro 
999605302a5SGregory Neil Shapiro 				/*
1000605302a5SGregory Neil Shapiro 				**  For recursion on a particular attribute,
1001605302a5SGregory Neil Shapiro 				**  we may need to see if this entry is
1002605302a5SGregory Neil Shapiro 				**  part of a particular objectclass.
1003605302a5SGregory Neil Shapiro 				**  Also, ignore objectClass attribute.
1004605302a5SGregory Neil Shapiro 				**  Otherwise we just ignore this attribute.
1005605302a5SGregory Neil Shapiro 				*/
1006605302a5SGregory Neil Shapiro 
1007605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_OBJCLASS ||
1008605302a5SGregory Neil Shapiro 				    (needobjclass != NULL &&
1009605302a5SGregory Neil Shapiro 				     !sm_ldap_has_objectclass(lmap, entry,
1010605302a5SGregory Neil Shapiro 							      needobjclass)))
1011605302a5SGregory Neil Shapiro 				{
1012605302a5SGregory Neil Shapiro 					ldap_memfree(attr);
1013605302a5SGregory Neil Shapiro 					continue;
1014605302a5SGregory Neil Shapiro 				}
1015605302a5SGregory Neil Shapiro 
101640266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
101740266059SGregory Neil Shapiro 				{
101840266059SGregory Neil Shapiro 					vals = ldap_get_values(lmap->ldap_ld,
101940266059SGregory Neil Shapiro 							       entry,
102040266059SGregory Neil Shapiro 							       attr);
102140266059SGregory Neil Shapiro 					if (vals == NULL)
102240266059SGregory Neil Shapiro 					{
102340266059SGregory Neil Shapiro 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
102440266059SGregory Neil Shapiro 						if (save_errno == LDAP_SUCCESS)
102540266059SGregory Neil Shapiro 						{
102640266059SGregory Neil Shapiro 							ldap_memfree(attr);
102740266059SGregory Neil Shapiro 							continue;
102840266059SGregory Neil Shapiro 						}
102940266059SGregory Neil Shapiro 
103040266059SGregory Neil Shapiro 						/* Must be an error */
103140266059SGregory Neil Shapiro 						save_errno += E_LDAPBASE;
103240266059SGregory Neil Shapiro 						ldap_memfree(attr);
1033605302a5SGregory Neil Shapiro 						SM_LDAP_ERROR_CLEANUP();
103440266059SGregory Neil Shapiro 						errno = save_errno;
103540266059SGregory Neil Shapiro 						return EX_TEMPFAIL;
103640266059SGregory Neil Shapiro 					}
103740266059SGregory Neil Shapiro 				}
103840266059SGregory Neil Shapiro 
103940266059SGregory Neil Shapiro 				statp = EX_OK;
104040266059SGregory Neil Shapiro 
104140266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
104240266059SGregory Neil Shapiro 				/*
104340266059SGregory Neil Shapiro 				**  Reset value to prevent lingering
104440266059SGregory Neil Shapiro 				**  LDAP_DECODING_ERROR due to
104540266059SGregory Neil Shapiro 				**  OpenLDAP 1.X's hack (see below)
104640266059SGregory Neil Shapiro 				*/
104740266059SGregory Neil Shapiro 
104840266059SGregory Neil Shapiro 				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
104940266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
105040266059SGregory Neil Shapiro 
105140266059SGregory Neil Shapiro 				/*
105240266059SGregory Neil Shapiro 				**  If matching only,
105340266059SGregory Neil Shapiro 				**  no need to spin through entries
105440266059SGregory Neil Shapiro 				*/
105540266059SGregory Neil Shapiro 
105640266059SGregory Neil Shapiro 				if (bitset(SM_LDAP_MATCHONLY, flags))
105740266059SGregory Neil Shapiro 				{
105840266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
105940266059SGregory Neil Shapiro 						ldap_value_free(vals);
106040266059SGregory Neil Shapiro 					ldap_memfree(attr);
106140266059SGregory Neil Shapiro 					continue;
106240266059SGregory Neil Shapiro 				}
106340266059SGregory Neil Shapiro 
106440266059SGregory Neil Shapiro 				/*
106540266059SGregory Neil Shapiro 				**  If we don't want multiple values,
106640266059SGregory Neil Shapiro 				**  return first found.
106740266059SGregory Neil Shapiro 				*/
106840266059SGregory Neil Shapiro 
1069605302a5SGregory Neil Shapiro 				if ((char) delim == '\0')
107040266059SGregory Neil Shapiro 				{
1071605302a5SGregory Neil Shapiro 					if (*result != NULL)
1072605302a5SGregory Neil Shapiro 					{
1073605302a5SGregory Neil Shapiro 						/* already have a value */
1074605302a5SGregory Neil Shapiro 						if (bitset(SM_LDAP_SINGLEMATCH,
107513d88268SGregory Neil Shapiro 							   flags))
1076605302a5SGregory Neil Shapiro 						{
1077605302a5SGregory Neil Shapiro 							/* only wanted one match */
1078605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
1079605302a5SGregory Neil Shapiro 							errno = ENOENT;
1080605302a5SGregory Neil Shapiro 							return EX_NOTFOUND;
1081605302a5SGregory Neil Shapiro 						}
108213d88268SGregory Neil Shapiro 						break;
108313d88268SGregory Neil Shapiro 					}
1084605302a5SGregory Neil Shapiro 
108540266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
108640266059SGregory Neil Shapiro 					{
108740266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
108840266059SGregory Neil Shapiro 									    attr);
108940266059SGregory Neil Shapiro 						ldap_memfree(attr);
109040266059SGregory Neil Shapiro 						break;
109140266059SGregory Neil Shapiro 					}
109240266059SGregory Neil Shapiro 
109340266059SGregory Neil Shapiro 					if (vals[0] == NULL)
109440266059SGregory Neil Shapiro 					{
109540266059SGregory Neil Shapiro 						ldap_value_free(vals);
109640266059SGregory Neil Shapiro 						ldap_memfree(attr);
109740266059SGregory Neil Shapiro 						continue;
109840266059SGregory Neil Shapiro 					}
109940266059SGregory Neil Shapiro 
110040266059SGregory Neil Shapiro 					vsize = strlen(vals[0]) + 1;
110140266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
110240266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
110340266059SGregory Neil Shapiro 					*result = sm_rpool_malloc_x(rpool,
110440266059SGregory Neil Shapiro 								    vsize);
110540266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
110640266059SGregory Neil Shapiro 						sm_snprintf(*result, vsize,
110740266059SGregory Neil Shapiro 							    "%s%c%s",
110840266059SGregory Neil Shapiro 							    attr,
110940266059SGregory Neil Shapiro 							    lmap->ldap_attrsep,
111040266059SGregory Neil Shapiro 							    vals[0]);
111140266059SGregory Neil Shapiro 					else
111240266059SGregory Neil Shapiro 						sm_strlcpy(*result, vals[0],
111340266059SGregory Neil Shapiro 							   vsize);
111440266059SGregory Neil Shapiro 					ldap_value_free(vals);
111540266059SGregory Neil Shapiro 					ldap_memfree(attr);
111640266059SGregory Neil Shapiro 					break;
111740266059SGregory Neil Shapiro 				}
111840266059SGregory Neil Shapiro 
111940266059SGregory Neil Shapiro 				/* attributes only */
112040266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
112140266059SGregory Neil Shapiro 				{
112240266059SGregory Neil Shapiro 					if (*result == NULL)
112340266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
112440266059SGregory Neil Shapiro 									    attr);
112540266059SGregory Neil Shapiro 					else
112640266059SGregory Neil Shapiro 					{
1127605302a5SGregory Neil Shapiro 						if (bitset(SM_LDAP_SINGLEMATCH,
1128605302a5SGregory Neil Shapiro 							   flags) &&
1129605302a5SGregory Neil Shapiro 						    *result != NULL)
1130605302a5SGregory Neil Shapiro 						{
1131605302a5SGregory Neil Shapiro 							/* only wanted one match */
1132605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
1133605302a5SGregory Neil Shapiro 							errno = ENOENT;
1134605302a5SGregory Neil Shapiro 							return EX_NOTFOUND;
1135605302a5SGregory Neil Shapiro 						}
1136605302a5SGregory Neil Shapiro 
113740266059SGregory Neil Shapiro 						vsize = strlen(*result) +
113840266059SGregory Neil Shapiro 							strlen(attr) + 2;
113940266059SGregory Neil Shapiro 						tmp = sm_rpool_malloc_x(rpool,
114040266059SGregory Neil Shapiro 									vsize);
114140266059SGregory Neil Shapiro 						(void) sm_snprintf(tmp,
114240266059SGregory Neil Shapiro 							vsize, "%s%c%s",
1143605302a5SGregory Neil Shapiro 							*result, (char) delim,
114440266059SGregory Neil Shapiro 							attr);
114540266059SGregory Neil Shapiro 						*result = tmp;
114640266059SGregory Neil Shapiro 					}
114740266059SGregory Neil Shapiro 					ldap_memfree(attr);
114840266059SGregory Neil Shapiro 					continue;
114940266059SGregory Neil Shapiro 				}
115040266059SGregory Neil Shapiro 
115140266059SGregory Neil Shapiro 				/*
1152605302a5SGregory Neil Shapiro 				**  If there is more than one, munge then
1153605302a5SGregory Neil Shapiro 				**  into a map_coldelim separated string.
1154605302a5SGregory Neil Shapiro 				**  If we are recursing we may have an entry
1155605302a5SGregory Neil Shapiro 				**  with no 'normal' values to put in the
1156605302a5SGregory Neil Shapiro 				**  string.
1157605302a5SGregory Neil Shapiro 				**  This is not an error.
115840266059SGregory Neil Shapiro 				*/
115940266059SGregory Neil Shapiro 
1160605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL &&
1161605302a5SGregory Neil Shapiro 				    bitset(SM_LDAP_SINGLEMATCH, flags) &&
1162605302a5SGregory Neil Shapiro 				    *result != NULL)
1163605302a5SGregory Neil Shapiro 				{
1164605302a5SGregory Neil Shapiro 					/* only wanted one match */
1165605302a5SGregory Neil Shapiro 					SM_LDAP_ERROR_CLEANUP();
1166605302a5SGregory Neil Shapiro 					errno = ENOENT;
1167605302a5SGregory Neil Shapiro 					return EX_NOTFOUND;
1168605302a5SGregory Neil Shapiro 				}
1169605302a5SGregory Neil Shapiro 
117040266059SGregory Neil Shapiro 				vsize = 0;
117140266059SGregory Neil Shapiro 				for (i = 0; vals[i] != NULL; i++)
117240266059SGregory Neil Shapiro 				{
1173605302a5SGregory Neil Shapiro 					if (type == SM_LDAP_ATTR_DN ||
1174605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_FILTER ||
1175605302a5SGregory Neil Shapiro 					    type == SM_LDAP_ATTR_URL)
117640266059SGregory Neil Shapiro 					{
1177605302a5SGregory Neil Shapiro 						/* add to recursion */
1178605302a5SGregory Neil Shapiro 						if (sm_ldap_add_recurse(&recurse,
117940266059SGregory Neil Shapiro 									vals[i],
1180605302a5SGregory Neil Shapiro 									type,
1181605302a5SGregory Neil Shapiro 									rpool) == NULL)
118240266059SGregory Neil Shapiro 						{
1183605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
118440266059SGregory Neil Shapiro 							errno = ENOMEM;
118540266059SGregory Neil Shapiro 							return EX_OSERR;
118640266059SGregory Neil Shapiro 						}
118740266059SGregory Neil Shapiro 						continue;
118840266059SGregory Neil Shapiro 					}
1189605302a5SGregory Neil Shapiro 
119040266059SGregory Neil Shapiro 					vsize += strlen(vals[i]) + 1;
119140266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
119240266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
119340266059SGregory Neil Shapiro 				}
1194605302a5SGregory Neil Shapiro 
1195605302a5SGregory Neil Shapiro 				/*
1196605302a5SGregory Neil Shapiro 				**  Create/Append to string any normal
1197605302a5SGregory Neil Shapiro 				**  attribute values.  Otherwise, just free
1198605302a5SGregory Neil Shapiro 				**  memory and move on to the next
1199605302a5SGregory Neil Shapiro 				**  attribute in this entry.
1200605302a5SGregory Neil Shapiro 				*/
1201605302a5SGregory Neil Shapiro 
1202605302a5SGregory Neil Shapiro 				if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)
1203605302a5SGregory Neil Shapiro 				{
1204605302a5SGregory Neil Shapiro 					char *pe;
1205605302a5SGregory Neil Shapiro 
1206605302a5SGregory Neil Shapiro 					/* Grow result string if needed */
1207605302a5SGregory Neil Shapiro 					if ((*resultln + vsize) >= *resultsz)
1208605302a5SGregory Neil Shapiro 					{
1209605302a5SGregory Neil Shapiro 						while ((*resultln + vsize) >= *resultsz)
1210605302a5SGregory Neil Shapiro 						{
1211605302a5SGregory Neil Shapiro 							if (*resultsz == 0)
1212605302a5SGregory Neil Shapiro 								*resultsz = 1024;
1213605302a5SGregory Neil Shapiro 							else
1214605302a5SGregory Neil Shapiro 								*resultsz *= 2;
1215605302a5SGregory Neil Shapiro 						}
1216605302a5SGregory Neil Shapiro 
1217605302a5SGregory Neil Shapiro 						vp_tmp = sm_rpool_malloc_x(rpool, *resultsz);
121840266059SGregory Neil Shapiro 						*vp_tmp = '\0';
121940266059SGregory Neil Shapiro 
1220605302a5SGregory Neil Shapiro 						if (*result != NULL)
1221605302a5SGregory Neil Shapiro 							sm_strlcpy(vp_tmp,
1222605302a5SGregory Neil Shapiro 								   *result,
1223605302a5SGregory Neil Shapiro 								   *resultsz);
1224605302a5SGregory Neil Shapiro 						*result = vp_tmp;
1225605302a5SGregory Neil Shapiro 					}
1226605302a5SGregory Neil Shapiro 
1227605302a5SGregory Neil Shapiro 					p = *result + *resultln;
1228605302a5SGregory Neil Shapiro 					pe = *result + *resultsz;
1229605302a5SGregory Neil Shapiro 
123040266059SGregory Neil Shapiro 					for (i = 0; vals[i] != NULL; i++)
123140266059SGregory Neil Shapiro 					{
1232959366dcSGregory Neil Shapiro 						if (*resultln > 0 &&
1233959366dcSGregory Neil Shapiro 						    p < pe)
1234605302a5SGregory Neil Shapiro 							*p++ = (char) delim;
1235605302a5SGregory Neil Shapiro 
123640266059SGregory Neil Shapiro 						if (lmap->ldap_attrsep != '\0')
123740266059SGregory Neil Shapiro 						{
123840266059SGregory Neil Shapiro 							p += sm_strlcpy(p, attr,
1239605302a5SGregory Neil Shapiro 									pe - p);
1240605302a5SGregory Neil Shapiro 							if (p < pe)
124140266059SGregory Neil Shapiro 								*p++ = lmap->ldap_attrsep;
124240266059SGregory Neil Shapiro 						}
1243605302a5SGregory Neil Shapiro 
124440266059SGregory Neil Shapiro 						p += sm_strlcpy(p, vals[i],
1245605302a5SGregory Neil Shapiro 								pe - p);
1246605302a5SGregory Neil Shapiro 						*resultln = p - (*result);
1247605302a5SGregory Neil Shapiro 						if (p >= pe)
124840266059SGregory Neil Shapiro 						{
124940266059SGregory Neil Shapiro 							/* Internal error: buffer too small for LDAP values */
1250605302a5SGregory Neil Shapiro 							SM_LDAP_ERROR_CLEANUP();
125140266059SGregory Neil Shapiro 							errno = ENOMEM;
125240266059SGregory Neil Shapiro 							return EX_OSERR;
125340266059SGregory Neil Shapiro 						}
1254605302a5SGregory Neil Shapiro 					}
125540266059SGregory Neil Shapiro 				}
125640266059SGregory Neil Shapiro 
125740266059SGregory Neil Shapiro 				ldap_value_free(vals);
125840266059SGregory Neil Shapiro 				ldap_memfree(attr);
125940266059SGregory Neil Shapiro 			}
126040266059SGregory Neil Shapiro 			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
126140266059SGregory Neil Shapiro 
126240266059SGregory Neil Shapiro 			/*
126340266059SGregory Neil Shapiro 			**  We check save_errno != LDAP_DECODING_ERROR since
126440266059SGregory Neil Shapiro 			**  OpenLDAP 1.X has a very ugly *undocumented*
126540266059SGregory Neil Shapiro 			**  hack of returning this error code from
126640266059SGregory Neil Shapiro 			**  ldap_next_attribute() if the library freed the
126740266059SGregory Neil Shapiro 			**  ber attribute.  See:
126840266059SGregory Neil Shapiro 			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
126940266059SGregory Neil Shapiro 			*/
127040266059SGregory Neil Shapiro 
127140266059SGregory Neil Shapiro 			if (save_errno != LDAP_SUCCESS &&
127240266059SGregory Neil Shapiro 			    save_errno != LDAP_DECODING_ERROR)
127340266059SGregory Neil Shapiro 			{
127440266059SGregory Neil Shapiro 				/* Must be an error */
127540266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
1276605302a5SGregory Neil Shapiro 				SM_LDAP_ERROR_CLEANUP();
127740266059SGregory Neil Shapiro 				errno = save_errno;
127840266059SGregory Neil Shapiro 				return EX_TEMPFAIL;
127940266059SGregory Neil Shapiro 			}
128040266059SGregory Neil Shapiro 
1281605302a5SGregory Neil Shapiro 			/* mark this DN as done */
1282605302a5SGregory Neil Shapiro 			rl->lr_done = true;
1283e92d3f3fSGregory Neil Shapiro 			if (rl->lr_ludp != NULL)
1284e92d3f3fSGregory Neil Shapiro 			{
1285e92d3f3fSGregory Neil Shapiro 				ldap_free_urldesc(rl->lr_ludp);
1286e92d3f3fSGregory Neil Shapiro 				rl->lr_ludp = NULL;
1287e92d3f3fSGregory Neil Shapiro 			}
1288e92d3f3fSGregory Neil Shapiro 			if (rl->lr_attrs != NULL)
1289e92d3f3fSGregory Neil Shapiro 			{
1290e92d3f3fSGregory Neil Shapiro 				free(rl->lr_attrs);
1291e92d3f3fSGregory Neil Shapiro 				rl->lr_attrs = NULL;
1292e92d3f3fSGregory Neil Shapiro 			}
1293605302a5SGregory Neil Shapiro 
129440266059SGregory Neil Shapiro 			/* We don't want multiple values and we have one */
129513d88268SGregory Neil Shapiro 			if ((char) delim == '\0' &&
129613d88268SGregory Neil Shapiro 			    !bitset(SM_LDAP_SINGLEMATCH, flags) &&
129713d88268SGregory Neil Shapiro 			    *result != NULL)
129840266059SGregory Neil Shapiro 				break;
129940266059SGregory Neil Shapiro 		}
130040266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
130140266059SGregory Neil Shapiro 		if (save_errno != LDAP_SUCCESS &&
130240266059SGregory Neil Shapiro 		    save_errno != LDAP_DECODING_ERROR)
130340266059SGregory Neil Shapiro 		{
130440266059SGregory Neil Shapiro 			/* Must be an error */
130540266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
1306605302a5SGregory Neil Shapiro 			SM_LDAP_ERROR_CLEANUP();
130740266059SGregory Neil Shapiro 			errno = save_errno;
130840266059SGregory Neil Shapiro 			return EX_TEMPFAIL;
130940266059SGregory Neil Shapiro 		}
131040266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
131140266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
131240266059SGregory Neil Shapiro 	}
131340266059SGregory Neil Shapiro 
131440266059SGregory Neil Shapiro 	if (ret == 0)
131540266059SGregory Neil Shapiro 		save_errno = ETIMEDOUT;
13166f9c8e5bSGregory Neil Shapiro 	else if (ret == LDAP_RES_SEARCH_RESULT)
13179bd497b8SGregory Neil Shapiro 	{
13189bd497b8SGregory Neil Shapiro 		/*
13199bd497b8SGregory Neil Shapiro 		**  We may have gotten an LDAP_RES_SEARCH_RESULT response
13209bd497b8SGregory Neil Shapiro 		**  with an error inside it, so we have to extract that
13219bd497b8SGregory Neil Shapiro 		**  with ldap_parse_result().  This can happen when talking
13229bd497b8SGregory Neil Shapiro 		**  to an LDAP proxy whose backend has gone down.
13239bd497b8SGregory Neil Shapiro 		*/
13249bd497b8SGregory Neil Shapiro 
13256f9c8e5bSGregory Neil Shapiro 		if (lmap->ldap_res == NULL)
13266f9c8e5bSGregory Neil Shapiro 			save_errno = LDAP_UNAVAILABLE;
13276f9c8e5bSGregory Neil Shapiro 		else
13286f9c8e5bSGregory Neil Shapiro 		{
13296f9c8e5bSGregory Neil Shapiro 			int rc;
13306f9c8e5bSGregory Neil Shapiro 
13316f9c8e5bSGregory Neil Shapiro 			save_errno = ldap_parse_result(lmap->ldap_ld,
13326f9c8e5bSGregory Neil Shapiro 					lmap->ldap_res, &rc, NULL, NULL,
13336f9c8e5bSGregory Neil Shapiro 					NULL, NULL, 0);
13349bd497b8SGregory Neil Shapiro 			if (save_errno == LDAP_SUCCESS)
13359bd497b8SGregory Neil Shapiro 				save_errno = rc;
13369bd497b8SGregory Neil Shapiro 		}
13376f9c8e5bSGregory Neil Shapiro 	}
13386f9c8e5bSGregory Neil Shapiro 	else
13396f9c8e5bSGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
134040266059SGregory Neil Shapiro 	if (save_errno != LDAP_SUCCESS)
134140266059SGregory Neil Shapiro 	{
134240266059SGregory Neil Shapiro 		statp = EX_TEMPFAIL;
134340266059SGregory Neil Shapiro 		switch (save_errno)
134440266059SGregory Neil Shapiro 		{
134540266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
134640266059SGregory Neil Shapiro 		  case LDAP_SERVER_DOWN:
134740266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
134840266059SGregory Neil Shapiro 		  case LDAP_TIMEOUT:
1349ffb83623SGregory Neil Shapiro 		  case ETIMEDOUT:
135040266059SGregory Neil Shapiro 		  case LDAP_UNAVAILABLE:
1351605302a5SGregory Neil Shapiro 
1352605302a5SGregory Neil Shapiro 			/*
1353605302a5SGregory Neil Shapiro 			**  server disappeared,
1354605302a5SGregory Neil Shapiro 			**  try reopen on next search
1355605302a5SGregory Neil Shapiro 			*/
1356605302a5SGregory Neil Shapiro 
135740266059SGregory Neil Shapiro 			statp = EX_RESTART;
135840266059SGregory Neil Shapiro 			break;
135940266059SGregory Neil Shapiro 		}
1360ffb83623SGregory Neil Shapiro 		if (ret != 0)
136140266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
1362605302a5SGregory Neil Shapiro 		SM_LDAP_ERROR_CLEANUP();
136340266059SGregory Neil Shapiro 		errno = save_errno;
136440266059SGregory Neil Shapiro 		return statp;
136540266059SGregory Neil Shapiro 	}
136640266059SGregory Neil Shapiro 
136740266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)
136840266059SGregory Neil Shapiro 	{
136940266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
137040266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
137140266059SGregory Neil Shapiro 	}
137240266059SGregory Neil Shapiro 
137340266059SGregory Neil Shapiro 	if (toplevel)
137440266059SGregory Neil Shapiro 	{
1375605302a5SGregory Neil Shapiro 		int rlidx;
137640266059SGregory Neil Shapiro 
137740266059SGregory Neil Shapiro 		/*
137840266059SGregory Neil Shapiro 		**  Spin through the built-up recurse list at the top
137940266059SGregory Neil Shapiro 		**  of the recursion.  Since new items are added at the
138040266059SGregory Neil Shapiro 		**  end of the shared list, we actually only ever get
138140266059SGregory Neil Shapiro 		**  one level of recursion before things pop back to the
138240266059SGregory Neil Shapiro 		**  top.  Any items added to the list during that recursion
138340266059SGregory Neil Shapiro 		**  will be expanded by the top level.
138440266059SGregory Neil Shapiro 		*/
138540266059SGregory Neil Shapiro 
1386d0cef73dSGregory Neil Shapiro 		for (rlidx = 0; recurse != NULL && rlidx < recurse->lrl_cnt;
1387d0cef73dSGregory Neil Shapiro 		     rlidx++)
138840266059SGregory Neil Shapiro 		{
1389605302a5SGregory Neil Shapiro 			int newflags;
139040266059SGregory Neil Shapiro 			int sid;
139140266059SGregory Neil Shapiro 			int status;
139240266059SGregory Neil Shapiro 
1393d0cef73dSGregory Neil Shapiro 			rl = recurse->lrl_data[rlidx];
1394605302a5SGregory Neil Shapiro 
1395605302a5SGregory Neil Shapiro 			newflags = flags;
1396605302a5SGregory Neil Shapiro 			if (rl->lr_done)
139740266059SGregory Neil Shapiro 			{
139840266059SGregory Neil Shapiro 				/* already expanded */
139940266059SGregory Neil Shapiro 				continue;
140040266059SGregory Neil Shapiro 			}
1401605302a5SGregory Neil Shapiro 
1402605302a5SGregory Neil Shapiro 			if (rl->lr_type == SM_LDAP_ATTR_DN)
140340266059SGregory Neil Shapiro 			{
140440266059SGregory Neil Shapiro 				/* do DN search */
140540266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
140640266059SGregory Neil Shapiro 						  rl->lr_search,
140740266059SGregory Neil Shapiro 						  lmap->ldap_scope,
140840266059SGregory Neil Shapiro 						  "(objectClass=*)",
1409605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1410605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
141140266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
141240266059SGregory Neil Shapiro 			}
1413605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_FILTER)
141440266059SGregory Neil Shapiro 			{
141540266059SGregory Neil Shapiro 				/* do new search */
141640266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
141740266059SGregory Neil Shapiro 						  lmap->ldap_base,
141840266059SGregory Neil Shapiro 						  lmap->ldap_scope,
141940266059SGregory Neil Shapiro 						  rl->lr_search,
1420605302a5SGregory Neil Shapiro 						  (lmap->ldap_attr[0] == NULL ?
1421605302a5SGregory Neil Shapiro 						   NULL : lmap->ldap_attr),
142240266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
142340266059SGregory Neil Shapiro 			}
1424605302a5SGregory Neil Shapiro 			else if (rl->lr_type == SM_LDAP_ATTR_URL)
142540266059SGregory Neil Shapiro 			{
1426e92d3f3fSGregory Neil Shapiro 				/* Parse URL */
1427e92d3f3fSGregory Neil Shapiro 				sid = ldap_url_parse(rl->lr_search,
1428e92d3f3fSGregory Neil Shapiro 						     &rl->lr_ludp);
1429e92d3f3fSGregory Neil Shapiro 
1430e92d3f3fSGregory Neil Shapiro 				if (sid != 0)
1431e92d3f3fSGregory Neil Shapiro 				{
1432e92d3f3fSGregory Neil Shapiro 					errno = sid + E_LDAPURLBASE;
1433e92d3f3fSGregory Neil Shapiro 					return EX_TEMPFAIL;
1434e92d3f3fSGregory Neil Shapiro 				}
1435e92d3f3fSGregory Neil Shapiro 
1436e92d3f3fSGregory Neil Shapiro 				/* We need to add objectClass */
1437e92d3f3fSGregory Neil Shapiro 				if (rl->lr_ludp->lud_attrs != NULL)
1438e92d3f3fSGregory Neil Shapiro 				{
1439e92d3f3fSGregory Neil Shapiro 					int attrnum = 0;
1440e92d3f3fSGregory Neil Shapiro 
1441e92d3f3fSGregory Neil Shapiro 					while (rl->lr_ludp->lud_attrs[attrnum] != NULL)
1442e92d3f3fSGregory Neil Shapiro 					{
1443e92d3f3fSGregory Neil Shapiro 						if (strcasecmp(rl->lr_ludp->lud_attrs[attrnum],
1444e92d3f3fSGregory Neil Shapiro 							       "objectClass") == 0)
1445e92d3f3fSGregory Neil Shapiro 						{
1446e92d3f3fSGregory Neil Shapiro 							/* already requested */
1447e92d3f3fSGregory Neil Shapiro 							attrnum = -1;
1448e92d3f3fSGregory Neil Shapiro 							break;
1449e92d3f3fSGregory Neil Shapiro 						}
1450e92d3f3fSGregory Neil Shapiro 						attrnum++;
1451e92d3f3fSGregory Neil Shapiro 					}
1452e92d3f3fSGregory Neil Shapiro 
1453e92d3f3fSGregory Neil Shapiro 					if (attrnum >= 0)
1454e92d3f3fSGregory Neil Shapiro 					{
1455e92d3f3fSGregory Neil Shapiro 						int i;
1456e92d3f3fSGregory Neil Shapiro 
1457e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs = (char **)malloc(sizeof(char *) * (attrnum + 2));
1458e92d3f3fSGregory Neil Shapiro 						if (rl->lr_attrs == NULL)
1459e92d3f3fSGregory Neil Shapiro 						{
1460e92d3f3fSGregory Neil Shapiro 							save_errno = errno;
1461e92d3f3fSGregory Neil Shapiro 							ldap_free_urldesc(rl->lr_ludp);
1462e92d3f3fSGregory Neil Shapiro 							errno = save_errno;
1463e92d3f3fSGregory Neil Shapiro 							return EX_TEMPFAIL;
1464e92d3f3fSGregory Neil Shapiro 						}
1465e92d3f3fSGregory Neil Shapiro 						for (i = 0 ; i < attrnum; i++)
1466e92d3f3fSGregory Neil Shapiro 						{
1467e92d3f3fSGregory Neil Shapiro 							rl->lr_attrs[i] = rl->lr_ludp->lud_attrs[i];
1468e92d3f3fSGregory Neil Shapiro 						}
1469e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs[i++] = "objectClass";
1470e92d3f3fSGregory Neil Shapiro 						rl->lr_attrs[i++] = NULL;
1471e92d3f3fSGregory Neil Shapiro 					}
1472e92d3f3fSGregory Neil Shapiro 				}
1473e92d3f3fSGregory Neil Shapiro 
1474e92d3f3fSGregory Neil Shapiro 				/*
1475e92d3f3fSGregory Neil Shapiro 				**  Use the existing connection
1476e92d3f3fSGregory Neil Shapiro 				**  for this search.  It really
1477e92d3f3fSGregory Neil Shapiro 				**  should use lud_scheme://lud_host:lud_port/
1478e92d3f3fSGregory Neil Shapiro 				**  instead but that would require
1479e92d3f3fSGregory Neil Shapiro 				**  opening a new connection.
1480e92d3f3fSGregory Neil Shapiro 				**  This should be fixed ASAP.
1481e92d3f3fSGregory Neil Shapiro 				*/
1482e92d3f3fSGregory Neil Shapiro 
1483e92d3f3fSGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
1484e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_dn,
1485e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_scope,
1486e92d3f3fSGregory Neil Shapiro 						  rl->lr_ludp->lud_filter,
1487e92d3f3fSGregory Neil Shapiro 						  rl->lr_attrs,
148840266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
1489e92d3f3fSGregory Neil Shapiro 
1490e92d3f3fSGregory Neil Shapiro 				/* Use the attributes specified by URL */
1491605302a5SGregory Neil Shapiro 				newflags |= SM_LDAP_USE_ALLATTR;
149240266059SGregory Neil Shapiro 			}
149340266059SGregory Neil Shapiro 			else
149440266059SGregory Neil Shapiro 			{
149540266059SGregory Neil Shapiro 				/* unknown or illegal attribute type */
149640266059SGregory Neil Shapiro 				errno = EFAULT;
149740266059SGregory Neil Shapiro 				return EX_SOFTWARE;
149840266059SGregory Neil Shapiro 			}
149940266059SGregory Neil Shapiro 
150040266059SGregory Neil Shapiro 			/* Collect results */
150140266059SGregory Neil Shapiro 			if (sid == -1)
150240266059SGregory Neil Shapiro 			{
150340266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
150440266059SGregory Neil Shapiro 				statp = EX_TEMPFAIL;
150540266059SGregory Neil Shapiro 				switch (save_errno)
150640266059SGregory Neil Shapiro 				{
150740266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
150840266059SGregory Neil Shapiro 				  case LDAP_SERVER_DOWN:
150940266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
151040266059SGregory Neil Shapiro 				  case LDAP_TIMEOUT:
1511ffb83623SGregory Neil Shapiro 				  case ETIMEDOUT:
151240266059SGregory Neil Shapiro 				  case LDAP_UNAVAILABLE:
1513605302a5SGregory Neil Shapiro 
1514605302a5SGregory Neil Shapiro 					/*
1515605302a5SGregory Neil Shapiro 					**  server disappeared,
1516605302a5SGregory Neil Shapiro 					**  try reopen on next search
1517605302a5SGregory Neil Shapiro 					*/
1518605302a5SGregory Neil Shapiro 
151940266059SGregory Neil Shapiro 					statp = EX_RESTART;
152040266059SGregory Neil Shapiro 					break;
152140266059SGregory Neil Shapiro 				}
152240266059SGregory Neil Shapiro 				errno = save_errno + E_LDAPBASE;
152340266059SGregory Neil Shapiro 				return statp;
152440266059SGregory Neil Shapiro 			}
152540266059SGregory Neil Shapiro 
1526605302a5SGregory Neil Shapiro 			status = sm_ldap_results(lmap, sid, newflags, delim,
1527605302a5SGregory Neil Shapiro 						 rpool, result, resultln,
1528605302a5SGregory Neil Shapiro 						 resultsz, recurse);
152940266059SGregory Neil Shapiro 			save_errno = errno;
153040266059SGregory Neil Shapiro 			if (status != EX_OK && status != EX_NOTFOUND)
153140266059SGregory Neil Shapiro 			{
153240266059SGregory Neil Shapiro 				errno = save_errno;
153340266059SGregory Neil Shapiro 				return status;
153440266059SGregory Neil Shapiro 			}
153540266059SGregory Neil Shapiro 
153640266059SGregory Neil Shapiro 			/* Mark as done */
1537605302a5SGregory Neil Shapiro 			rl->lr_done = true;
1538e92d3f3fSGregory Neil Shapiro 			if (rl->lr_ludp != NULL)
1539e92d3f3fSGregory Neil Shapiro 			{
1540e92d3f3fSGregory Neil Shapiro 				ldap_free_urldesc(rl->lr_ludp);
1541e92d3f3fSGregory Neil Shapiro 				rl->lr_ludp = NULL;
1542e92d3f3fSGregory Neil Shapiro 			}
1543e92d3f3fSGregory Neil Shapiro 			if (rl->lr_attrs != NULL)
1544e92d3f3fSGregory Neil Shapiro 			{
1545e92d3f3fSGregory Neil Shapiro 				free(rl->lr_attrs);
1546e92d3f3fSGregory Neil Shapiro 				rl->lr_attrs = NULL;
1547e92d3f3fSGregory Neil Shapiro 			}
1548605302a5SGregory Neil Shapiro 
1549605302a5SGregory Neil Shapiro 			/* Reset rlidx as new items may have been added */
1550605302a5SGregory Neil Shapiro 			rlidx = -1;
155140266059SGregory Neil Shapiro 		}
155240266059SGregory Neil Shapiro 	}
155340266059SGregory Neil Shapiro 	return statp;
155440266059SGregory Neil Shapiro }
155540266059SGregory Neil Shapiro 
155640266059SGregory Neil Shapiro /*
155740266059SGregory Neil Shapiro **  SM_LDAP_CLOSE -- close LDAP connection
155840266059SGregory Neil Shapiro **
155940266059SGregory Neil Shapiro **	Parameters:
156040266059SGregory Neil Shapiro **		lmap -- LDAP map information
156140266059SGregory Neil Shapiro **
156240266059SGregory Neil Shapiro **	Returns:
156340266059SGregory Neil Shapiro **		None.
156440266059SGregory Neil Shapiro **
156540266059SGregory Neil Shapiro */
156640266059SGregory Neil Shapiro 
156740266059SGregory Neil Shapiro void
156840266059SGregory Neil Shapiro sm_ldap_close(lmap)
156940266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
157040266059SGregory Neil Shapiro {
157140266059SGregory Neil Shapiro 	if (lmap->ldap_ld == NULL)
157240266059SGregory Neil Shapiro 		return;
157340266059SGregory Neil Shapiro 
157440266059SGregory Neil Shapiro 	if (lmap->ldap_pid == getpid())
157540266059SGregory Neil Shapiro 		ldap_unbind(lmap->ldap_ld);
157640266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
157740266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
157840266059SGregory Neil Shapiro }
157940266059SGregory Neil Shapiro /*
158040266059SGregory Neil Shapiro **  SM_LDAP_GETERRNO -- get ldap errno value
158140266059SGregory Neil Shapiro **
158240266059SGregory Neil Shapiro **	Parameters:
158340266059SGregory Neil Shapiro **		ld -- LDAP session handle
158440266059SGregory Neil Shapiro **
158540266059SGregory Neil Shapiro **	Returns:
158640266059SGregory Neil Shapiro **		LDAP errno.
158740266059SGregory Neil Shapiro **
158840266059SGregory Neil Shapiro */
158940266059SGregory Neil Shapiro 
159040266059SGregory Neil Shapiro int
159140266059SGregory Neil Shapiro sm_ldap_geterrno(ld)
159240266059SGregory Neil Shapiro 	LDAP *ld;
159340266059SGregory Neil Shapiro {
159440266059SGregory Neil Shapiro 	int err = LDAP_SUCCESS;
159540266059SGregory Neil Shapiro 
159640266059SGregory Neil Shapiro # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
1597*5b0945b5SGregory Neil Shapiro #  ifdef LDAP_OPT_RESULT_CODE
1598*5b0945b5SGregory Neil Shapiro #   define LDAP_GET_RESULT_CODE LDAP_OPT_RESULT_CODE
1599*5b0945b5SGregory Neil Shapiro #  else
1600*5b0945b5SGregory Neil Shapiro #   define LDAP_GET_RESULT_CODE LDAP_OPT_ERROR_NUMBER
1601*5b0945b5SGregory Neil Shapiro #  endif
1602*5b0945b5SGregory Neil Shapiro 	(void) ldap_get_option(ld, LDAP_GET_RESULT_CODE, &err);
1603*5b0945b5SGregory Neil Shapiro # else
160440266059SGregory Neil Shapiro #  ifdef LDAP_OPT_SIZELIMIT
160540266059SGregory Neil Shapiro 	err = ldap_get_lderrno(ld, NULL, NULL);
1606*5b0945b5SGregory Neil Shapiro #  else
160740266059SGregory Neil Shapiro 	err = ld->ld_errno;
160840266059SGregory Neil Shapiro 
160940266059SGregory Neil Shapiro 	/*
161040266059SGregory Neil Shapiro 	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
161140266059SGregory Neil Shapiro 	**  OpenLDAP 1.X's hack (see above)
161240266059SGregory Neil Shapiro 	*/
161340266059SGregory Neil Shapiro 
161440266059SGregory Neil Shapiro 	ld->ld_errno = LDAP_SUCCESS;
161540266059SGregory Neil Shapiro #  endif /* LDAP_OPT_SIZELIMIT */
161640266059SGregory Neil Shapiro # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
161740266059SGregory Neil Shapiro 	return err;
161840266059SGregory Neil Shapiro }
161940266059SGregory Neil Shapiro # endif /* LDAPMAP */
1620