xref: /freebsd/contrib/sendmail/libsm/ldap.c (revision 4026605903c0ab8df33c4ae8c419acdb2b652af8)
140266059SGregory Neil Shapiro /*
240266059SGregory Neil Shapiro  * Copyright (c) 2001-2002 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>
1140266059SGregory Neil Shapiro SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")
1240266059SGregory Neil Shapiro 
1340266059SGregory Neil Shapiro #if LDAPMAP
1440266059SGregory Neil Shapiro # include <sys/types.h>
1540266059SGregory Neil Shapiro # include <errno.h>
1640266059SGregory Neil Shapiro # include <setjmp.h>
1740266059SGregory Neil Shapiro # include <stdlib.h>
1840266059SGregory Neil Shapiro # include <unistd.h>
1940266059SGregory Neil Shapiro 
2040266059SGregory Neil Shapiro # include <sm/bitops.h>
2140266059SGregory Neil Shapiro # include <sm/clock.h>
2240266059SGregory Neil Shapiro # include <sm/conf.h>
2340266059SGregory Neil Shapiro # include <sm/debug.h>
2440266059SGregory Neil Shapiro # include <sm/errstring.h>
2540266059SGregory Neil Shapiro # include <sm/ldap.h>
2640266059SGregory Neil Shapiro # include <sm/string.h>
2740266059SGregory Neil Shapiro # include <sm/sysexits.h>
2840266059SGregory Neil Shapiro 
2940266059SGregory Neil Shapiro SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
3040266059SGregory Neil Shapiro 	"@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
3140266059SGregory Neil Shapiro 
3240266059SGregory Neil Shapiro static void	ldaptimeout __P((int));
3340266059SGregory Neil Shapiro 
3440266059SGregory Neil Shapiro /*
3540266059SGregory Neil Shapiro **  SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
3640266059SGregory Neil Shapiro **
3740266059SGregory Neil Shapiro **	Parameters:
3840266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT to clear
3940266059SGregory Neil Shapiro **
4040266059SGregory Neil Shapiro **	Returns:
4140266059SGregory Neil Shapiro **		None.
4240266059SGregory Neil Shapiro **
4340266059SGregory Neil Shapiro */
4440266059SGregory Neil Shapiro 
4540266059SGregory Neil Shapiro void
4640266059SGregory Neil Shapiro sm_ldap_clear(lmap)
4740266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
4840266059SGregory Neil Shapiro {
4940266059SGregory Neil Shapiro 	if (lmap == NULL)
5040266059SGregory Neil Shapiro 		return;
5140266059SGregory Neil Shapiro 
5240266059SGregory Neil Shapiro 	lmap->ldap_host = NULL;
5340266059SGregory Neil Shapiro 	lmap->ldap_port = LDAP_PORT;
5440266059SGregory Neil Shapiro 	lmap->ldap_deref = LDAP_DEREF_NEVER;
5540266059SGregory Neil Shapiro 	lmap->ldap_timelimit = LDAP_NO_LIMIT;
5640266059SGregory Neil Shapiro 	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
5740266059SGregory Neil Shapiro # ifdef LDAP_REFERRALS
5840266059SGregory Neil Shapiro 	lmap->ldap_options = LDAP_OPT_REFERRALS;
5940266059SGregory Neil Shapiro # else /* LDAP_REFERRALS */
6040266059SGregory Neil Shapiro 	lmap->ldap_options = 0;
6140266059SGregory Neil Shapiro # endif /* LDAP_REFERRALS */
6240266059SGregory Neil Shapiro 	lmap->ldap_attrsep = '\0';
6340266059SGregory Neil Shapiro 	lmap->ldap_binddn = NULL;
6440266059SGregory Neil Shapiro 	lmap->ldap_secret = NULL;
6540266059SGregory Neil Shapiro 	lmap->ldap_method = LDAP_AUTH_SIMPLE;
6640266059SGregory Neil Shapiro 	lmap->ldap_base = NULL;
6740266059SGregory Neil Shapiro 	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
6840266059SGregory Neil Shapiro 	lmap->ldap_attrsonly = LDAPMAP_FALSE;
6940266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_sec = 0;
7040266059SGregory Neil Shapiro 	lmap->ldap_timeout.tv_usec = 0;
7140266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
7240266059SGregory Neil Shapiro 	lmap->ldap_filter = NULL;
7340266059SGregory Neil Shapiro 	lmap->ldap_attr[0] = NULL;
7440266059SGregory Neil Shapiro #if _FFR_LDAP_RECURSION
7540266059SGregory Neil Shapiro 	lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL;
7640266059SGregory Neil Shapiro 	lmap->ldap_attr_final[0] = NULL;
7740266059SGregory Neil Shapiro #endif /* _FFR_LDAP_RECURSION */
7840266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
7940266059SGregory Neil Shapiro 	lmap->ldap_next = NULL;
8040266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
8140266059SGregory Neil Shapiro }
8240266059SGregory Neil Shapiro 
8340266059SGregory Neil Shapiro /*
8440266059SGregory Neil Shapiro **  SM_LDAP_START -- actually connect to an LDAP server
8540266059SGregory Neil Shapiro **
8640266059SGregory Neil Shapiro **	Parameters:
8740266059SGregory Neil Shapiro **		name -- name of map for debug output.
8840266059SGregory Neil Shapiro **		lmap -- the LDAP map being opened.
8940266059SGregory Neil Shapiro **
9040266059SGregory Neil Shapiro **	Returns:
9140266059SGregory Neil Shapiro **		true if connection is successful, false otherwise.
9240266059SGregory Neil Shapiro **
9340266059SGregory Neil Shapiro **	Side Effects:
9440266059SGregory Neil Shapiro **		Populates lmap->ldap_ld.
9540266059SGregory Neil Shapiro */
9640266059SGregory Neil Shapiro 
9740266059SGregory Neil Shapiro static jmp_buf	LDAPTimeout;
9840266059SGregory Neil Shapiro 
9940266059SGregory Neil Shapiro #define SM_LDAP_SETTIMEOUT(to)						\
10040266059SGregory Neil Shapiro do									\
10140266059SGregory Neil Shapiro {									\
10240266059SGregory Neil Shapiro 	if (to != 0)							\
10340266059SGregory Neil Shapiro 	{								\
10440266059SGregory Neil Shapiro 		if (setjmp(LDAPTimeout) != 0)				\
10540266059SGregory Neil Shapiro 		{							\
10640266059SGregory Neil Shapiro 			errno = ETIMEDOUT;				\
10740266059SGregory Neil Shapiro 			return false;					\
10840266059SGregory Neil Shapiro 		}							\
10940266059SGregory Neil Shapiro 		ev = sm_setevent(to, ldaptimeout, 0);			\
11040266059SGregory Neil Shapiro 	}								\
11140266059SGregory Neil Shapiro } while (0)
11240266059SGregory Neil Shapiro 
11340266059SGregory Neil Shapiro #define SM_LDAP_CLEARTIMEOUT()						\
11440266059SGregory Neil Shapiro do									\
11540266059SGregory Neil Shapiro {									\
11640266059SGregory Neil Shapiro 	if (ev != NULL)							\
11740266059SGregory Neil Shapiro 		sm_clrevent(ev);					\
11840266059SGregory Neil Shapiro } while (0)
11940266059SGregory Neil Shapiro 
12040266059SGregory Neil Shapiro bool
12140266059SGregory Neil Shapiro sm_ldap_start(name, lmap)
12240266059SGregory Neil Shapiro 	char *name;
12340266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
12440266059SGregory Neil Shapiro {
12540266059SGregory Neil Shapiro 	int bind_result;
12640266059SGregory Neil Shapiro 	int save_errno;
12740266059SGregory Neil Shapiro 	SM_EVENT *ev = NULL;
12840266059SGregory Neil Shapiro 	LDAP *ld;
12940266059SGregory Neil Shapiro 
13040266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 2))
13140266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
13240266059SGregory Neil Shapiro 
13340266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 9))
13440266059SGregory Neil Shapiro 		sm_dprintf("ldapmap_start(%s, %d)\n",
13540266059SGregory Neil Shapiro 			   lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
13640266059SGregory Neil Shapiro 			   lmap->ldap_port);
13740266059SGregory Neil Shapiro 
13840266059SGregory Neil Shapiro # if USE_LDAP_INIT
13940266059SGregory Neil Shapiro 	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
14040266059SGregory Neil Shapiro 	save_errno = errno;
14140266059SGregory Neil Shapiro # else /* USE_LDAP_INIT */
14240266059SGregory Neil Shapiro 	/*
14340266059SGregory Neil Shapiro 	**  If using ldap_open(), the actual connection to the server
14440266059SGregory Neil Shapiro 	**  happens now so we need the timeout here.  For ldap_init(),
14540266059SGregory Neil Shapiro 	**  the connection happens at bind time.
14640266059SGregory Neil Shapiro 	*/
14740266059SGregory Neil Shapiro 
14840266059SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
14940266059SGregory Neil Shapiro 	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
15040266059SGregory Neil Shapiro 	save_errno = errno;
15140266059SGregory Neil Shapiro 
15240266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
15340266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
15440266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
15540266059SGregory Neil Shapiro 
15640266059SGregory Neil Shapiro 	errno = save_errno;
15740266059SGregory Neil Shapiro 	if (ld == NULL)
15840266059SGregory Neil Shapiro 		return false;
15940266059SGregory Neil Shapiro 
16040266059SGregory Neil Shapiro 	sm_ldap_setopts(ld, lmap);
16140266059SGregory Neil Shapiro 
16240266059SGregory Neil Shapiro # if USE_LDAP_INIT
16340266059SGregory Neil Shapiro 	/*
16440266059SGregory Neil Shapiro 	**  If using ldap_init(), the actual connection to the server
16540266059SGregory Neil Shapiro 	**  happens at ldap_bind_s() so we need the timeout here.
16640266059SGregory Neil Shapiro 	*/
16740266059SGregory Neil Shapiro 
16840266059SGregory Neil Shapiro 	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
16940266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
17040266059SGregory Neil Shapiro 
17140266059SGregory Neil Shapiro # ifdef LDAP_AUTH_KRBV4
17240266059SGregory Neil Shapiro 	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
17340266059SGregory Neil Shapiro 	    lmap->ldap_secret != NULL)
17440266059SGregory Neil Shapiro 	{
17540266059SGregory Neil Shapiro 		/*
17640266059SGregory Neil Shapiro 		**  Need to put ticket in environment here instead of
17740266059SGregory Neil Shapiro 		**  during parseargs as there may be different tickets
17840266059SGregory Neil Shapiro 		**  for different LDAP connections.
17940266059SGregory Neil Shapiro 		*/
18040266059SGregory Neil Shapiro 
18140266059SGregory Neil Shapiro 		(void) putenv(lmap->ldap_secret);
18240266059SGregory Neil Shapiro 	}
18340266059SGregory Neil Shapiro # endif /* LDAP_AUTH_KRBV4 */
18440266059SGregory Neil Shapiro 
18540266059SGregory Neil Shapiro 	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
18640266059SGregory Neil Shapiro 				  lmap->ldap_secret, lmap->ldap_method);
18740266059SGregory Neil Shapiro 
18840266059SGregory Neil Shapiro # if USE_LDAP_INIT
18940266059SGregory Neil Shapiro 	/* clear the event if it has not sprung */
19040266059SGregory Neil Shapiro 	SM_LDAP_CLEARTIMEOUT();
19140266059SGregory Neil Shapiro # endif /* USE_LDAP_INIT */
19240266059SGregory Neil Shapiro 
19340266059SGregory Neil Shapiro 	if (bind_result != LDAP_SUCCESS)
19440266059SGregory Neil Shapiro 	{
19540266059SGregory Neil Shapiro 		errno = bind_result + E_LDAPBASE;
19640266059SGregory Neil Shapiro 		return false;
19740266059SGregory Neil Shapiro 	}
19840266059SGregory Neil Shapiro 
19940266059SGregory Neil Shapiro 	/* Save PID to make sure only this PID closes the LDAP connection */
20040266059SGregory Neil Shapiro 	lmap->ldap_pid = getpid();
20140266059SGregory Neil Shapiro 	lmap->ldap_ld = ld;
20240266059SGregory Neil Shapiro 	return true;
20340266059SGregory Neil Shapiro }
20440266059SGregory Neil Shapiro 
20540266059SGregory Neil Shapiro /* ARGSUSED */
20640266059SGregory Neil Shapiro static void
20740266059SGregory Neil Shapiro ldaptimeout(unused)
20840266059SGregory Neil Shapiro 	int unused;
20940266059SGregory Neil Shapiro {
21040266059SGregory Neil Shapiro 	/*
21140266059SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
21240266059SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
21340266059SGregory Neil Shapiro 	**	DOING.
21440266059SGregory Neil Shapiro 	*/
21540266059SGregory Neil Shapiro 
21640266059SGregory Neil Shapiro 	errno = ETIMEDOUT;
21740266059SGregory Neil Shapiro 	longjmp(LDAPTimeout, 1);
21840266059SGregory Neil Shapiro }
21940266059SGregory Neil Shapiro 
22040266059SGregory Neil Shapiro /*
22140266059SGregory Neil Shapiro **  SM_LDAP_SEARCH -- iniate LDAP search
22240266059SGregory Neil Shapiro **
22340266059SGregory Neil Shapiro **	Initiate an LDAP search, return the msgid.
22440266059SGregory Neil Shapiro **	The calling function must collect the results.
22540266059SGregory Neil Shapiro **
22640266059SGregory Neil Shapiro **	Parameters:
22740266059SGregory Neil Shapiro **		lmap -- LDAP map information
22840266059SGregory Neil Shapiro **		key -- key to substitute in LDAP filter
22940266059SGregory Neil Shapiro **
23040266059SGregory Neil Shapiro **	Returns:
23140266059SGregory Neil Shapiro **		-1 on failure, msgid on success
23240266059SGregory Neil Shapiro **
23340266059SGregory Neil Shapiro */
23440266059SGregory Neil Shapiro 
23540266059SGregory Neil Shapiro int
23640266059SGregory Neil Shapiro sm_ldap_search(lmap, key)
23740266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
23840266059SGregory Neil Shapiro 	char *key;
23940266059SGregory Neil Shapiro {
24040266059SGregory Neil Shapiro 	int msgid;
24140266059SGregory Neil Shapiro 	char *fp, *p, *q;
24240266059SGregory Neil Shapiro 	char filter[LDAPMAP_MAX_FILTER + 1];
24340266059SGregory Neil Shapiro 
24440266059SGregory Neil Shapiro 	/* substitute key into filter, perhaps multiple times */
24540266059SGregory Neil Shapiro 	memset(filter, '\0', sizeof filter);
24640266059SGregory Neil Shapiro 	fp = filter;
24740266059SGregory Neil Shapiro 	p = lmap->ldap_filter;
24840266059SGregory Neil Shapiro 	while ((q = strchr(p, '%')) != NULL)
24940266059SGregory Neil Shapiro 	{
25040266059SGregory Neil Shapiro 		if (q[1] == 's')
25140266059SGregory Neil Shapiro 		{
25240266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
25340266059SGregory Neil Shapiro 					   "%.*s%s", (int) (q - p), p, key);
25440266059SGregory Neil Shapiro 			fp += strlen(fp);
25540266059SGregory Neil Shapiro 			p = q + 2;
25640266059SGregory Neil Shapiro 		}
25740266059SGregory Neil Shapiro 		else if (q[1] == '0')
25840266059SGregory Neil Shapiro 		{
25940266059SGregory Neil Shapiro 			char *k = key;
26040266059SGregory Neil Shapiro 
26140266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
26240266059SGregory Neil Shapiro 					   "%.*s", (int) (q - p), p);
26340266059SGregory Neil Shapiro 			fp += strlen(fp);
26440266059SGregory Neil Shapiro 			p = q + 2;
26540266059SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro 			/* Properly escape LDAP special characters */
26740266059SGregory Neil Shapiro 			while (SPACELEFT(filter, fp) > 0 &&
26840266059SGregory Neil Shapiro 			       *k != '\0')
26940266059SGregory Neil Shapiro 			{
27040266059SGregory Neil Shapiro 				if (*k == '*' || *k == '(' ||
27140266059SGregory Neil Shapiro 				    *k == ')' || *k == '\\')
27240266059SGregory Neil Shapiro 				{
27340266059SGregory Neil Shapiro 					(void) sm_strlcat(fp,
27440266059SGregory Neil Shapiro 						       (*k == '*' ? "\\2A" :
27540266059SGregory Neil Shapiro 							(*k == '(' ? "\\28" :
27640266059SGregory Neil Shapiro 							 (*k == ')' ? "\\29" :
27740266059SGregory Neil Shapiro 							  (*k == '\\' ? "\\5C" :
27840266059SGregory Neil Shapiro 							   "\00")))),
27940266059SGregory Neil Shapiro 						SPACELEFT(filter, fp));
28040266059SGregory Neil Shapiro 					fp += strlen(fp);
28140266059SGregory Neil Shapiro 					k++;
28240266059SGregory Neil Shapiro 				}
28340266059SGregory Neil Shapiro 				else
28440266059SGregory Neil Shapiro 					*fp++ = *k++;
28540266059SGregory Neil Shapiro 			}
28640266059SGregory Neil Shapiro 		}
28740266059SGregory Neil Shapiro 		else
28840266059SGregory Neil Shapiro 		{
28940266059SGregory Neil Shapiro 			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
29040266059SGregory Neil Shapiro 				"%.*s", (int) (q - p + 1), p);
29140266059SGregory Neil Shapiro 			p = q + (q[1] == '%' ? 2 : 1);
29240266059SGregory Neil Shapiro 			fp += strlen(fp);
29340266059SGregory Neil Shapiro 		}
29440266059SGregory Neil Shapiro 	}
29540266059SGregory Neil Shapiro 	(void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
29640266059SGregory Neil Shapiro 	if (sm_debug_active(&SmLDAPTrace, 20))
29740266059SGregory Neil Shapiro 		sm_dprintf("ldap search filter=%s\n", filter);
29840266059SGregory Neil Shapiro 
29940266059SGregory Neil Shapiro 	lmap->ldap_res = NULL;
30040266059SGregory Neil Shapiro 	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
30140266059SGregory Neil Shapiro 			    filter,
30240266059SGregory Neil Shapiro 			    (lmap->ldap_attr[0] == NULL ? NULL :
30340266059SGregory Neil Shapiro 			     lmap->ldap_attr),
30440266059SGregory Neil Shapiro 			    lmap->ldap_attrsonly);
30540266059SGregory Neil Shapiro 	return msgid;
30640266059SGregory Neil Shapiro }
30740266059SGregory Neil Shapiro 
30840266059SGregory Neil Shapiro # if _FFR_LDAP_RECURSION
30940266059SGregory Neil Shapiro /*
31040266059SGregory Neil Shapiro **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
31140266059SGregory Neil Shapiro **
31240266059SGregory Neil Shapiro **	Parameters:
31340266059SGregory Neil Shapiro **		lmap -- pointer to SM_LDAP_STRUCT in use
31440266059SGregory Neil Shapiro **		msgid -- msgid returned by sm_ldap_search()
31540266059SGregory Neil Shapiro **		flags -- flags for the lookup
31640266059SGregory Neil Shapiro **		delim -- delimiter for result concatenation
31740266059SGregory Neil Shapiro **		rpool -- memory pool for storage
31840266059SGregory Neil Shapiro **		result -- return string
31940266059SGregory Neil Shapiro **		recurse -- recursion list
32040266059SGregory Neil Shapiro **
32140266059SGregory Neil Shapiro **	Returns:
32240266059SGregory Neil Shapiro **		status (sysexit)
32340266059SGregory Neil Shapiro */
32440266059SGregory Neil Shapiro 
32540266059SGregory Neil Shapiro # define LDAPMAP_ERROR_CLEANUP()				\
32640266059SGregory Neil Shapiro {								\
32740266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)				\
32840266059SGregory Neil Shapiro 	{							\
32940266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);			\
33040266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;				\
33140266059SGregory Neil Shapiro 	}							\
33240266059SGregory Neil Shapiro 	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
33340266059SGregory Neil Shapiro }
33440266059SGregory Neil Shapiro 
33540266059SGregory Neil Shapiro static int
33640266059SGregory Neil Shapiro ldapmap_add_recurse(top, item, type, rpool)
33740266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST **top;
33840266059SGregory Neil Shapiro 	char *item;
33940266059SGregory Neil Shapiro 	int type;
34040266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
34140266059SGregory Neil Shapiro {
34240266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *p;
34340266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *last;
34440266059SGregory Neil Shapiro 
34540266059SGregory Neil Shapiro 	last = NULL;
34640266059SGregory Neil Shapiro 	for (p = *top; p != NULL; p = p->lr_next)
34740266059SGregory Neil Shapiro 	{
34840266059SGregory Neil Shapiro 		if (strcasecmp(item, p->lr_search) == 0 &&
34940266059SGregory Neil Shapiro 		    type == p->lr_type)
35040266059SGregory Neil Shapiro 		{
35140266059SGregory Neil Shapiro 			/* already on list */
35240266059SGregory Neil Shapiro 			return 1;
35340266059SGregory Neil Shapiro 		}
35440266059SGregory Neil Shapiro 		last = p;
35540266059SGregory Neil Shapiro 	}
35640266059SGregory Neil Shapiro 
35740266059SGregory Neil Shapiro 	/* not on list, add it */
35840266059SGregory Neil Shapiro 	p = sm_rpool_malloc_x(rpool, sizeof *p);
35940266059SGregory Neil Shapiro 	p->lr_search = sm_rpool_strdup_x(rpool, item);
36040266059SGregory Neil Shapiro 	p->lr_type = type;
36140266059SGregory Neil Shapiro 	p->lr_next = NULL;
36240266059SGregory Neil Shapiro 	if (last == NULL)
36340266059SGregory Neil Shapiro 		*top = p;
36440266059SGregory Neil Shapiro 	else
36540266059SGregory Neil Shapiro 		last->lr_next = p;
36640266059SGregory Neil Shapiro 	return 0;
36740266059SGregory Neil Shapiro }
36840266059SGregory Neil Shapiro 
36940266059SGregory Neil Shapiro int
37040266059SGregory Neil Shapiro sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
37140266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
37240266059SGregory Neil Shapiro 	int msgid;
37340266059SGregory Neil Shapiro 	int flags;
37440266059SGregory Neil Shapiro 	char delim;
37540266059SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
37640266059SGregory Neil Shapiro 	char **result;
37740266059SGregory Neil Shapiro 	SM_LDAP_RECURSE_LIST *recurse;
37840266059SGregory Neil Shapiro {
37940266059SGregory Neil Shapiro 	bool toplevel;
38040266059SGregory Neil Shapiro 	int i;
38140266059SGregory Neil Shapiro 	int entries = 0;
38240266059SGregory Neil Shapiro 	int statp;
38340266059SGregory Neil Shapiro 	int vsize;
38440266059SGregory Neil Shapiro 	int ret;
38540266059SGregory Neil Shapiro 	int save_errno;
38640266059SGregory Neil Shapiro 	char *p;
38740266059SGregory Neil Shapiro 
38840266059SGregory Neil Shapiro 	/* Are we the top top level of the search? */
38940266059SGregory Neil Shapiro 	toplevel = (recurse == NULL);
39040266059SGregory Neil Shapiro 
39140266059SGregory Neil Shapiro 	/* Get results */
39240266059SGregory Neil Shapiro 	statp = EX_NOTFOUND;
39340266059SGregory Neil Shapiro 	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
39440266059SGregory Neil Shapiro 				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
39540266059SGregory Neil Shapiro 				   &(lmap->ldap_timeout)),
39640266059SGregory Neil Shapiro 				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
39740266059SGregory Neil Shapiro 	{
39840266059SGregory Neil Shapiro 		LDAPMessage *entry;
39940266059SGregory Neil Shapiro 
40040266059SGregory Neil Shapiro 		if (bitset(SM_LDAP_SINGLEMATCH, flags))
40140266059SGregory Neil Shapiro 		{
40240266059SGregory Neil Shapiro 			entries += ldap_count_entries(lmap->ldap_ld,
40340266059SGregory Neil Shapiro 						      lmap->ldap_res);
40440266059SGregory Neil Shapiro 			if (entries > 1)
40540266059SGregory Neil Shapiro 			{
40640266059SGregory Neil Shapiro 				LDAPMAP_ERROR_CLEANUP();
40740266059SGregory Neil Shapiro 				errno = ENOENT;
40840266059SGregory Neil Shapiro 				return EX_NOTFOUND;
40940266059SGregory Neil Shapiro 			}
41040266059SGregory Neil Shapiro 		}
41140266059SGregory Neil Shapiro 
41240266059SGregory Neil Shapiro 		/* If we don't want multiple values and we have one, break */
41340266059SGregory Neil Shapiro 		if (delim == '\0' && *result != NULL)
41440266059SGregory Neil Shapiro 			break;
41540266059SGregory Neil Shapiro 
41640266059SGregory Neil Shapiro 		/* Cycle through all entries */
41740266059SGregory Neil Shapiro 		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
41840266059SGregory Neil Shapiro 		     entry != NULL;
41940266059SGregory Neil Shapiro 		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
42040266059SGregory Neil Shapiro 		{
42140266059SGregory Neil Shapiro 			BerElement *ber;
42240266059SGregory Neil Shapiro 			char *attr;
42340266059SGregory Neil Shapiro 			char **vals = NULL;
42440266059SGregory Neil Shapiro 			char *dn;
42540266059SGregory Neil Shapiro 
42640266059SGregory Neil Shapiro 			/*
42740266059SGregory Neil Shapiro 			**  If matching only and found an entry,
42840266059SGregory Neil Shapiro 			**  no need to spin through attributes
42940266059SGregory Neil Shapiro 			*/
43040266059SGregory Neil Shapiro 
43140266059SGregory Neil Shapiro 			if (statp == EX_OK &&
43240266059SGregory Neil Shapiro 			    bitset(SM_LDAP_MATCHONLY, flags))
43340266059SGregory Neil Shapiro 				continue;
43440266059SGregory Neil Shapiro 
43540266059SGregory Neil Shapiro 			/* record completed DN's to prevent loops */
43640266059SGregory Neil Shapiro 			dn = ldap_get_dn(lmap->ldap_ld, entry);
43740266059SGregory Neil Shapiro 			if (dn == NULL)
43840266059SGregory Neil Shapiro 			{
43940266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
44040266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
44140266059SGregory Neil Shapiro 				LDAPMAP_ERROR_CLEANUP();
44240266059SGregory Neil Shapiro 				errno = save_errno;
44340266059SGregory Neil Shapiro 				return EX_OSERR;
44440266059SGregory Neil Shapiro 			}
44540266059SGregory Neil Shapiro 
44640266059SGregory Neil Shapiro 			switch (ldapmap_add_recurse(&recurse, dn,
44740266059SGregory Neil Shapiro 						    LDAPMAP_ATTR_NORMAL,
44840266059SGregory Neil Shapiro 						    rpool))
44940266059SGregory Neil Shapiro 			{
45040266059SGregory Neil Shapiro 			  case -1:
45140266059SGregory Neil Shapiro 				/* error adding */
45240266059SGregory Neil Shapiro 				ldap_memfree(dn);
45340266059SGregory Neil Shapiro 				LDAPMAP_ERROR_CLEANUP();
45440266059SGregory Neil Shapiro 				errno = ENOMEM;
45540266059SGregory Neil Shapiro 				return EX_OSERR;
45640266059SGregory Neil Shapiro 
45740266059SGregory Neil Shapiro 			  case 1:
45840266059SGregory Neil Shapiro 				/* already on list, skip it */
45940266059SGregory Neil Shapiro 				ldap_memfree(dn);
46040266059SGregory Neil Shapiro 				continue;
46140266059SGregory Neil Shapiro 			}
46240266059SGregory Neil Shapiro 			ldap_memfree(dn);
46340266059SGregory Neil Shapiro 
46440266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
46540266059SGregory Neil Shapiro 			/*
46640266059SGregory Neil Shapiro 			**  Reset value to prevent lingering
46740266059SGregory Neil Shapiro 			**  LDAP_DECODING_ERROR due to
46840266059SGregory Neil Shapiro 			**  OpenLDAP 1.X's hack (see below)
46940266059SGregory Neil Shapiro 			*/
47040266059SGregory Neil Shapiro 
47140266059SGregory Neil Shapiro 			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
47240266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
47340266059SGregory Neil Shapiro 
47440266059SGregory Neil Shapiro 			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
47540266059SGregory Neil Shapiro 							 &ber);
47640266059SGregory Neil Shapiro 			     attr != NULL;
47740266059SGregory Neil Shapiro 			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
47840266059SGregory Neil Shapiro 							ber))
47940266059SGregory Neil Shapiro 			{
48040266059SGregory Neil Shapiro 				char *tmp, *vp_tmp;
48140266059SGregory Neil Shapiro 				int type;
48240266059SGregory Neil Shapiro 
48340266059SGregory Neil Shapiro 				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
48440266059SGregory Neil Shapiro 				{
48540266059SGregory Neil Shapiro 					if (sm_strcasecmp(lmap->ldap_attr[i],
48640266059SGregory Neil Shapiro 							  attr) == 0)
48740266059SGregory Neil Shapiro 					{
48840266059SGregory Neil Shapiro 						type = lmap->ldap_attr_type[i];
48940266059SGregory Neil Shapiro 						break;
49040266059SGregory Neil Shapiro 					}
49140266059SGregory Neil Shapiro 				}
49240266059SGregory Neil Shapiro 				if (lmap->ldap_attr[i] == NULL)
49340266059SGregory Neil Shapiro 				{
49440266059SGregory Neil Shapiro 					/* attribute not requested */
49540266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
49640266059SGregory Neil Shapiro 					ldap_memfree(attr);
49740266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
49840266059SGregory Neil Shapiro 					LDAPMAP_ERROR_CLEANUP();
49940266059SGregory Neil Shapiro 					errno = EFAULT;
50040266059SGregory Neil Shapiro 					return EX_SOFTWARE;
50140266059SGregory Neil Shapiro 				}
50240266059SGregory Neil Shapiro 
50340266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
50440266059SGregory Neil Shapiro 				{
50540266059SGregory Neil Shapiro 					vals = ldap_get_values(lmap->ldap_ld,
50640266059SGregory Neil Shapiro 							       entry,
50740266059SGregory Neil Shapiro 							       attr);
50840266059SGregory Neil Shapiro 					if (vals == NULL)
50940266059SGregory Neil Shapiro 					{
51040266059SGregory Neil Shapiro 						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
51140266059SGregory Neil Shapiro 						if (save_errno == LDAP_SUCCESS)
51240266059SGregory Neil Shapiro 						{
51340266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
51440266059SGregory Neil Shapiro 							ldap_memfree(attr);
51540266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
51640266059SGregory Neil Shapiro 							continue;
51740266059SGregory Neil Shapiro 						}
51840266059SGregory Neil Shapiro 
51940266059SGregory Neil Shapiro 						/* Must be an error */
52040266059SGregory Neil Shapiro 						save_errno += E_LDAPBASE;
52140266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
52240266059SGregory Neil Shapiro 						ldap_memfree(attr);
52340266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
52440266059SGregory Neil Shapiro 						LDAPMAP_ERROR_CLEANUP();
52540266059SGregory Neil Shapiro 						errno = save_errno;
52640266059SGregory Neil Shapiro 						return EX_TEMPFAIL;
52740266059SGregory Neil Shapiro 					}
52840266059SGregory Neil Shapiro 				}
52940266059SGregory Neil Shapiro 
53040266059SGregory Neil Shapiro 				statp = EX_OK;
53140266059SGregory Neil Shapiro 
53240266059SGregory Neil Shapiro # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
53340266059SGregory Neil Shapiro 				/*
53440266059SGregory Neil Shapiro 				**  Reset value to prevent lingering
53540266059SGregory Neil Shapiro 				**  LDAP_DECODING_ERROR due to
53640266059SGregory Neil Shapiro 				**  OpenLDAP 1.X's hack (see below)
53740266059SGregory Neil Shapiro 				*/
53840266059SGregory Neil Shapiro 
53940266059SGregory Neil Shapiro 				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
54040266059SGregory Neil Shapiro # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
54140266059SGregory Neil Shapiro 
54240266059SGregory Neil Shapiro 				/*
54340266059SGregory Neil Shapiro 				**  If matching only,
54440266059SGregory Neil Shapiro 				**  no need to spin through entries
54540266059SGregory Neil Shapiro 				*/
54640266059SGregory Neil Shapiro 
54740266059SGregory Neil Shapiro 				if (bitset(SM_LDAP_MATCHONLY, flags))
54840266059SGregory Neil Shapiro 				{
54940266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
55040266059SGregory Neil Shapiro 						ldap_value_free(vals);
55140266059SGregory Neil Shapiro 
55240266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
55340266059SGregory Neil Shapiro 					ldap_memfree(attr);
55440266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
55540266059SGregory Neil Shapiro 					continue;
55640266059SGregory Neil Shapiro 				}
55740266059SGregory Neil Shapiro 
55840266059SGregory Neil Shapiro 				/*
55940266059SGregory Neil Shapiro 				**  If we don't want multiple values,
56040266059SGregory Neil Shapiro 				**  return first found.
56140266059SGregory Neil Shapiro 				*/
56240266059SGregory Neil Shapiro 
56340266059SGregory Neil Shapiro 				if (delim == '\0')
56440266059SGregory Neil Shapiro 				{
56540266059SGregory Neil Shapiro 					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
56640266059SGregory Neil Shapiro 					{
56740266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
56840266059SGregory Neil Shapiro 									    attr);
56940266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
57040266059SGregory Neil Shapiro 						ldap_memfree(attr);
57140266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
57240266059SGregory Neil Shapiro 						break;
57340266059SGregory Neil Shapiro 					}
57440266059SGregory Neil Shapiro 
57540266059SGregory Neil Shapiro 					if (vals[0] == NULL)
57640266059SGregory Neil Shapiro 					{
57740266059SGregory Neil Shapiro 						ldap_value_free(vals);
57840266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
57940266059SGregory Neil Shapiro 						ldap_memfree(attr);
58040266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
58140266059SGregory Neil Shapiro 						continue;
58240266059SGregory Neil Shapiro 					}
58340266059SGregory Neil Shapiro 
58440266059SGregory Neil Shapiro 					vsize = strlen(vals[0]) + 1;
58540266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
58640266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
58740266059SGregory Neil Shapiro 					*result = sm_rpool_malloc_x(rpool,
58840266059SGregory Neil Shapiro 								    vsize);
58940266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
59040266059SGregory Neil Shapiro 						sm_snprintf(*result, vsize,
59140266059SGregory Neil Shapiro 							    "%s%c%s",
59240266059SGregory Neil Shapiro 							    attr,
59340266059SGregory Neil Shapiro 							    lmap->ldap_attrsep,
59440266059SGregory Neil Shapiro 							    vals[0]);
59540266059SGregory Neil Shapiro 					else
59640266059SGregory Neil Shapiro 						sm_strlcpy(*result, vals[0],
59740266059SGregory Neil Shapiro 							   vsize);
59840266059SGregory Neil Shapiro 					ldap_value_free(vals);
59940266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
60040266059SGregory Neil Shapiro 					ldap_memfree(attr);
60140266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
60240266059SGregory Neil Shapiro 					break;
60340266059SGregory Neil Shapiro 				}
60440266059SGregory Neil Shapiro 
60540266059SGregory Neil Shapiro 				/* attributes only */
60640266059SGregory Neil Shapiro 				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
60740266059SGregory Neil Shapiro 				{
60840266059SGregory Neil Shapiro 					if (*result == NULL)
60940266059SGregory Neil Shapiro 						*result = sm_rpool_strdup_x(rpool,
61040266059SGregory Neil Shapiro 									    attr);
61140266059SGregory Neil Shapiro 					else
61240266059SGregory Neil Shapiro 					{
61340266059SGregory Neil Shapiro 						vsize = strlen(*result) +
61440266059SGregory Neil Shapiro 							strlen(attr) + 2;
61540266059SGregory Neil Shapiro 						tmp = sm_rpool_malloc_x(rpool,
61640266059SGregory Neil Shapiro 									vsize);
61740266059SGregory Neil Shapiro 						(void) sm_snprintf(tmp,
61840266059SGregory Neil Shapiro 							vsize, "%s%c%s",
61940266059SGregory Neil Shapiro 							*result, delim,
62040266059SGregory Neil Shapiro 							attr);
62140266059SGregory Neil Shapiro 						*result = tmp;
62240266059SGregory Neil Shapiro 					}
62340266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
62440266059SGregory Neil Shapiro 					ldap_memfree(attr);
62540266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
62640266059SGregory Neil Shapiro 					continue;
62740266059SGregory Neil Shapiro 				}
62840266059SGregory Neil Shapiro 
62940266059SGregory Neil Shapiro 				/*
63040266059SGregory Neil Shapiro 				**  If there is more than one,
63140266059SGregory Neil Shapiro 				**  munge then into a map_coldelim
63240266059SGregory Neil Shapiro 				**  separated string
63340266059SGregory Neil Shapiro 				*/
63440266059SGregory Neil Shapiro 
63540266059SGregory Neil Shapiro 				vsize = 0;
63640266059SGregory Neil Shapiro 				for (i = 0; vals[i] != NULL; i++)
63740266059SGregory Neil Shapiro 				{
63840266059SGregory Neil Shapiro 					if (type == LDAPMAP_ATTR_DN ||
63940266059SGregory Neil Shapiro 					    type == LDAPMAP_ATTR_FILTER ||
64040266059SGregory Neil Shapiro 					    type == LDAPMAP_ATTR_URL)
64140266059SGregory Neil Shapiro 					{
64240266059SGregory Neil Shapiro 						if (ldapmap_add_recurse(&recurse,
64340266059SGregory Neil Shapiro 									vals[i],
64440266059SGregory Neil Shapiro 									type) < 0)
64540266059SGregory Neil Shapiro 						{
64640266059SGregory Neil Shapiro 							LDAPMAP_ERROR_CLEANUP();
64740266059SGregory Neil Shapiro 							errno = ENOMEM;
64840266059SGregory Neil Shapiro 							return EX_OSERR;
64940266059SGregory Neil Shapiro 						}
65040266059SGregory Neil Shapiro 					}
65140266059SGregory Neil Shapiro 					if (type != LDAPMAP_ATTR_NORMAL)
65240266059SGregory Neil Shapiro 					{
65340266059SGregory Neil Shapiro #  if USING_NETSCAPE_LDAP
65440266059SGregory Neil Shapiro 						ldap_memfree(attr);
65540266059SGregory Neil Shapiro #  endif /* USING_NETSCAPE_LDAP */
65640266059SGregory Neil Shapiro 						continue;
65740266059SGregory Neil Shapiro 					}
65840266059SGregory Neil Shapiro 					vsize += strlen(vals[i]) + 1;
65940266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
66040266059SGregory Neil Shapiro 						vsize += strlen(attr) + 1;
66140266059SGregory Neil Shapiro 				}
66240266059SGregory Neil Shapiro 				vp_tmp = sm_rpool_malloc_x(rpool, vsize);
66340266059SGregory Neil Shapiro 				*vp_tmp = '\0';
66440266059SGregory Neil Shapiro 
66540266059SGregory Neil Shapiro 				p = vp_tmp;
66640266059SGregory Neil Shapiro 				for (i = 0; vals[i] != NULL; i++)
66740266059SGregory Neil Shapiro 				{
66840266059SGregory Neil Shapiro 					if (lmap->ldap_attrsep != '\0')
66940266059SGregory Neil Shapiro 					{
67040266059SGregory Neil Shapiro 						p += sm_strlcpy(p, attr,
67140266059SGregory Neil Shapiro 								vsize - (p - vp_tmp));
67240266059SGregory Neil Shapiro 						*p++ = lmap->ldap_attrsep;
67340266059SGregory Neil Shapiro 					}
67440266059SGregory Neil Shapiro 					p += sm_strlcpy(p, vals[i],
67540266059SGregory Neil Shapiro 							vsize - (p - vp_tmp));
67640266059SGregory Neil Shapiro 					if (p >= vp_tmp + vsize)
67740266059SGregory Neil Shapiro 					{
67840266059SGregory Neil Shapiro 						/* Internal error: buffer too small for LDAP values */
67940266059SGregory Neil Shapiro 						LDAPMAP_ERROR_CLEANUP();
68040266059SGregory Neil Shapiro 						errno = ENOMEM;
68140266059SGregory Neil Shapiro 						return EX_OSERR;
68240266059SGregory Neil Shapiro 					}
68340266059SGregory Neil Shapiro 					if (vals[i + 1] != NULL)
68440266059SGregory Neil Shapiro 						*p++ = delim;
68540266059SGregory Neil Shapiro 				}
68640266059SGregory Neil Shapiro 
68740266059SGregory Neil Shapiro 				ldap_value_free(vals);
68840266059SGregory Neil Shapiro # if USING_NETSCAPE_LDAP
68940266059SGregory Neil Shapiro 				ldap_memfree(attr);
69040266059SGregory Neil Shapiro # endif /* USING_NETSCAPE_LDAP */
69140266059SGregory Neil Shapiro 				if (*result == NULL)
69240266059SGregory Neil Shapiro 				{
69340266059SGregory Neil Shapiro 					*result = vp_tmp;
69440266059SGregory Neil Shapiro 					continue;
69540266059SGregory Neil Shapiro 				}
69640266059SGregory Neil Shapiro 				vsize = strlen(*result) + strlen(vp_tmp) + 2;
69740266059SGregory Neil Shapiro 				tmp = sm_rpool_malloc_x(rpool, vsize);
69840266059SGregory Neil Shapiro 				(void) sm_snprintf(tmp, vsize, "%s%c%s",
69940266059SGregory Neil Shapiro 						   *result, delim, vp_tmp);
70040266059SGregory Neil Shapiro 				*result = tmp;
70140266059SGregory Neil Shapiro 			}
70240266059SGregory Neil Shapiro 			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
70340266059SGregory Neil Shapiro 
70440266059SGregory Neil Shapiro 			/*
70540266059SGregory Neil Shapiro 			**  We check save_errno != LDAP_DECODING_ERROR since
70640266059SGregory Neil Shapiro 			**  OpenLDAP 1.X has a very ugly *undocumented*
70740266059SGregory Neil Shapiro 			**  hack of returning this error code from
70840266059SGregory Neil Shapiro 			**  ldap_next_attribute() if the library freed the
70940266059SGregory Neil Shapiro 			**  ber attribute.  See:
71040266059SGregory Neil Shapiro 			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
71140266059SGregory Neil Shapiro 			*/
71240266059SGregory Neil Shapiro 
71340266059SGregory Neil Shapiro 			if (save_errno != LDAP_SUCCESS &&
71440266059SGregory Neil Shapiro 			    save_errno != LDAP_DECODING_ERROR)
71540266059SGregory Neil Shapiro 			{
71640266059SGregory Neil Shapiro 				/* Must be an error */
71740266059SGregory Neil Shapiro 				save_errno += E_LDAPBASE;
71840266059SGregory Neil Shapiro 				LDAPMAP_ERROR_CLEANUP();
71940266059SGregory Neil Shapiro 				errno = save_errno;
72040266059SGregory Neil Shapiro 				return EX_TEMPFAIL;
72140266059SGregory Neil Shapiro 			}
72240266059SGregory Neil Shapiro 
72340266059SGregory Neil Shapiro 			/* We don't want multiple values and we have one */
72440266059SGregory Neil Shapiro 			if (delim == '\0' && *result != NULL)
72540266059SGregory Neil Shapiro 				break;
72640266059SGregory Neil Shapiro 		}
72740266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
72840266059SGregory Neil Shapiro 		if (save_errno != LDAP_SUCCESS &&
72940266059SGregory Neil Shapiro 		    save_errno != LDAP_DECODING_ERROR)
73040266059SGregory Neil Shapiro 		{
73140266059SGregory Neil Shapiro 			/* Must be an error */
73240266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
73340266059SGregory Neil Shapiro 			LDAPMAP_ERROR_CLEANUP();
73440266059SGregory Neil Shapiro 			errno = save_errno;
73540266059SGregory Neil Shapiro 			return EX_TEMPFAIL;
73640266059SGregory Neil Shapiro 		}
73740266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
73840266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
73940266059SGregory Neil Shapiro 	}
74040266059SGregory Neil Shapiro 
74140266059SGregory Neil Shapiro 	if (ret == 0)
74240266059SGregory Neil Shapiro 		save_errno = ETIMEDOUT;
74340266059SGregory Neil Shapiro 	else
74440266059SGregory Neil Shapiro 		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
74540266059SGregory Neil Shapiro 	if (save_errno != LDAP_SUCCESS)
74640266059SGregory Neil Shapiro 	{
74740266059SGregory Neil Shapiro 		statp = EX_TEMPFAIL;
74840266059SGregory Neil Shapiro 		if (ret != 0)
74940266059SGregory Neil Shapiro 		{
75040266059SGregory Neil Shapiro 			switch (save_errno)
75140266059SGregory Neil Shapiro 			{
75240266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
75340266059SGregory Neil Shapiro 			  case LDAP_SERVER_DOWN:
75440266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
75540266059SGregory Neil Shapiro 			  case LDAP_TIMEOUT:
75640266059SGregory Neil Shapiro 			  case LDAP_UNAVAILABLE:
75740266059SGregory Neil Shapiro 				/* server disappeared, try reopen on next search */
75840266059SGregory Neil Shapiro 				statp = EX_RESTART;
75940266059SGregory Neil Shapiro 				break;
76040266059SGregory Neil Shapiro 			}
76140266059SGregory Neil Shapiro 			save_errno += E_LDAPBASE;
76240266059SGregory Neil Shapiro 		}
76340266059SGregory Neil Shapiro 		LDAPMAP_ERROR_CLEANUP();
76440266059SGregory Neil Shapiro 		errno = save_errno;
76540266059SGregory Neil Shapiro 		return statp;
76640266059SGregory Neil Shapiro 	}
76740266059SGregory Neil Shapiro 
76840266059SGregory Neil Shapiro 	if (lmap->ldap_res != NULL)
76940266059SGregory Neil Shapiro 	{
77040266059SGregory Neil Shapiro 		ldap_msgfree(lmap->ldap_res);
77140266059SGregory Neil Shapiro 		lmap->ldap_res = NULL;
77240266059SGregory Neil Shapiro 	}
77340266059SGregory Neil Shapiro 
77440266059SGregory Neil Shapiro 	if (toplevel)
77540266059SGregory Neil Shapiro 	{
77640266059SGregory Neil Shapiro 		SM_LDAP_RECURSE_LIST *rl;
77740266059SGregory Neil Shapiro 
77840266059SGregory Neil Shapiro 		/*
77940266059SGregory Neil Shapiro 		**  Spin through the built-up recurse list at the top
78040266059SGregory Neil Shapiro 		**  of the recursion.  Since new items are added at the
78140266059SGregory Neil Shapiro 		**  end of the shared list, we actually only ever get
78240266059SGregory Neil Shapiro 		**  one level of recursion before things pop back to the
78340266059SGregory Neil Shapiro 		**  top.  Any items added to the list during that recursion
78440266059SGregory Neil Shapiro 		**  will be expanded by the top level.
78540266059SGregory Neil Shapiro 		*/
78640266059SGregory Neil Shapiro 
78740266059SGregory Neil Shapiro 		for (rl = recurse; rl != NULL; rl = rl->lr_next)
78840266059SGregory Neil Shapiro 		{
78940266059SGregory Neil Shapiro 			int sid;
79040266059SGregory Neil Shapiro 			int status;
79140266059SGregory Neil Shapiro 
79240266059SGregory Neil Shapiro 			if (rl->lr_type == LDAPMAP_ATTR_NORMAL)
79340266059SGregory Neil Shapiro 			{
79440266059SGregory Neil Shapiro 				/* already expanded */
79540266059SGregory Neil Shapiro 				continue;
79640266059SGregory Neil Shapiro 			}
79740266059SGregory Neil Shapiro 			else if (rl->lr_type == LDAPMAP_ATTR_DN)
79840266059SGregory Neil Shapiro 			{
79940266059SGregory Neil Shapiro 				/* do DN search */
80040266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
80140266059SGregory Neil Shapiro 						  rl->lr_search,
80240266059SGregory Neil Shapiro 						  lmap->ldap_scope,
80340266059SGregory Neil Shapiro 						  "(objectClass=*)",
80440266059SGregory Neil Shapiro 						  lmap->ldap_attr_final,
80540266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
80640266059SGregory Neil Shapiro 			}
80740266059SGregory Neil Shapiro 			else if (rl->lr_type == LDAPMAP_ATTR_FILTER)
80840266059SGregory Neil Shapiro 			{
80940266059SGregory Neil Shapiro 				/* do new search */
81040266059SGregory Neil Shapiro 				sid = ldap_search(lmap->ldap_ld,
81140266059SGregory Neil Shapiro 						  lmap->ldap_base,
81240266059SGregory Neil Shapiro 						  lmap->ldap_scope,
81340266059SGregory Neil Shapiro 						  rl->lr_search,
81440266059SGregory Neil Shapiro 						  lmap->ldap_attr_final,
81540266059SGregory Neil Shapiro 						  lmap->ldap_attrsonly);
81640266059SGregory Neil Shapiro 			}
81740266059SGregory Neil Shapiro 			else if (rl->lr_type == LDAPMAP_ATTR_URL)
81840266059SGregory Neil Shapiro 			{
81940266059SGregory Neil Shapiro 				/* do new URL search */
82040266059SGregory Neil Shapiro 				sid = ldap_url_search(lmap->ldap_ld,
82140266059SGregory Neil Shapiro 						      rl->lr_search,
82240266059SGregory Neil Shapiro 						      lmap->ldap_attrsonly);
82340266059SGregory Neil Shapiro 			}
82440266059SGregory Neil Shapiro 			else
82540266059SGregory Neil Shapiro 			{
82640266059SGregory Neil Shapiro 				/* unknown or illegal attribute type */
82740266059SGregory Neil Shapiro 				errno = EFAULT;
82840266059SGregory Neil Shapiro 				return EX_SOFTWARE;
82940266059SGregory Neil Shapiro 			}
83040266059SGregory Neil Shapiro 
83140266059SGregory Neil Shapiro 			/* Collect results */
83240266059SGregory Neil Shapiro 			if (sid == -1)
83340266059SGregory Neil Shapiro 			{
83440266059SGregory Neil Shapiro 				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
83540266059SGregory Neil Shapiro 				statp = EX_TEMPFAIL;
83640266059SGregory Neil Shapiro 				switch (save_errno)
83740266059SGregory Neil Shapiro 				{
83840266059SGregory Neil Shapiro #ifdef LDAP_SERVER_DOWN
83940266059SGregory Neil Shapiro 				  case LDAP_SERVER_DOWN:
84040266059SGregory Neil Shapiro #endif /* LDAP_SERVER_DOWN */
84140266059SGregory Neil Shapiro 				  case LDAP_TIMEOUT:
84240266059SGregory Neil Shapiro 				  case LDAP_UNAVAILABLE:
84340266059SGregory Neil Shapiro 					/* server disappeared, try reopen on next search */
84440266059SGregory Neil Shapiro 					statp = EX_RESTART;
84540266059SGregory Neil Shapiro 					break;
84640266059SGregory Neil Shapiro 				}
84740266059SGregory Neil Shapiro 				errno = save_errno + E_LDAPBASE;
84840266059SGregory Neil Shapiro 				return statp;
84940266059SGregory Neil Shapiro 			}
85040266059SGregory Neil Shapiro 
85140266059SGregory Neil Shapiro 			status = sm_ldap_results(lmap, sid, flags, delim,
85240266059SGregory Neil Shapiro 						 rpool, result, recurse);
85340266059SGregory Neil Shapiro 			save_errno = errno;
85440266059SGregory Neil Shapiro 			if (status != EX_OK && status != EX_NOTFOUND)
85540266059SGregory Neil Shapiro 			{
85640266059SGregory Neil Shapiro 				errno = save_errno;
85740266059SGregory Neil Shapiro 				return status;
85840266059SGregory Neil Shapiro 			}
85940266059SGregory Neil Shapiro 
86040266059SGregory Neil Shapiro 			/* Mark as done */
86140266059SGregory Neil Shapiro 			rl->lr_type = LDAPMAP_ATTR_NORMAL;
86240266059SGregory Neil Shapiro 		}
86340266059SGregory Neil Shapiro 	}
86440266059SGregory Neil Shapiro 	return statp;
86540266059SGregory Neil Shapiro }
86640266059SGregory Neil Shapiro #endif /* _FFR_LDAP_RECURSION */
86740266059SGregory Neil Shapiro 
86840266059SGregory Neil Shapiro /*
86940266059SGregory Neil Shapiro **  SM_LDAP_CLOSE -- close LDAP connection
87040266059SGregory Neil Shapiro **
87140266059SGregory Neil Shapiro **	Parameters:
87240266059SGregory Neil Shapiro **		lmap -- LDAP map information
87340266059SGregory Neil Shapiro **
87440266059SGregory Neil Shapiro **	Returns:
87540266059SGregory Neil Shapiro **		None.
87640266059SGregory Neil Shapiro **
87740266059SGregory Neil Shapiro */
87840266059SGregory Neil Shapiro 
87940266059SGregory Neil Shapiro void
88040266059SGregory Neil Shapiro sm_ldap_close(lmap)
88140266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
88240266059SGregory Neil Shapiro {
88340266059SGregory Neil Shapiro 	if (lmap->ldap_ld == NULL)
88440266059SGregory Neil Shapiro 		return;
88540266059SGregory Neil Shapiro 
88640266059SGregory Neil Shapiro 	if (lmap->ldap_pid == getpid())
88740266059SGregory Neil Shapiro 		ldap_unbind(lmap->ldap_ld);
88840266059SGregory Neil Shapiro 	lmap->ldap_ld = NULL;
88940266059SGregory Neil Shapiro 	lmap->ldap_pid = 0;
89040266059SGregory Neil Shapiro }
89140266059SGregory Neil Shapiro 
89240266059SGregory Neil Shapiro /*
89340266059SGregory Neil Shapiro **  SM_LDAP_SETOPTS -- set LDAP options
89440266059SGregory Neil Shapiro **
89540266059SGregory Neil Shapiro **	Parameters:
89640266059SGregory Neil Shapiro **		ld -- LDAP session handle
89740266059SGregory Neil Shapiro **		lmap -- LDAP map information
89840266059SGregory Neil Shapiro **
89940266059SGregory Neil Shapiro **	Returns:
90040266059SGregory Neil Shapiro **		None.
90140266059SGregory Neil Shapiro **
90240266059SGregory Neil Shapiro */
90340266059SGregory Neil Shapiro 
90440266059SGregory Neil Shapiro void
90540266059SGregory Neil Shapiro sm_ldap_setopts(ld, lmap)
90640266059SGregory Neil Shapiro 	LDAP *ld;
90740266059SGregory Neil Shapiro 	SM_LDAP_STRUCT *lmap;
90840266059SGregory Neil Shapiro {
90940266059SGregory Neil Shapiro # if USE_LDAP_SET_OPTION
91040266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
91140266059SGregory Neil Shapiro 	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
91240266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
91340266059SGregory Neil Shapiro 	else
91440266059SGregory Neil Shapiro 		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
91540266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
91640266059SGregory Neil Shapiro 	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
91740266059SGregory Neil Shapiro # else /* USE_LDAP_SET_OPTION */
91840266059SGregory Neil Shapiro 	/* From here on in we can use ldap internal timelimits */
91940266059SGregory Neil Shapiro 	ld->ld_deref = lmap->ldap_deref;
92040266059SGregory Neil Shapiro 	ld->ld_options = lmap->ldap_options;
92140266059SGregory Neil Shapiro 	ld->ld_sizelimit = lmap->ldap_sizelimit;
92240266059SGregory Neil Shapiro 	ld->ld_timelimit = lmap->ldap_timelimit;
92340266059SGregory Neil Shapiro # endif /* USE_LDAP_SET_OPTION */
92440266059SGregory Neil Shapiro }
92540266059SGregory Neil Shapiro 
92640266059SGregory Neil Shapiro /*
92740266059SGregory Neil Shapiro **  SM_LDAP_GETERRNO -- get ldap errno value
92840266059SGregory Neil Shapiro **
92940266059SGregory Neil Shapiro **	Parameters:
93040266059SGregory Neil Shapiro **		ld -- LDAP session handle
93140266059SGregory Neil Shapiro **
93240266059SGregory Neil Shapiro **	Returns:
93340266059SGregory Neil Shapiro **		LDAP errno.
93440266059SGregory Neil Shapiro **
93540266059SGregory Neil Shapiro */
93640266059SGregory Neil Shapiro 
93740266059SGregory Neil Shapiro int
93840266059SGregory Neil Shapiro sm_ldap_geterrno(ld)
93940266059SGregory Neil Shapiro 	LDAP *ld;
94040266059SGregory Neil Shapiro {
94140266059SGregory Neil Shapiro 	int err = LDAP_SUCCESS;
94240266059SGregory Neil Shapiro 
94340266059SGregory Neil Shapiro # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
94440266059SGregory Neil Shapiro 	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
94540266059SGregory Neil Shapiro # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
94640266059SGregory Neil Shapiro #  ifdef LDAP_OPT_SIZELIMIT
94740266059SGregory Neil Shapiro 	err = ldap_get_lderrno(ld, NULL, NULL);
94840266059SGregory Neil Shapiro #  else /* LDAP_OPT_SIZELIMIT */
94940266059SGregory Neil Shapiro 	err = ld->ld_errno;
95040266059SGregory Neil Shapiro 
95140266059SGregory Neil Shapiro 	/*
95240266059SGregory Neil Shapiro 	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
95340266059SGregory Neil Shapiro 	**  OpenLDAP 1.X's hack (see above)
95440266059SGregory Neil Shapiro 	*/
95540266059SGregory Neil Shapiro 
95640266059SGregory Neil Shapiro 	ld->ld_errno = LDAP_SUCCESS;
95740266059SGregory Neil Shapiro #  endif /* LDAP_OPT_SIZELIMIT */
95840266059SGregory Neil Shapiro # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
95940266059SGregory Neil Shapiro 	return err;
96040266059SGregory Neil Shapiro }
96140266059SGregory Neil Shapiro # endif /* LDAPMAP */
962