diff options
Diffstat (limited to 'contrib/sendmail/libsm/ldap.c')
| -rw-r--r-- | contrib/sendmail/libsm/ldap.c | 524 | 
1 files changed, 386 insertions, 138 deletions
| diff --git a/contrib/sendmail/libsm/ldap.c b/contrib/sendmail/libsm/ldap.c index a431511e079df..3e85a87664e09 100644 --- a/contrib/sendmail/libsm/ldap.c +++ b/contrib/sendmail/libsm/ldap.c @@ -8,7 +8,7 @@   */  #include <sm/gen.h> -SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $") +SM_RCSID("@(#)$Id: ldap.c,v 1.44 2002/02/22 21:54:02 gshapiro Exp $")  #if LDAPMAP  # include <sys/types.h> @@ -24,6 +24,9 @@ SM_RCSID("@(#)$Id: ldap.c,v 1.18 2002/01/11 22:06:51 gshapiro Exp $")  # include <sm/errstring.h>  # include <sm/ldap.h>  # include <sm/string.h> +#  ifdef EX_OK +#   undef EX_OK			/* for SVr4.2 SMP */ +#  endif /* EX_OK */  # include <sm/sysexits.h>  SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap", @@ -49,8 +52,14 @@ sm_ldap_clear(lmap)  	if (lmap == NULL)  		return; -	lmap->ldap_host = NULL; +	lmap->ldap_target = NULL;  	lmap->ldap_port = LDAP_PORT; +#if _FFR_LDAP_URI +	lmap->ldap_uri = false; +#endif /* _FFR_LDAP_URI */ +#  if _FFR_LDAP_SETVERSION +	lmap->ldap_version = 0; +#  endif /* _FFR_LDAP_SETVERSION */  	lmap->ldap_deref = LDAP_DEREF_NEVER;  	lmap->ldap_timelimit = LDAP_NO_LIMIT;  	lmap->ldap_sizelimit = LDAP_NO_LIMIT; @@ -72,8 +81,8 @@ sm_ldap_clear(lmap)  	lmap->ldap_filter = NULL;  	lmap->ldap_attr[0] = NULL;  #if _FFR_LDAP_RECURSION -	lmap->ldap_attr_type[0] = LDAPMAP_ATTR_NORMAL; -	lmap->ldap_attr_final[0] = NULL; +	lmap->ldap_attr_type[0] = SM_LDAP_ATTR_NONE; +	lmap->ldap_attr_needobjclass[0] = NULL;  #endif /* _FFR_LDAP_RECURSION */  	lmap->ldap_res = NULL;  	lmap->ldap_next = NULL; @@ -132,11 +141,16 @@ sm_ldap_start(name, lmap)  	if (sm_debug_active(&SmLDAPTrace, 9))  		sm_dprintf("ldapmap_start(%s, %d)\n", -			   lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host, +			   lmap->ldap_target == NULL ? "localhost" : lmap->ldap_target,  			   lmap->ldap_port);  # if USE_LDAP_INIT -	ld = ldap_init(lmap->ldap_host, lmap->ldap_port); +#  if _FFR_LDAP_URI +	if (lmap->ldap_uri) +		errno = ldap_initialize(&ld, lmap->ldap_target); +	else +#  endif /* _FFR_LDAP_URI */ +		ld = ldap_init(lmap->ldap_target, lmap->ldap_port);  	save_errno = errno;  # else /* USE_LDAP_INIT */  	/* @@ -146,7 +160,7 @@ sm_ldap_start(name, lmap)  	*/  	SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec); -	ld = ldap_open(lmap->ldap_host, lmap->ldap_port); +	ld = ldap_open(lmap->ldap_target, lmap->ldap_port);  	save_errno = errno;  	/* clear the event if it has not sprung */ @@ -297,8 +311,8 @@ sm_ldap_search(lmap, key)  		sm_dprintf("ldap search filter=%s\n", filter);  	lmap->ldap_res = NULL; -	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope, -			    filter, +	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, +			    lmap->ldap_scope, filter,  			    (lmap->ldap_attr[0] == NULL ? NULL :  			     lmap->ldap_attr),  			    lmap->ldap_attrsonly); @@ -307,6 +321,66 @@ sm_ldap_search(lmap, key)  # if _FFR_LDAP_RECURSION  /* +**  SM_LDAP_HAS_OBJECTCLASS -- determine if an LDAP entry is part of a +**			       particular objectClass +** +**	Parameters: +**		lmap -- pointer to SM_LDAP_STRUCT in use +**		entry -- current LDAP entry struct +**		ocvalue -- particular objectclass in question. +**			   may be of form (fee|foo|fum) meaning +**			   any entry can be part of either fee, +**			   foo or fum objectclass +** +**	Returns: +**		true if item has that objectClass +*/ + +static bool +sm_ldap_has_objectclass(lmap, entry, ocvalue) +	SM_LDAP_STRUCT *lmap; +	LDAPMessage *entry; +	char *ocvalue; +{ +	char **vals = NULL; +	int i; + +	if (ocvalue == NULL) +		return false; + +	vals = ldap_get_values(lmap->ldap_ld, entry, "objectClass"); +	if (vals == NULL) +		return false; + +	for (i = 0; vals[i] != NULL; i++) +	{ +		char *p; +		char *q; + +		p = q = ocvalue; +		while (*p != '\0') +		{ +			while (*p != '\0' && *p != '|') +				p++; + +			if ((p - q) == strlen(vals[i]) && +			    sm_strncasecmp(vals[i], q, p - q) == 0) +			{ +				ldap_value_free(vals); +				return true; +			} + +			while (*p == '|') +				p++; +			q = p; +		} +	} + +	ldap_value_free(vals); +	return false; +} + +/*  **  SM_LDAP_RESULTS -- return results from an LDAP lookup in result  **  **	Parameters: @@ -322,7 +396,7 @@ sm_ldap_search(lmap, key)  **		status (sysexit)  */ -# define LDAPMAP_ERROR_CLEANUP()				\ +# define SM_LDAP_ERROR_CLEANUP()				\  {								\  	if (lmap->ldap_res != NULL)				\  	{							\ @@ -332,58 +406,138 @@ sm_ldap_search(lmap, key)  	(void) ldap_abandon(lmap->ldap_ld, msgid);		\  } -static int -ldapmap_add_recurse(top, item, type, rpool) +static SM_LDAP_RECURSE_ENTRY * +sm_ldap_add_recurse(top, item, type, rpool)  	SM_LDAP_RECURSE_LIST **top;  	char *item;  	int type;  	SM_RPOOL_T *rpool;  { -	SM_LDAP_RECURSE_LIST *p; -	SM_LDAP_RECURSE_LIST *last; +	int n; +	int m; +	int p; +	int insertat; +	int moveb; +	int oldsizeb; +	int rc; +	SM_LDAP_RECURSE_ENTRY *newe; +	SM_LDAP_RECURSE_ENTRY **olddata; + +	/* +	**  This code will maintain a list of +	**  SM_LDAP_RECURSE_ENTRY structures +	**  in ascending order. +	*/ + +	if (*top == NULL) +	{ +		/* Allocate an initial SM_LDAP_RECURSE_LIST struct */ +		*top = sm_rpool_malloc_x(rpool, sizeof **top); +		(*top)->lr_cnt = 0; +		(*top)->lr_size = 0; +		(*top)->lr_data = NULL; +	} -	last = NULL; -	for (p = *top; p != NULL; p = p->lr_next) +	if ((*top)->lr_cnt >= (*top)->lr_size)  	{ -		if (strcasecmp(item, p->lr_search) == 0 && -		    type == p->lr_type) +		/* Grow the list of SM_LDAP_RECURSE_ENTRY ptrs */ +		olddata = (*top)->lr_data; +		if ((*top)->lr_size == 0)  		{ -			/* already on list */ -			return 1; +			oldsizeb = 0; +			(*top)->lr_size = 256;  		} -		last = p; +		else +		{ +			oldsizeb = (*top)->lr_size * sizeof *((*top)->lr_data); +			(*top)->lr_size *= 2; +		} +		(*top)->lr_data = sm_rpool_malloc_x(rpool, +						    (*top)->lr_size * sizeof *((*top)->lr_data)); +		if (oldsizeb > 0) +			memcpy((*top)->lr_data, olddata, oldsizeb);  	} -	/* not on list, add it */ -	p = sm_rpool_malloc_x(rpool, sizeof *p); -	p->lr_search = sm_rpool_strdup_x(rpool, item); -	p->lr_type = type; -	p->lr_next = NULL; -	if (last == NULL) -		*top = p; +	/* +	**  Binary search/insert item:type into list. +	**  Return current entry pointer if already exists. +	*/ + +	n = 0; +	m = (*top)->lr_cnt - 1; +	if (m < 0) +		insertat = 0;  	else -		last->lr_next = p; -	return 0; +		insertat = -1; + +	while (insertat == -1) +	{ +		p = (m + n) / 2; + +		rc = sm_strcasecmp(item, (*top)->lr_data[p]->lr_search); +		if (rc == 0) +			rc = type - (*top)->lr_data[p]->lr_type; + +		if (rc < 0) +			m = p - 1; +		else if (rc > 0) +			n = p + 1; +		else +			return (*top)->lr_data[p]; + +		if (m == -1) +			insertat = 0; +		else if (n >= (*top)->lr_cnt) +			insertat = (*top)->lr_cnt; +		else if (m < n) +			insertat = m + 1; +	} + +	/* +	** Not found in list, make room +	** at insert point and add it. +	*/ + +	newe = sm_rpool_malloc_x(rpool, sizeof *newe); +	if (newe != NULL) +	{ +		moveb = ((*top)->lr_cnt - insertat) * sizeof *((*top)->lr_data); +		if (moveb > 0) +			memmove(&((*top)->lr_data[insertat + 1]), +				&((*top)->lr_data[insertat]), +				moveb); + +		newe->lr_search = sm_rpool_strdup_x(rpool, item); +		newe->lr_type = type; +		newe->lr_done = false; + +		((*top)->lr_data)[insertat] = newe; +		(*top)->lr_cnt++; +	} +	return newe;  }  int -sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse) +sm_ldap_results(lmap, msgid, flags, delim, rpool, result, +		resultln, resultsz, recurse)  	SM_LDAP_STRUCT *lmap;  	int msgid;  	int flags; -	char delim; +	int delim;  	SM_RPOOL_T *rpool;  	char **result; +	int *resultln; +	int *resultsz;  	SM_LDAP_RECURSE_LIST *recurse;  {  	bool toplevel;  	int i; -	int entries = 0;  	int statp;  	int vsize;  	int ret;  	int save_errno;  	char *p; +	SM_LDAP_RECURSE_ENTRY *rl;  	/* Are we the top top level of the search? */  	toplevel = (recurse == NULL); @@ -397,20 +551,8 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  	{  		LDAPMessage *entry; -		if (bitset(SM_LDAP_SINGLEMATCH, flags)) -		{ -			entries += ldap_count_entries(lmap->ldap_ld, -						      lmap->ldap_res); -			if (entries > 1) -			{ -				LDAPMAP_ERROR_CLEANUP(); -				errno = ENOENT; -				return EX_NOTFOUND; -			} -		} -  		/* If we don't want multiple values and we have one, break */ -		if (delim == '\0' && *result != NULL) +		if ((char) delim == '\0' && *result != NULL)  			break;  		/* Cycle through all entries */ @@ -438,23 +580,24 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  			{  				save_errno = sm_ldap_geterrno(lmap->ldap_ld);  				save_errno += E_LDAPBASE; -				LDAPMAP_ERROR_CLEANUP(); +				SM_LDAP_ERROR_CLEANUP();  				errno = save_errno;  				return EX_OSERR;  			} -			switch (ldapmap_add_recurse(&recurse, dn, -						    LDAPMAP_ATTR_NORMAL, -						    rpool)) +			rl = sm_ldap_add_recurse(&recurse, dn, +						 SM_LDAP_ATTR_DN, +						 rpool); + +			if (rl == NULL)  			{ -			  case -1: -				/* error adding */  				ldap_memfree(dn); -				LDAPMAP_ERROR_CLEANUP(); +				SM_LDAP_ERROR_CLEANUP();  				errno = ENOMEM;  				return EX_OSERR; - -			  case 1: +			} +			else if (rl->lr_done) +			{  				/* already on list, skip it */  				ldap_memfree(dn);  				continue; @@ -479,27 +622,54 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  			{  				char *tmp, *vp_tmp;  				int type; +				char *needobjclass = NULL; +				type = SM_LDAP_ATTR_NONE;  				for (i = 0; lmap->ldap_attr[i] != NULL; i++)  				{  					if (sm_strcasecmp(lmap->ldap_attr[i],  							  attr) == 0)  					{  						type = lmap->ldap_attr_type[i]; +						needobjclass = lmap->ldap_attr_needobjclass[i];  						break;  					}  				} -				if (lmap->ldap_attr[i] == NULL) + +				if (bitset(SM_LDAP_USE_ALLATTR, flags) && +				    type == SM_LDAP_ATTR_NONE) +				{ +					/* URL lookups specify attrs to use */ +					type = SM_LDAP_ATTR_NORMAL; +					needobjclass = NULL; +				} + +				if (type == SM_LDAP_ATTR_NONE)  				{  					/* attribute not requested */ -# if USING_NETSCAPE_LDAP  					ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */ -					LDAPMAP_ERROR_CLEANUP(); +					SM_LDAP_ERROR_CLEANUP();  					errno = EFAULT;  					return EX_SOFTWARE;  				} +				/* +				**  For recursion on a particular attribute, +				**  we may need to see if this entry is +				**  part of a particular objectclass. +				**  Also, ignore objectClass attribute. +				**  Otherwise we just ignore this attribute. +				*/ + +				if (type == SM_LDAP_ATTR_OBJCLASS || +				    (needobjclass != NULL && +				     !sm_ldap_has_objectclass(lmap, entry, +							      needobjclass))) +				{ +					ldap_memfree(attr); +					continue; +				} +  				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)  				{  					vals = ldap_get_values(lmap->ldap_ld, @@ -510,18 +680,14 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  						save_errno = sm_ldap_geterrno(lmap->ldap_ld);  						if (save_errno == LDAP_SUCCESS)  						{ -# if USING_NETSCAPE_LDAP  							ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  							continue;  						}  						/* Must be an error */  						save_errno += E_LDAPBASE; -# if USING_NETSCAPE_LDAP  						ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */ -						LDAPMAP_ERROR_CLEANUP(); +						SM_LDAP_ERROR_CLEANUP();  						errno = save_errno;  						return EX_TEMPFAIL;  					} @@ -548,10 +714,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  				{  					if (lmap->ldap_attrsonly == LDAPMAP_FALSE)  						ldap_value_free(vals); - -# if USING_NETSCAPE_LDAP  					ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  					continue;  				} @@ -560,24 +723,36 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  				**  return first found.  				*/ -				if (delim == '\0') +				if ((char) delim == '\0')  				{ +					if (*result != NULL) +					{ +						/* already have a value */ +						break; +					} + +					if (bitset(SM_LDAP_SINGLEMATCH, +						   flags) && +					    *result != NULL) +					{ +						/* only wanted one match */ +						SM_LDAP_ERROR_CLEANUP(); +						errno = ENOENT; +						return EX_NOTFOUND; +					} +  					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)  					{  						*result = sm_rpool_strdup_x(rpool,  									    attr); -# if USING_NETSCAPE_LDAP  						ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  						break;  					}  					if (vals[0] == NULL)  					{  						ldap_value_free(vals); -# if USING_NETSCAPE_LDAP  						ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  						continue;  					} @@ -596,9 +771,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  						sm_strlcpy(*result, vals[0],  							   vsize);  					ldap_value_free(vals); -# if USING_NETSCAPE_LDAP  					ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  					break;  				} @@ -610,94 +783,137 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  									    attr);  					else  					{ +						if (bitset(SM_LDAP_SINGLEMATCH, +							   flags) && +						    *result != NULL) +						{ +							/* only wanted one match */ +							SM_LDAP_ERROR_CLEANUP(); +							errno = ENOENT; +							return EX_NOTFOUND; +						} +  						vsize = strlen(*result) +  							strlen(attr) + 2;  						tmp = sm_rpool_malloc_x(rpool,  									vsize);  						(void) sm_snprintf(tmp,  							vsize, "%s%c%s", -							*result, delim, +							*result, (char) delim,  							attr);  						*result = tmp;  					} -# if USING_NETSCAPE_LDAP  					ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */  					continue;  				}  				/* -				**  If there is more than one, -				**  munge then into a map_coldelim -				**  separated string +				**  If there is more than one, munge then +				**  into a map_coldelim separated string. +				**  If we are recursing we may have an entry +				**  with no 'normal' values to put in the +				**  string. +				**  This is not an error.  				*/ +				if (type == SM_LDAP_ATTR_NORMAL && +				    bitset(SM_LDAP_SINGLEMATCH, flags) && +				    *result != NULL) +				{ +					/* only wanted one match */ +					SM_LDAP_ERROR_CLEANUP(); +					errno = ENOENT; +					return EX_NOTFOUND; +				} +  				vsize = 0;  				for (i = 0; vals[i] != NULL; i++)  				{ -					if (type == LDAPMAP_ATTR_DN || -					    type == LDAPMAP_ATTR_FILTER || -					    type == LDAPMAP_ATTR_URL) +					if (type == SM_LDAP_ATTR_DN || +					    type == SM_LDAP_ATTR_FILTER || +					    type == SM_LDAP_ATTR_URL)  					{ -						if (ldapmap_add_recurse(&recurse, +						/* add to recursion */ +						if (sm_ldap_add_recurse(&recurse,  									vals[i], -									type) < 0) +									type, +									rpool) == NULL)  						{ -							LDAPMAP_ERROR_CLEANUP(); +							SM_LDAP_ERROR_CLEANUP();  							errno = ENOMEM;  							return EX_OSERR;  						} -					} -					if (type != LDAPMAP_ATTR_NORMAL) -					{ -#  if USING_NETSCAPE_LDAP -						ldap_memfree(attr); -#  endif /* USING_NETSCAPE_LDAP */  						continue;  					} +  					vsize += strlen(vals[i]) + 1;  					if (lmap->ldap_attrsep != '\0')  						vsize += strlen(attr) + 1;  				} -				vp_tmp = sm_rpool_malloc_x(rpool, vsize); -				*vp_tmp = '\0'; -				p = vp_tmp; -				for (i = 0; vals[i] != NULL; i++) +				/* +				**  Create/Append to string any normal +				**  attribute values.  Otherwise, just free +				**  memory and move on to the next +				**  attribute in this entry. +				*/ + +				if (type == SM_LDAP_ATTR_NORMAL && vsize > 0)  				{ -					if (lmap->ldap_attrsep != '\0') +					char *pe; + +					/* Grow result string if needed */ +					if ((*resultln + vsize) >= *resultsz)  					{ -						p += sm_strlcpy(p, attr, -								vsize - (p - vp_tmp)); -						*p++ = lmap->ldap_attrsep; +						while ((*resultln + vsize) >= *resultsz) +						{ +							if (*resultsz == 0) +								*resultsz = 1024; +							else +								*resultsz *= 2; +						} + +						vp_tmp = sm_rpool_malloc_x(rpool, *resultsz); +						*vp_tmp = '\0'; + +						if (*result != NULL) +							sm_strlcpy(vp_tmp, +								   *result, +								   *resultsz); +						*result = vp_tmp;  					} -					p += sm_strlcpy(p, vals[i], -							vsize - (p - vp_tmp)); -					if (p >= vp_tmp + vsize) + +					p = *result + *resultln; +					pe = *result + *resultsz; + +					for (i = 0; vals[i] != NULL; i++)  					{ -						/* Internal error: buffer too small for LDAP values */ -						LDAPMAP_ERROR_CLEANUP(); -						errno = ENOMEM; -						return EX_OSERR; +						if (*resultln > 0) +							*p++ = (char) delim; + +						if (lmap->ldap_attrsep != '\0') +						{ +							p += sm_strlcpy(p, attr, +									pe - p); +							if (p < pe) +								*p++ = lmap->ldap_attrsep; +						} + +						p += sm_strlcpy(p, vals[i], +								pe - p); +						*resultln = p - (*result); +						if (p >= pe) +						{ +							/* Internal error: buffer too small for LDAP values */ +							SM_LDAP_ERROR_CLEANUP(); +							errno = ENOMEM; +							return EX_OSERR; +						}  					} -					if (vals[i + 1] != NULL) -						*p++ = delim;  				}  				ldap_value_free(vals); -# if USING_NETSCAPE_LDAP  				ldap_memfree(attr); -# endif /* USING_NETSCAPE_LDAP */ -				if (*result == NULL) -				{ -					*result = vp_tmp; -					continue; -				} -				vsize = strlen(*result) + strlen(vp_tmp) + 2; -				tmp = sm_rpool_malloc_x(rpool, vsize); -				(void) sm_snprintf(tmp, vsize, "%s%c%s", -						   *result, delim, vp_tmp); -				*result = tmp;  			}  			save_errno = sm_ldap_geterrno(lmap->ldap_ld); @@ -715,13 +931,16 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  			{  				/* Must be an error */  				save_errno += E_LDAPBASE; -				LDAPMAP_ERROR_CLEANUP(); +				SM_LDAP_ERROR_CLEANUP();  				errno = save_errno;  				return EX_TEMPFAIL;  			} +			/* mark this DN as done */ +			rl->lr_done = true; +  			/* We don't want multiple values and we have one */ -			if (delim == '\0' && *result != NULL) +			if ((char) delim == '\0' && *result != NULL)  				break;  		}  		save_errno = sm_ldap_geterrno(lmap->ldap_ld); @@ -730,7 +949,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  		{  			/* Must be an error */  			save_errno += E_LDAPBASE; -			LDAPMAP_ERROR_CLEANUP(); +			SM_LDAP_ERROR_CLEANUP();  			errno = save_errno;  			return EX_TEMPFAIL;  		} @@ -754,13 +973,18 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  #endif /* LDAP_SERVER_DOWN */  			  case LDAP_TIMEOUT:  			  case LDAP_UNAVAILABLE: -				/* server disappeared, try reopen on next search */ + +				/* +				**  server disappeared, +				**  try reopen on next search +				*/ +  				statp = EX_RESTART;  				break;  			}  			save_errno += E_LDAPBASE;  		} -		LDAPMAP_ERROR_CLEANUP(); +		SM_LDAP_ERROR_CLEANUP();  		errno = save_errno;  		return statp;  	} @@ -773,7 +997,7 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  	if (toplevel)  	{ -		SM_LDAP_RECURSE_LIST *rl; +		int rlidx;  		/*  		**  Spin through the built-up recurse list at the top @@ -784,42 +1008,50 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  		**  will be expanded by the top level.  		*/ -		for (rl = recurse; rl != NULL; rl = rl->lr_next) +		for (rlidx = 0; recurse != NULL && rlidx < recurse->lr_cnt; rlidx++)  		{ +			int newflags;  			int sid;  			int status; -			if (rl->lr_type == LDAPMAP_ATTR_NORMAL) +			rl = recurse->lr_data[rlidx]; + +			newflags = flags; +			if (rl->lr_done)  			{  				/* already expanded */  				continue;  			} -			else if (rl->lr_type == LDAPMAP_ATTR_DN) + +			if (rl->lr_type == SM_LDAP_ATTR_DN)  			{  				/* do DN search */  				sid = ldap_search(lmap->ldap_ld,  						  rl->lr_search,  						  lmap->ldap_scope,  						  "(objectClass=*)", -						  lmap->ldap_attr_final, +						  (lmap->ldap_attr[0] == NULL ? +						   NULL : lmap->ldap_attr),  						  lmap->ldap_attrsonly);  			} -			else if (rl->lr_type == LDAPMAP_ATTR_FILTER) +			else if (rl->lr_type == SM_LDAP_ATTR_FILTER)  			{  				/* do new search */  				sid = ldap_search(lmap->ldap_ld,  						  lmap->ldap_base,  						  lmap->ldap_scope,  						  rl->lr_search, -						  lmap->ldap_attr_final, +						  (lmap->ldap_attr[0] == NULL ? +						   NULL : lmap->ldap_attr),  						  lmap->ldap_attrsonly);  			} -			else if (rl->lr_type == LDAPMAP_ATTR_URL) +			else if (rl->lr_type == SM_LDAP_ATTR_URL)  			{  				/* do new URL search */  				sid = ldap_url_search(lmap->ldap_ld,  						      rl->lr_search,  						      lmap->ldap_attrsonly); +				newflags |= SM_LDAP_USE_ALLATTR;  			}  			else  			{ @@ -840,7 +1072,12 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  #endif /* LDAP_SERVER_DOWN */  				  case LDAP_TIMEOUT:  				  case LDAP_UNAVAILABLE: -					/* server disappeared, try reopen on next search */ + +					/* +					**  server disappeared, +					**  try reopen on next search +					*/ +  					statp = EX_RESTART;  					break;  				} @@ -848,8 +1085,9 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  				return statp;  			} -			status = sm_ldap_results(lmap, sid, flags, delim, -						 rpool, result, recurse); +			status = sm_ldap_results(lmap, sid, newflags, delim, +						 rpool, result, resultln, +						 resultsz, recurse);  			save_errno = errno;  			if (status != EX_OK && status != EX_NOTFOUND)  			{ @@ -858,7 +1096,10 @@ sm_ldap_results(lmap, msgid, flags, delim, rpool, result, recurse)  			}  			/* Mark as done */ -			rl->lr_type = LDAPMAP_ATTR_NORMAL; +			rl->lr_done = true; + +			/* Reset rlidx as new items may have been added */ +			rlidx = -1;  		}  	}  	return statp; @@ -907,6 +1148,13 @@ sm_ldap_setopts(ld, lmap)  	SM_LDAP_STRUCT *lmap;  {  # if USE_LDAP_SET_OPTION +#  if _FFR_LDAP_SETVERSION +	if (lmap->ldap_version != 0) +	{ +		ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, +				&lmap->ldap_version); +	} +#  endif /* _FFR_LDAP_SETVERSION */  	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);  	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))  		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); | 
