ldap.c revision 90792
190792Sgshapiro/*
290792Sgshapiro * Copyright (c) 2001-2002 Sendmail, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro *
590792Sgshapiro * By using this file, you agree to the terms and conditions set
690792Sgshapiro * forth in the LICENSE file which can be found at the top level of
790792Sgshapiro * the sendmail distribution.
890792Sgshapiro */
990792Sgshapiro
1090792Sgshapiro#include <sm/gen.h>
1190792SgshapiroSM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")
1290792Sgshapiro
1390792Sgshapiro#if LDAPMAP
1490792Sgshapiro# include <sys/types.h>
1590792Sgshapiro# include <errno.h>
1690792Sgshapiro# include <setjmp.h>
1790792Sgshapiro# include <stdlib.h>
1890792Sgshapiro# include <unistd.h>
1990792Sgshapiro
2090792Sgshapiro# include <sm/bitops.h>
2190792Sgshapiro# include <sm/clock.h>
2290792Sgshapiro# include <sm/conf.h>
2390792Sgshapiro# include <sm/debug.h>
2490792Sgshapiro# include <sm/errstring.h>
2590792Sgshapiro# include <sm/ldap.h>
2690792Sgshapiro# include <sm/string.h>
2790792Sgshapiro# include <sm/sysexits.h>
2890792Sgshapiro
2990792SgshapiroSM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
3090792Sgshapiro	"@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
3190792Sgshapiro
3290792Sgshapirostatic void	ldaptimeout __P((int));
3390792Sgshapiro
3490792Sgshapiro/*
3590792Sgshapiro**  SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
3690792Sgshapiro**
3790792Sgshapiro**	Parameters:
3890792Sgshapiro**		lmap -- pointer to SM_LDAP_STRUCT to clear
3990792Sgshapiro**
4090792Sgshapiro**	Returns:
4190792Sgshapiro**		None.
4290792Sgshapiro**
4390792Sgshapiro*/
4490792Sgshapiro
4590792Sgshapirovoid
4690792Sgshapirosm_ldap_clear(lmap)
4790792Sgshapiro	SM_LDAP_STRUCT *lmap;
4890792Sgshapiro{
4990792Sgshapiro	if (lmap == NULL)
5090792Sgshapiro		return;
5190792Sgshapiro
5290792Sgshapiro	lmap->ldap_host = NULL;
5390792Sgshapiro	lmap->ldap_port = LDAP_PORT;
5490792Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
5590792Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
5690792Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
5790792Sgshapiro# ifdef LDAP_REFERRALS
5890792Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
5990792Sgshapiro# else /* LDAP_REFERRALS */
6090792Sgshapiro	lmap->ldap_options = 0;
6190792Sgshapiro# endif /* LDAP_REFERRALS */
6290792Sgshapiro	lmap->ldap_attrsep = '\0';
6390792Sgshapiro	lmap->ldap_binddn = NULL;
6490792Sgshapiro	lmap->ldap_secret = NULL;
6590792Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
6690792Sgshapiro	lmap->ldap_base = NULL;
6790792Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
6890792Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
6990792Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
7090792Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
7190792Sgshapiro	lmap->ldap_ld = NULL;
7290792Sgshapiro	lmap->ldap_filter = NULL;
7390792Sgshapiro	lmap->ldap_attr[0] = NULL;
7490792Sgshapiro#if _FFR_LDAP_RECURSION
7590792Sgshapiro	lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL;
7690792Sgshapiro	lmap->ldap_attr_final[0] = NULL;
7790792Sgshapiro#endif /* _FFR_LDAP_RECURSION */
7890792Sgshapiro	lmap->ldap_res = NULL;
7990792Sgshapiro	lmap->ldap_next = NULL;
8090792Sgshapiro	lmap->ldap_pid = 0;
8190792Sgshapiro}
8290792Sgshapiro
8390792Sgshapiro/*
8490792Sgshapiro**  SM_LDAP_START -- actually connect to an LDAP server
8590792Sgshapiro**
8690792Sgshapiro**	Parameters:
8790792Sgshapiro**		name -- name of map for debug output.
8890792Sgshapiro**		lmap -- the LDAP map being opened.
8990792Sgshapiro**
9090792Sgshapiro**	Returns:
9190792Sgshapiro**		true if connection is successful, false otherwise.
9290792Sgshapiro**
9390792Sgshapiro**	Side Effects:
9490792Sgshapiro**		Populates lmap->ldap_ld.
9590792Sgshapiro*/
9690792Sgshapiro
9790792Sgshapirostatic jmp_buf	LDAPTimeout;
9890792Sgshapiro
9990792Sgshapiro#define SM_LDAP_SETTIMEOUT(to)						\
10090792Sgshapirodo									\
10190792Sgshapiro{									\
10290792Sgshapiro	if (to != 0)							\
10390792Sgshapiro	{								\
10490792Sgshapiro		if (setjmp(LDAPTimeout) != 0)				\
10590792Sgshapiro		{							\
10690792Sgshapiro			errno = ETIMEDOUT;				\
10790792Sgshapiro			return false;					\
10890792Sgshapiro		}							\
10990792Sgshapiro		ev = sm_setevent(to, ldaptimeout, 0);			\
11090792Sgshapiro	}								\
11190792Sgshapiro} while (0)
11290792Sgshapiro
11390792Sgshapiro#define SM_LDAP_CLEARTIMEOUT()						\
11490792Sgshapirodo									\
11590792Sgshapiro{									\
11690792Sgshapiro	if (ev != NULL)							\
11790792Sgshapiro		sm_clrevent(ev);					\
11890792Sgshapiro} while (0)
11990792Sgshapiro
12090792Sgshapirobool
12190792Sgshapirosm_ldap_start(name, lmap)
12290792Sgshapiro	char *name;
12390792Sgshapiro	SM_LDAP_STRUCT *lmap;
12490792Sgshapiro{
12590792Sgshapiro	int bind_result;
12690792Sgshapiro	int save_errno;
12790792Sgshapiro	SM_EVENT *ev = NULL;
12890792Sgshapiro	LDAP *ld;
12990792Sgshapiro
13090792Sgshapiro	if (sm_debug_active(&SmLDAPTrace, 2))
13190792Sgshapiro		sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
13290792Sgshapiro
13390792Sgshapiro	if (sm_debug_active(&SmLDAPTrace, 9))
13490792Sgshapiro		sm_dprintf("ldapmap_start(%s, %d)\n",
13590792Sgshapiro			   lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
13690792Sgshapiro			   lmap->ldap_port);
13790792Sgshapiro
13890792Sgshapiro# if USE_LDAP_INIT
13990792Sgshapiro	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
14090792Sgshapiro	save_errno = errno;
14190792Sgshapiro# else /* USE_LDAP_INIT */
14290792Sgshapiro	/*
14390792Sgshapiro	**  If using ldap_open(), the actual connection to the server
14490792Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
14590792Sgshapiro	**  the connection happens at bind time.
14690792Sgshapiro	*/
14790792Sgshapiro
14890792Sgshapiro	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
14990792Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
15090792Sgshapiro	save_errno = errno;
15190792Sgshapiro
15290792Sgshapiro	/* clear the event if it has not sprung */
15390792Sgshapiro	SM_LDAP_CLEARTIMEOUT();
15490792Sgshapiro# endif /* USE_LDAP_INIT */
15590792Sgshapiro
15690792Sgshapiro	errno = save_errno;
15790792Sgshapiro	if (ld == NULL)
15890792Sgshapiro		return false;
15990792Sgshapiro
16090792Sgshapiro	sm_ldap_setopts(ld, lmap);
16190792Sgshapiro
16290792Sgshapiro# if USE_LDAP_INIT
16390792Sgshapiro	/*
16490792Sgshapiro	**  If using ldap_init(), the actual connection to the server
16590792Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
16690792Sgshapiro	*/
16790792Sgshapiro
16890792Sgshapiro	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
16990792Sgshapiro# endif /* USE_LDAP_INIT */
17090792Sgshapiro
17190792Sgshapiro# ifdef LDAP_AUTH_KRBV4
17290792Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
17390792Sgshapiro	    lmap->ldap_secret != NULL)
17490792Sgshapiro	{
17590792Sgshapiro		/*
17690792Sgshapiro		**  Need to put ticket in environment here instead of
17790792Sgshapiro		**  during parseargs as there may be different tickets
17890792Sgshapiro		**  for different LDAP connections.
17990792Sgshapiro		*/
18090792Sgshapiro
18190792Sgshapiro		(void) putenv(lmap->ldap_secret);
18290792Sgshapiro	}
18390792Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
18490792Sgshapiro
18590792Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
18690792Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
18790792Sgshapiro
18890792Sgshapiro# if USE_LDAP_INIT
18990792Sgshapiro	/* clear the event if it has not sprung */
19090792Sgshapiro	SM_LDAP_CLEARTIMEOUT();
19190792Sgshapiro# endif /* USE_LDAP_INIT */
19290792Sgshapiro
19390792Sgshapiro	if (bind_result != LDAP_SUCCESS)
19490792Sgshapiro	{
19590792Sgshapiro		errno = bind_result + E_LDAPBASE;
19690792Sgshapiro		return false;
19790792Sgshapiro	}
19890792Sgshapiro
19990792Sgshapiro	/* Save PID to make sure only this PID closes the LDAP connection */
20090792Sgshapiro	lmap->ldap_pid = getpid();
20190792Sgshapiro	lmap->ldap_ld = ld;
20290792Sgshapiro	return true;
20390792Sgshapiro}
20490792Sgshapiro
20590792Sgshapiro/* ARGSUSED */
20690792Sgshapirostatic void
20790792Sgshapiroldaptimeout(unused)
20890792Sgshapiro	int unused;
20990792Sgshapiro{
21090792Sgshapiro	/*
21190792Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
21290792Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
21390792Sgshapiro	**	DOING.
21490792Sgshapiro	*/
21590792Sgshapiro
21690792Sgshapiro	errno = ETIMEDOUT;
21790792Sgshapiro	longjmp(LDAPTimeout, 1);
21890792Sgshapiro}
21990792Sgshapiro
22090792Sgshapiro/*
22190792Sgshapiro**  SM_LDAP_SEARCH -- iniate LDAP search
22290792Sgshapiro**
22390792Sgshapiro**	Initiate an LDAP search, return the msgid.
22490792Sgshapiro**	The calling function must collect the results.
22590792Sgshapiro**
22690792Sgshapiro**	Parameters:
22790792Sgshapiro**		lmap -- LDAP map information
22890792Sgshapiro**		key -- key to substitute in LDAP filter
22990792Sgshapiro**
23090792Sgshapiro**	Returns:
23190792Sgshapiro**		-1 on failure, msgid on success
23290792Sgshapiro**
23390792Sgshapiro*/
23490792Sgshapiro
23590792Sgshapiroint
23690792Sgshapirosm_ldap_search(lmap, key)
23790792Sgshapiro	SM_LDAP_STRUCT *lmap;
23890792Sgshapiro	char *key;
23990792Sgshapiro{
24090792Sgshapiro	int msgid;
24190792Sgshapiro	char *fp, *p, *q;
24290792Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
24390792Sgshapiro
24490792Sgshapiro	/* substitute key into filter, perhaps multiple times */
24590792Sgshapiro	memset(filter, '\0', sizeof filter);
24690792Sgshapiro	fp = filter;
24790792Sgshapiro	p = lmap->ldap_filter;
24890792Sgshapiro	while ((q = strchr(p, '%')) != NULL)
24990792Sgshapiro	{
25090792Sgshapiro		if (q[1] == 's')
25190792Sgshapiro		{
25290792Sgshapiro			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
25390792Sgshapiro					   "%.*s%s", (int) (q - p), p, key);
25490792Sgshapiro			fp += strlen(fp);
25590792Sgshapiro			p = q + 2;
25690792Sgshapiro		}
25790792Sgshapiro		else if (q[1] == '0')
25890792Sgshapiro		{
25990792Sgshapiro			char *k = key;
26090792Sgshapiro
26190792Sgshapiro			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
26290792Sgshapiro					   "%.*s", (int) (q - p), p);
26390792Sgshapiro			fp += strlen(fp);
26490792Sgshapiro			p = q + 2;
26590792Sgshapiro
26690792Sgshapiro			/* Properly escape LDAP special characters */
26790792Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
26890792Sgshapiro			       *k != '\0')
26990792Sgshapiro			{
27090792Sgshapiro				if (*k == '*' || *k == '(' ||
27190792Sgshapiro				    *k == ')' || *k == '\\')
27290792Sgshapiro				{
27390792Sgshapiro					(void) sm_strlcat(fp,
27490792Sgshapiro						       (*k == '*' ? "\\2A" :
27590792Sgshapiro							(*k == '(' ? "\\28" :
27690792Sgshapiro							 (*k == ')' ? "\\29" :
27790792Sgshapiro							  (*k == '\\' ? "\\5C" :
27890792Sgshapiro							   "\00")))),
27990792Sgshapiro						SPACELEFT(filter, fp));
28090792Sgshapiro					fp += strlen(fp);
28190792Sgshapiro					k++;
28290792Sgshapiro				}
28390792Sgshapiro				else
28490792Sgshapiro					*fp++ = *k++;
28590792Sgshapiro			}
28690792Sgshapiro		}
28790792Sgshapiro		else
28890792Sgshapiro		{
28990792Sgshapiro			(void) sm_snprintf(fp, SPACELEFT(filter, fp),
29090792Sgshapiro				"%.*s", (int) (q - p + 1), p);
29190792Sgshapiro			p = q + (q[1] == '%' ? 2 : 1);
29290792Sgshapiro			fp += strlen(fp);
29390792Sgshapiro		}
29490792Sgshapiro	}
29590792Sgshapiro	(void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
29690792Sgshapiro	if (sm_debug_active(&SmLDAPTrace, 20))
29790792Sgshapiro		sm_dprintf("ldap search filter=%s\n", filter);
29890792Sgshapiro
29990792Sgshapiro	lmap->ldap_res = NULL;
30090792Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
30190792Sgshapiro			    filter,
30290792Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
30390792Sgshapiro			     lmap->ldap_attr),
30490792Sgshapiro			    lmap->ldap_attrsonly);
30590792Sgshapiro	return msgid;
30690792Sgshapiro}
30790792Sgshapiro
30890792Sgshapiro# if _FFR_LDAP_RECURSION
30990792Sgshapiro/*
31090792Sgshapiro**  SM_LDAP_RESULTS -- return results from an LDAP lookup in result
31190792Sgshapiro**
31290792Sgshapiro**	Parameters:
31390792Sgshapiro**		lmap -- pointer to SM_LDAP_STRUCT in use
31490792Sgshapiro**		msgid -- msgid returned by sm_ldap_search()
31590792Sgshapiro**		flags -- flags for the lookup
31690792Sgshapiro**		delim -- delimiter for result concatenation
31790792Sgshapiro**		rpool -- memory pool for storage
31890792Sgshapiro**		result -- return string
31990792Sgshapiro**		recurse -- recursion list
32090792Sgshapiro**
32190792Sgshapiro**	Returns:
32290792Sgshapiro**		status (sysexit)
32390792Sgshapiro*/
32490792Sgshapiro
32590792Sgshapiro# define LDAPMAP_ERROR_CLEANUP()				\
32690792Sgshapiro{								\
32790792Sgshapiro	if (lmap->ldap_res != NULL)				\
32890792Sgshapiro	{							\
32990792Sgshapiro		ldap_msgfree(lmap->ldap_res);			\
33090792Sgshapiro		lmap->ldap_res = NULL;				\
33190792Sgshapiro	}							\
33290792Sgshapiro	(void) ldap_abandon(lmap->ldap_ld, msgid);		\
33390792Sgshapiro}
33490792Sgshapiro
33590792Sgshapirostatic int
33690792Sgshapiroldapmap_add_recurse(top, item, type, rpool)
33790792Sgshapiro	SM_LDAP_RECURSE_LIST **top;
33890792Sgshapiro	char *item;
33990792Sgshapiro	int type;
34090792Sgshapiro	SM_RPOOL_T *rpool;
34190792Sgshapiro{
34290792Sgshapiro	SM_LDAP_RECURSE_LIST *p;
34390792Sgshapiro	SM_LDAP_RECURSE_LIST *last;
34490792Sgshapiro
34590792Sgshapiro	last = NULL;
34690792Sgshapiro	for (p = *top; p != NULL; p = p->lr_next)
34790792Sgshapiro	{
34890792Sgshapiro		if (strcasecmp(item, p->lr_search) == 0 &&
34990792Sgshapiro		    type == p->lr_type)
35090792Sgshapiro		{
35190792Sgshapiro			/* already on list */
35290792Sgshapiro			return 1;
35390792Sgshapiro		}
35490792Sgshapiro		last = p;
35590792Sgshapiro	}
35690792Sgshapiro
35790792Sgshapiro	/* not on list, add it */
35890792Sgshapiro	p = sm_rpool_malloc_x(rpool, sizeof *p);
35990792Sgshapiro	p->lr_search = sm_rpool_strdup_x(rpool, item);
36090792Sgshapiro	p->lr_type = type;
36190792Sgshapiro	p->lr_next = NULL;
36290792Sgshapiro	if (last == NULL)
36390792Sgshapiro		*top = p;
36490792Sgshapiro	else
36590792Sgshapiro		last->lr_next = p;
36690792Sgshapiro	return 0;
36790792Sgshapiro}
36890792Sgshapiro
36990792Sgshapiroint
37090792Sgshapirosm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)
37190792Sgshapiro	SM_LDAP_STRUCT *lmap;
37290792Sgshapiro	int msgid;
37390792Sgshapiro	int flags;
37490792Sgshapiro	char delim;
37590792Sgshapiro	SM_RPOOL_T *rpool;
37690792Sgshapiro	char **result;
37790792Sgshapiro	SM_LDAP_RECURSE_LIST *recurse;
37890792Sgshapiro{
37990792Sgshapiro	bool toplevel;
38090792Sgshapiro	int i;
38190792Sgshapiro	int entries = 0;
38290792Sgshapiro	int statp;
38390792Sgshapiro	int vsize;
38490792Sgshapiro	int ret;
38590792Sgshapiro	int save_errno;
38690792Sgshapiro	char *p;
38790792Sgshapiro
38890792Sgshapiro	/* Are we the top top level of the search? */
38990792Sgshapiro	toplevel = (recurse == NULL);
39090792Sgshapiro
39190792Sgshapiro	/* Get results */
39290792Sgshapiro	statp = EX_NOTFOUND;
39390792Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid, 0,
39490792Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
39590792Sgshapiro				   &(lmap->ldap_timeout)),
39690792Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
39790792Sgshapiro	{
39890792Sgshapiro		LDAPMessage *entry;
39990792Sgshapiro
40090792Sgshapiro		if (bitset(SM_LDAP_SINGLEMATCH, flags))
40190792Sgshapiro		{
40290792Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
40390792Sgshapiro						      lmap->ldap_res);
40490792Sgshapiro			if (entries > 1)
40590792Sgshapiro			{
40690792Sgshapiro				LDAPMAP_ERROR_CLEANUP();
40790792Sgshapiro				errno = ENOENT;
40890792Sgshapiro				return EX_NOTFOUND;
40990792Sgshapiro			}
41090792Sgshapiro		}
41190792Sgshapiro
41290792Sgshapiro		/* If we don't want multiple values and we have one, break */
41390792Sgshapiro		if (delim == '\0' && *result != NULL)
41490792Sgshapiro			break;
41590792Sgshapiro
41690792Sgshapiro		/* Cycle through all entries */
41790792Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
41890792Sgshapiro		     entry != NULL;
41990792Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
42090792Sgshapiro		{
42190792Sgshapiro			BerElement *ber;
42290792Sgshapiro			char *attr;
42390792Sgshapiro			char **vals = NULL;
42490792Sgshapiro			char *dn;
42590792Sgshapiro
42690792Sgshapiro			/*
42790792Sgshapiro			**  If matching only and found an entry,
42890792Sgshapiro			**  no need to spin through attributes
42990792Sgshapiro			*/
43090792Sgshapiro
43190792Sgshapiro			if (statp == EX_OK &&
43290792Sgshapiro			    bitset(SM_LDAP_MATCHONLY, flags))
43390792Sgshapiro				continue;
43490792Sgshapiro
43590792Sgshapiro			/* record completed DN's to prevent loops */
43690792Sgshapiro			dn = ldap_get_dn(lmap->ldap_ld, entry);
43790792Sgshapiro			if (dn == NULL)
43890792Sgshapiro			{
43990792Sgshapiro				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
44090792Sgshapiro				save_errno += E_LDAPBASE;
44190792Sgshapiro				LDAPMAP_ERROR_CLEANUP();
44290792Sgshapiro				errno = save_errno;
44390792Sgshapiro				return EX_OSERR;
44490792Sgshapiro			}
44590792Sgshapiro
44690792Sgshapiro			switch (ldapmap_add_recurse(&recurse, dn,
44790792Sgshapiro						    LDAPMAP_ATTR_NORMAL,
44890792Sgshapiro						    rpool))
44990792Sgshapiro			{
45090792Sgshapiro			  case -1:
45190792Sgshapiro				/* error adding */
45290792Sgshapiro				ldap_memfree(dn);
45390792Sgshapiro				LDAPMAP_ERROR_CLEANUP();
45490792Sgshapiro				errno = ENOMEM;
45590792Sgshapiro				return EX_OSERR;
45690792Sgshapiro
45790792Sgshapiro			  case 1:
45890792Sgshapiro				/* already on list, skip it */
45990792Sgshapiro				ldap_memfree(dn);
46090792Sgshapiro				continue;
46190792Sgshapiro			}
46290792Sgshapiro			ldap_memfree(dn);
46390792Sgshapiro
46490792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
46590792Sgshapiro			/*
46690792Sgshapiro			**  Reset value to prevent lingering
46790792Sgshapiro			**  LDAP_DECODING_ERROR due to
46890792Sgshapiro			**  OpenLDAP 1.X's hack (see below)
46990792Sgshapiro			*/
47090792Sgshapiro
47190792Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
47290792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
47390792Sgshapiro
47490792Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
47590792Sgshapiro							 &ber);
47690792Sgshapiro			     attr != NULL;
47790792Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
47890792Sgshapiro							ber))
47990792Sgshapiro			{
48090792Sgshapiro				char *tmp, *vp_tmp;
48190792Sgshapiro				int type;
48290792Sgshapiro
48390792Sgshapiro				for (i = 0; lmap->ldap_attr[i] != NULL; i++)
48490792Sgshapiro				{
48590792Sgshapiro					if (sm_strcasecmp(lmap->ldap_attr[i],
48690792Sgshapiro							  attr) == 0)
48790792Sgshapiro					{
48890792Sgshapiro						type = lmap->ldap_attr_type[i];
48990792Sgshapiro						break;
49090792Sgshapiro					}
49190792Sgshapiro				}
49290792Sgshapiro				if (lmap->ldap_attr[i] == NULL)
49390792Sgshapiro				{
49490792Sgshapiro					/* attribute not requested */
49590792Sgshapiro# if USING_NETSCAPE_LDAP
49690792Sgshapiro					ldap_memfree(attr);
49790792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
49890792Sgshapiro					LDAPMAP_ERROR_CLEANUP();
49990792Sgshapiro					errno = EFAULT;
50090792Sgshapiro					return EX_SOFTWARE;
50190792Sgshapiro				}
50290792Sgshapiro
50390792Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
50490792Sgshapiro				{
50590792Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
50690792Sgshapiro							       entry,
50790792Sgshapiro							       attr);
50890792Sgshapiro					if (vals == NULL)
50990792Sgshapiro					{
51090792Sgshapiro						save_errno = sm_ldap_geterrno(lmap->ldap_ld);
51190792Sgshapiro						if (save_errno == LDAP_SUCCESS)
51290792Sgshapiro						{
51390792Sgshapiro# if USING_NETSCAPE_LDAP
51490792Sgshapiro							ldap_memfree(attr);
51590792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
51690792Sgshapiro							continue;
51790792Sgshapiro						}
51890792Sgshapiro
51990792Sgshapiro						/* Must be an error */
52090792Sgshapiro						save_errno += E_LDAPBASE;
52190792Sgshapiro# if USING_NETSCAPE_LDAP
52290792Sgshapiro						ldap_memfree(attr);
52390792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
52490792Sgshapiro						LDAPMAP_ERROR_CLEANUP();
52590792Sgshapiro						errno = save_errno;
52690792Sgshapiro						return EX_TEMPFAIL;
52790792Sgshapiro					}
52890792Sgshapiro				}
52990792Sgshapiro
53090792Sgshapiro				statp = EX_OK;
53190792Sgshapiro
53290792Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
53390792Sgshapiro				/*
53490792Sgshapiro				**  Reset value to prevent lingering
53590792Sgshapiro				**  LDAP_DECODING_ERROR due to
53690792Sgshapiro				**  OpenLDAP 1.X's hack (see below)
53790792Sgshapiro				*/
53890792Sgshapiro
53990792Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
54090792Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
54190792Sgshapiro
54290792Sgshapiro				/*
54390792Sgshapiro				**  If matching only,
54490792Sgshapiro				**  no need to spin through entries
54590792Sgshapiro				*/
54690792Sgshapiro
54790792Sgshapiro				if (bitset(SM_LDAP_MATCHONLY, flags))
54890792Sgshapiro				{
54990792Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
55090792Sgshapiro						ldap_value_free(vals);
55190792Sgshapiro
55290792Sgshapiro# if USING_NETSCAPE_LDAP
55390792Sgshapiro					ldap_memfree(attr);
55490792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
55590792Sgshapiro					continue;
55690792Sgshapiro				}
55790792Sgshapiro
55890792Sgshapiro				/*
55990792Sgshapiro				**  If we don't want multiple values,
56090792Sgshapiro				**  return first found.
56190792Sgshapiro				*/
56290792Sgshapiro
56390792Sgshapiro				if (delim == '\0')
56490792Sgshapiro				{
56590792Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
56690792Sgshapiro					{
56790792Sgshapiro						*result = sm_rpool_strdup_x(rpool,
56890792Sgshapiro									    attr);
56990792Sgshapiro# if USING_NETSCAPE_LDAP
57090792Sgshapiro						ldap_memfree(attr);
57190792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
57290792Sgshapiro						break;
57390792Sgshapiro					}
57490792Sgshapiro
57590792Sgshapiro					if (vals[0] == NULL)
57690792Sgshapiro					{
57790792Sgshapiro						ldap_value_free(vals);
57890792Sgshapiro# if USING_NETSCAPE_LDAP
57990792Sgshapiro						ldap_memfree(attr);
58090792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
58190792Sgshapiro						continue;
58290792Sgshapiro					}
58390792Sgshapiro
58490792Sgshapiro					vsize = strlen(vals[0]) + 1;
58590792Sgshapiro					if (lmap->ldap_attrsep != '\0')
58690792Sgshapiro						vsize += strlen(attr) + 1;
58790792Sgshapiro					*result = sm_rpool_malloc_x(rpool,
58890792Sgshapiro								    vsize);
58990792Sgshapiro					if (lmap->ldap_attrsep != '\0')
59090792Sgshapiro						sm_snprintf(*result, vsize,
59190792Sgshapiro							    "%s%c%s",
59290792Sgshapiro							    attr,
59390792Sgshapiro							    lmap->ldap_attrsep,
59490792Sgshapiro							    vals[0]);
59590792Sgshapiro					else
59690792Sgshapiro						sm_strlcpy(*result, vals[0],
59790792Sgshapiro							   vsize);
59890792Sgshapiro					ldap_value_free(vals);
59990792Sgshapiro# if USING_NETSCAPE_LDAP
60090792Sgshapiro					ldap_memfree(attr);
60190792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
60290792Sgshapiro					break;
60390792Sgshapiro				}
60490792Sgshapiro
60590792Sgshapiro				/* attributes only */
60690792Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
60790792Sgshapiro				{
60890792Sgshapiro					if (*result == NULL)
60990792Sgshapiro						*result = sm_rpool_strdup_x(rpool,
61090792Sgshapiro									    attr);
61190792Sgshapiro					else
61290792Sgshapiro					{
61390792Sgshapiro						vsize = strlen(*result) +
61490792Sgshapiro							strlen(attr) + 2;
61590792Sgshapiro						tmp = sm_rpool_malloc_x(rpool,
61690792Sgshapiro									vsize);
61790792Sgshapiro						(void) sm_snprintf(tmp,
61890792Sgshapiro							vsize, "%s%c%s",
61990792Sgshapiro							*result, delim,
62090792Sgshapiro							attr);
62190792Sgshapiro						*result = tmp;
62290792Sgshapiro					}
62390792Sgshapiro# if USING_NETSCAPE_LDAP
62490792Sgshapiro					ldap_memfree(attr);
62590792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
62690792Sgshapiro					continue;
62790792Sgshapiro				}
62890792Sgshapiro
62990792Sgshapiro				/*
63090792Sgshapiro				**  If there is more than one,
63190792Sgshapiro				**  munge then into a map_coldelim
63290792Sgshapiro				**  separated string
63390792Sgshapiro				*/
63490792Sgshapiro
63590792Sgshapiro				vsize = 0;
63690792Sgshapiro				for (i = 0; vals[i] != NULL; i++)
63790792Sgshapiro				{
63890792Sgshapiro					if (type == LDAPMAP_ATTR_DN ||
63990792Sgshapiro					    type == LDAPMAP_ATTR_FILTER ||
64090792Sgshapiro					    type == LDAPMAP_ATTR_URL)
64190792Sgshapiro					{
64290792Sgshapiro						if (ldapmap_add_recurse(&recurse,
64390792Sgshapiro									vals[i],
64490792Sgshapiro									type) < 0)
64590792Sgshapiro						{
64690792Sgshapiro							LDAPMAP_ERROR_CLEANUP();
64790792Sgshapiro							errno = ENOMEM;
64890792Sgshapiro							return EX_OSERR;
64990792Sgshapiro						}
65090792Sgshapiro					}
65190792Sgshapiro					if (type != LDAPMAP_ATTR_NORMAL)
65290792Sgshapiro					{
65390792Sgshapiro#  if USING_NETSCAPE_LDAP
65490792Sgshapiro						ldap_memfree(attr);
65590792Sgshapiro#  endif /* USING_NETSCAPE_LDAP */
65690792Sgshapiro						continue;
65790792Sgshapiro					}
65890792Sgshapiro					vsize += strlen(vals[i]) + 1;
65990792Sgshapiro					if (lmap->ldap_attrsep != '\0')
66090792Sgshapiro						vsize += strlen(attr) + 1;
66190792Sgshapiro				}
66290792Sgshapiro				vp_tmp = sm_rpool_malloc_x(rpool, vsize);
66390792Sgshapiro				*vp_tmp = '\0';
66490792Sgshapiro
66590792Sgshapiro				p = vp_tmp;
66690792Sgshapiro				for (i = 0; vals[i] != NULL; i++)
66790792Sgshapiro				{
66890792Sgshapiro					if (lmap->ldap_attrsep != '\0')
66990792Sgshapiro					{
67090792Sgshapiro						p += sm_strlcpy(p, attr,
67190792Sgshapiro								vsize - (p - vp_tmp));
67290792Sgshapiro						*p++ = lmap->ldap_attrsep;
67390792Sgshapiro					}
67490792Sgshapiro					p += sm_strlcpy(p, vals[i],
67590792Sgshapiro							vsize - (p - vp_tmp));
67690792Sgshapiro					if (p >= vp_tmp + vsize)
67790792Sgshapiro					{
67890792Sgshapiro						/* Internal error: buffer too small for LDAP values */
67990792Sgshapiro						LDAPMAP_ERROR_CLEANUP();
68090792Sgshapiro						errno = ENOMEM;
68190792Sgshapiro						return EX_OSERR;
68290792Sgshapiro					}
68390792Sgshapiro					if (vals[i + 1] != NULL)
68490792Sgshapiro						*p++ = delim;
68590792Sgshapiro				}
68690792Sgshapiro
68790792Sgshapiro				ldap_value_free(vals);
68890792Sgshapiro# if USING_NETSCAPE_LDAP
68990792Sgshapiro				ldap_memfree(attr);
69090792Sgshapiro# endif /* USING_NETSCAPE_LDAP */
69190792Sgshapiro				if (*result == NULL)
69290792Sgshapiro				{
69390792Sgshapiro					*result = vp_tmp;
69490792Sgshapiro					continue;
69590792Sgshapiro				}
69690792Sgshapiro				vsize = strlen(*result) + strlen(vp_tmp) + 2;
69790792Sgshapiro				tmp = sm_rpool_malloc_x(rpool, vsize);
69890792Sgshapiro				(void) sm_snprintf(tmp, vsize, "%s%c%s",
69990792Sgshapiro						   *result, delim, vp_tmp);
70090792Sgshapiro				*result = tmp;
70190792Sgshapiro			}
70290792Sgshapiro			save_errno = sm_ldap_geterrno(lmap->ldap_ld);
70390792Sgshapiro
70490792Sgshapiro			/*
70590792Sgshapiro			**  We check save_errno != LDAP_DECODING_ERROR since
70690792Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
70790792Sgshapiro			**  hack of returning this error code from
70890792Sgshapiro			**  ldap_next_attribute() if the library freed the
70990792Sgshapiro			**  ber attribute.  See:
71090792Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
71190792Sgshapiro			*/
71290792Sgshapiro
71390792Sgshapiro			if (save_errno != LDAP_SUCCESS &&
71490792Sgshapiro			    save_errno != LDAP_DECODING_ERROR)
71590792Sgshapiro			{
71690792Sgshapiro				/* Must be an error */
71790792Sgshapiro				save_errno += E_LDAPBASE;
71890792Sgshapiro				LDAPMAP_ERROR_CLEANUP();
71990792Sgshapiro				errno = save_errno;
72090792Sgshapiro				return EX_TEMPFAIL;
72190792Sgshapiro			}
72290792Sgshapiro
72390792Sgshapiro			/* We don't want multiple values and we have one */
72490792Sgshapiro			if (delim == '\0' && *result != NULL)
72590792Sgshapiro				break;
72690792Sgshapiro		}
72790792Sgshapiro		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
72890792Sgshapiro		if (save_errno != LDAP_SUCCESS &&
72990792Sgshapiro		    save_errno != LDAP_DECODING_ERROR)
73090792Sgshapiro		{
73190792Sgshapiro			/* Must be an error */
73290792Sgshapiro			save_errno += E_LDAPBASE;
73390792Sgshapiro			LDAPMAP_ERROR_CLEANUP();
73490792Sgshapiro			errno = save_errno;
73590792Sgshapiro			return EX_TEMPFAIL;
73690792Sgshapiro		}
73790792Sgshapiro		ldap_msgfree(lmap->ldap_res);
73890792Sgshapiro		lmap->ldap_res = NULL;
73990792Sgshapiro	}
74090792Sgshapiro
74190792Sgshapiro	if (ret == 0)
74290792Sgshapiro		save_errno = ETIMEDOUT;
74390792Sgshapiro	else
74490792Sgshapiro		save_errno = sm_ldap_geterrno(lmap->ldap_ld);
74590792Sgshapiro	if (save_errno != LDAP_SUCCESS)
74690792Sgshapiro	{
74790792Sgshapiro		statp = EX_TEMPFAIL;
74890792Sgshapiro		if (ret != 0)
74990792Sgshapiro		{
75090792Sgshapiro			switch (save_errno)
75190792Sgshapiro			{
75290792Sgshapiro#ifdef LDAP_SERVER_DOWN
75390792Sgshapiro			  case LDAP_SERVER_DOWN:
75490792Sgshapiro#endif /* LDAP_SERVER_DOWN */
75590792Sgshapiro			  case LDAP_TIMEOUT:
75690792Sgshapiro			  case LDAP_UNAVAILABLE:
75790792Sgshapiro				/* server disappeared, try reopen on next search */
75890792Sgshapiro				statp = EX_RESTART;
75990792Sgshapiro				break;
76090792Sgshapiro			}
76190792Sgshapiro			save_errno += E_LDAPBASE;
76290792Sgshapiro		}
76390792Sgshapiro		LDAPMAP_ERROR_CLEANUP();
76490792Sgshapiro		errno = save_errno;
76590792Sgshapiro		return statp;
76690792Sgshapiro	}
76790792Sgshapiro
76890792Sgshapiro	if (lmap->ldap_res != NULL)
76990792Sgshapiro	{
77090792Sgshapiro		ldap_msgfree(lmap->ldap_res);
77190792Sgshapiro		lmap->ldap_res = NULL;
77290792Sgshapiro	}
77390792Sgshapiro
77490792Sgshapiro	if (toplevel)
77590792Sgshapiro	{
77690792Sgshapiro		SM_LDAP_RECURSE_LIST *rl;
77790792Sgshapiro
77890792Sgshapiro		/*
77990792Sgshapiro		**  Spin through the built-up recurse list at the top
78090792Sgshapiro		**  of the recursion.  Since new items are added at the
78190792Sgshapiro		**  end of the shared list, we actually only ever get
78290792Sgshapiro		**  one level of recursion before things pop back to the
78390792Sgshapiro		**  top.  Any items added to the list during that recursion
78490792Sgshapiro		**  will be expanded by the top level.
78590792Sgshapiro		*/
78690792Sgshapiro
78790792Sgshapiro		for (rl = recurse; rl != NULL; rl = rl->lr_next)
78890792Sgshapiro		{
78990792Sgshapiro			int sid;
79090792Sgshapiro			int status;
79190792Sgshapiro
79290792Sgshapiro			if (rl->lr_type == LDAPMAP_ATTR_NORMAL)
79390792Sgshapiro			{
79490792Sgshapiro				/* already expanded */
79590792Sgshapiro				continue;
79690792Sgshapiro			}
79790792Sgshapiro			else if (rl->lr_type == LDAPMAP_ATTR_DN)
79890792Sgshapiro			{
79990792Sgshapiro				/* do DN search */
80090792Sgshapiro				sid = ldap_search(lmap->ldap_ld,
80190792Sgshapiro						  rl->lr_search,
80290792Sgshapiro						  lmap->ldap_scope,
80390792Sgshapiro						  "(objectClass=*)",
80490792Sgshapiro						  lmap->ldap_attr_final,
80590792Sgshapiro						  lmap->ldap_attrsonly);
80690792Sgshapiro			}
80790792Sgshapiro			else if (rl->lr_type == LDAPMAP_ATTR_FILTER)
80890792Sgshapiro			{
80990792Sgshapiro				/* do new search */
81090792Sgshapiro				sid = ldap_search(lmap->ldap_ld,
81190792Sgshapiro						  lmap->ldap_base,
81290792Sgshapiro						  lmap->ldap_scope,
81390792Sgshapiro						  rl->lr_search,
81490792Sgshapiro						  lmap->ldap_attr_final,
81590792Sgshapiro						  lmap->ldap_attrsonly);
81690792Sgshapiro			}
81790792Sgshapiro			else if (rl->lr_type == LDAPMAP_ATTR_URL)
81890792Sgshapiro			{
81990792Sgshapiro				/* do new URL search */
82090792Sgshapiro				sid = ldap_url_search(lmap->ldap_ld,
82190792Sgshapiro						      rl->lr_search,
82290792Sgshapiro						      lmap->ldap_attrsonly);
82390792Sgshapiro			}
82490792Sgshapiro			else
82590792Sgshapiro			{
82690792Sgshapiro				/* unknown or illegal attribute type */
82790792Sgshapiro				errno = EFAULT;
82890792Sgshapiro				return EX_SOFTWARE;
82990792Sgshapiro			}
83090792Sgshapiro
83190792Sgshapiro			/* Collect results */
83290792Sgshapiro			if (sid == -1)
83390792Sgshapiro			{
83490792Sgshapiro				save_errno = sm_ldap_geterrno(lmap->ldap_ld);
83590792Sgshapiro				statp = EX_TEMPFAIL;
83690792Sgshapiro				switch (save_errno)
83790792Sgshapiro				{
83890792Sgshapiro#ifdef LDAP_SERVER_DOWN
83990792Sgshapiro				  case LDAP_SERVER_DOWN:
84090792Sgshapiro#endif /* LDAP_SERVER_DOWN */
84190792Sgshapiro				  case LDAP_TIMEOUT:
84290792Sgshapiro				  case LDAP_UNAVAILABLE:
84390792Sgshapiro					/* server disappeared, try reopen on next search */
84490792Sgshapiro					statp = EX_RESTART;
84590792Sgshapiro					break;
84690792Sgshapiro				}
84790792Sgshapiro				errno = save_errno + E_LDAPBASE;
84890792Sgshapiro				return statp;
84990792Sgshapiro			}
85090792Sgshapiro
85190792Sgshapiro			status = sm_ldap_results(lmap, sid, flags, delim,
85290792Sgshapiro						 rpool, result, recurse);
85390792Sgshapiro			save_errno = errno;
85490792Sgshapiro			if (status != EX_OK && status != EX_NOTFOUND)
85590792Sgshapiro			{
85690792Sgshapiro				errno = save_errno;
85790792Sgshapiro				return status;
85890792Sgshapiro			}
85990792Sgshapiro
86090792Sgshapiro			/* Mark as done */
86190792Sgshapiro			rl->lr_type = LDAPMAP_ATTR_NORMAL;
86290792Sgshapiro		}
86390792Sgshapiro	}
86490792Sgshapiro	return statp;
86590792Sgshapiro}
86690792Sgshapiro#endif /* _FFR_LDAP_RECURSION */
86790792Sgshapiro
86890792Sgshapiro/*
86990792Sgshapiro**  SM_LDAP_CLOSE -- close LDAP connection
87090792Sgshapiro**
87190792Sgshapiro**	Parameters:
87290792Sgshapiro**		lmap -- LDAP map information
87390792Sgshapiro**
87490792Sgshapiro**	Returns:
87590792Sgshapiro**		None.
87690792Sgshapiro**
87790792Sgshapiro*/
87890792Sgshapiro
87990792Sgshapirovoid
88090792Sgshapirosm_ldap_close(lmap)
88190792Sgshapiro	SM_LDAP_STRUCT *lmap;
88290792Sgshapiro{
88390792Sgshapiro	if (lmap->ldap_ld == NULL)
88490792Sgshapiro		return;
88590792Sgshapiro
88690792Sgshapiro	if (lmap->ldap_pid == getpid())
88790792Sgshapiro		ldap_unbind(lmap->ldap_ld);
88890792Sgshapiro	lmap->ldap_ld = NULL;
88990792Sgshapiro	lmap->ldap_pid = 0;
89090792Sgshapiro}
89190792Sgshapiro
89290792Sgshapiro/*
89390792Sgshapiro**  SM_LDAP_SETOPTS -- set LDAP options
89490792Sgshapiro**
89590792Sgshapiro**	Parameters:
89690792Sgshapiro**		ld -- LDAP session handle
89790792Sgshapiro**		lmap -- LDAP map information
89890792Sgshapiro**
89990792Sgshapiro**	Returns:
90090792Sgshapiro**		None.
90190792Sgshapiro**
90290792Sgshapiro*/
90390792Sgshapiro
90490792Sgshapirovoid
90590792Sgshapirosm_ldap_setopts(ld, lmap)
90690792Sgshapiro	LDAP *ld;
90790792Sgshapiro	SM_LDAP_STRUCT *lmap;
90890792Sgshapiro{
90990792Sgshapiro# if USE_LDAP_SET_OPTION
91090792Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
91190792Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
91290792Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
91390792Sgshapiro	else
91490792Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
91590792Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
91690792Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
91790792Sgshapiro# else /* USE_LDAP_SET_OPTION */
91890792Sgshapiro	/* From here on in we can use ldap internal timelimits */
91990792Sgshapiro	ld->ld_deref = lmap->ldap_deref;
92090792Sgshapiro	ld->ld_options = lmap->ldap_options;
92190792Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
92290792Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
92390792Sgshapiro# endif /* USE_LDAP_SET_OPTION */
92490792Sgshapiro}
92590792Sgshapiro
92690792Sgshapiro/*
92790792Sgshapiro**  SM_LDAP_GETERRNO -- get ldap errno value
92890792Sgshapiro**
92990792Sgshapiro**	Parameters:
93090792Sgshapiro**		ld -- LDAP session handle
93190792Sgshapiro**
93290792Sgshapiro**	Returns:
93390792Sgshapiro**		LDAP errno.
93490792Sgshapiro**
93590792Sgshapiro*/
93690792Sgshapiro
93790792Sgshapiroint
93890792Sgshapirosm_ldap_geterrno(ld)
93990792Sgshapiro	LDAP *ld;
94090792Sgshapiro{
94190792Sgshapiro	int err = LDAP_SUCCESS;
94290792Sgshapiro
94390792Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
94490792Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
94590792Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
94690792Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
94790792Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
94890792Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
94990792Sgshapiro	err = ld->ld_errno;
95090792Sgshapiro
95190792Sgshapiro	/*
95290792Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
95390792Sgshapiro	**  OpenLDAP 1.X's hack (see above)
95490792Sgshapiro	*/
95590792Sgshapiro
95690792Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
95790792Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
95890792Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
95990792Sgshapiro	return err;
96090792Sgshapiro}
96190792Sgshapiro# endif /* LDAPMAP */
962