diff --git a/COPYRIGHT b/COPYRIGHT
index 447503e187212153d938001672dfe450a55cab1c..73e3b057b8d9d670b1cd043d31a13c6139bfa063 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -7,12 +7,11 @@ Public License.  A copy of this license is available at
 http://www.OpenLDAP.org/license.html or in file LICENSE in the
 top-level directory of the distribution.
 
-Individual files and/or contributed packages may be copyright by
-other parties and use subject to additional restrictions.
+Individual files and/or contributed packages may contain material
+copyright by other parties and use subject to additional restrictions.
 
 This work is derived from the University of Michigan LDAP v3.3
-distribution.  Information concerning this software is available
-at: http://www.umich.edu/~dirsvcs/ldap/
+software <http://www.umich.edu/~dirsvcs/ldap/>.
 
 This work also contains materials derived from public sources.
 
diff --git a/clients/fax500/rp500.c b/clients/fax500/rp500.c
index 9ac3b3f8ffc3e7cde3c57478c48322cd23a68a9f..806774f91e3a2549be8a70189d9791e568eb3543 100644
--- a/clients/fax500/rp500.c
+++ b/clients/fax500/rp500.c
@@ -129,18 +129,6 @@ main( int argc, char **argv )
 	}
 
 	result = NULL;
-	if ( strchr( key, ',' ) != NULL ) {
-		int ld_deref = LDAP_DEREF_FINDING;
-		ldap_set_option(ld, LDAP_OPT_DEREF, &ld_deref);
-		if ( (rc = ldap_ufn_search_s( ld, key, attrs, 0, &result ))
-		    != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
-		    rc != LDAP_TIMELIMIT_EXCEEDED )
-		{
-			ldap_perror( ld, "ldap_ufn_search_s" );
-			exit( -1 );
-		}
-		matches = ldap_count_entries( ld, result );
-	} else {
 		for ( fi = ldap_getfirstfilter( filtd, "rp500", key );
 		    fi != NULL; fi = ldap_getnextfilter( filtd ) ) {
 			if ( (rc = ldap_search_s( ld, base, LDAP_SCOPE_SUBTREE,
@@ -157,7 +145,6 @@ main( int argc, char **argv )
 				break;
 			}
 		}
-	}
 
 	if ( matches == 1 ) {
 		e = ldap_first_entry( ld, result );
diff --git a/clients/finger/main.c b/clients/finger/main.c
index a19fece964834f910d6f217923db8b280c1accb0..96f8d3595c3f65f9ff5a68a2b871a3403c73f6f5 100644
--- a/clients/finger/main.c
+++ b/clients/finger/main.c
@@ -259,7 +259,7 @@ do_search( LDAP *ld, char *buf )
 {
 	char		*dn, *rdn;
 	char		**title;
-	int		rc = 0, matches = 0, i, ufn;
+	int		rc = 0, matches = 0, i;
 	struct timeval	tv;
 	LDAPFiltDesc	*fd;
 	LDAPFiltInfo	*fi = NULL;
@@ -270,25 +270,6 @@ do_search( LDAP *ld, char *buf )
 #endif
 					0 };
 
-	ufn = 0;
-#ifdef FINGER_UFN
-	if ( strchr( buf, ',' ) != NULL ) {
-		ldap_ufn_setprefix( ld, base );
-		tv.tv_sec = FINGER_TIMEOUT;
-		tv.tv_usec = 0;
-		ldap_ufn_timeout( (void *) &tv );
-
-		if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &result ))
-		    != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
-			fprintf( stderr, FINGER_UNAVAILABLE );
-			ldap_perror( ld, "ldap_search_st" );
-			exit( EXIT_FAILURE );
-		}
-
-		matches = ldap_count_entries( ld, result );
-		ufn = 1;
-	} else {
-#endif
 		if ( (fd = ldap_init_getfilter( filterfile ))
 		    == NULL ) {
 			fprintf( stderr, "Cannot open filter file (%s)\n",
@@ -318,9 +299,6 @@ do_search( LDAP *ld, char *buf )
 			ldap_msgfree( result );
 			result = NULL;
 		}
-#ifdef FINGER_UFN
-	}
-#endif
 
 	if ( rc == LDAP_SIZELIMIT_EXCEEDED ) {
 		printf( "(Partial results - a size limit was exceeded)\r\n" );
@@ -336,7 +314,7 @@ do_search( LDAP *ld, char *buf )
 		exit( EXIT_FAILURE );
 	} else if ( matches <= FINGER_LISTLIMIT ) {
 		printf( "%d %s match%s found for \"%s\":\r\n", matches,
-		    ufn ? "UFN" : fi->lfi_desc, matches > 1 ? "es" : "", buf );
+		    fi->lfi_desc, matches > 1 ? "es" : "", buf );
 		fflush( stdout );
 
 		for ( e = ldap_first_entry( ld, result ); e != NULL; ) {
@@ -348,7 +326,7 @@ do_search( LDAP *ld, char *buf )
 		}
 	} else {
 		printf( "%d %s matches for \"%s\":\r\n", matches,
-		    ufn ? "UFN" : fi->lfi_desc, buf );
+		    fi->lfi_desc, buf );
 		fflush( stdout );
 
 #ifdef FINGER_SORT_ATTR
diff --git a/clients/gopher/go500.c b/clients/gopher/go500.c
index 2b7c4ed6752af712cff475b8d0cdf4caf5c51fd2..948d4b4e8870ca54146b952cd2ee80d0bbcc766f 100644
--- a/clients/gopher/go500.c
+++ b/clients/gopher/go500.c
@@ -482,24 +482,6 @@ do_search( LDAP *ld, FILE *fp, char *buf )
 	LDAPMessage	*e, *res;
 	static char	*attrs[] = { "title", 0 };
 
-#ifdef GO500_UFN
-	if ( strchr( buf, ',' ) != NULL ) {
-		ldap_ufn_setprefix( ld, base );
-		tv.tv_sec = GO500_TIMEOUT;
-		tv.tv_usec = 0;
-		ldap_ufn_timeout( (void *) &tv );
-
-		if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &res ))
-		    != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
-			fprintf(fp,
-			    "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
-			    rc, myhost, myport );
-			return;
-		}
-
-		matches = ldap_count_entries( ld, res );
-	} else {
-#endif
 		if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
 			fprintf( stderr, "Cannot open filter file (%s)\n",
 			    filterfile );
@@ -525,9 +507,6 @@ do_search( LDAP *ld, FILE *fp, char *buf )
 				break;
 		}
 		ldap_getfilter_free( filtd );
-#ifdef GO500_UFN
-	}
-#endif
 
 	if ( matches <= 0 ) {
 		return;
diff --git a/clients/gopher/go500gw.c b/clients/gopher/go500gw.c
index efe5054d811d97c2bcb67c7e32d0f6f0c11fe69b..b1292ba8977f1a84cd513f34ceebb9e8c524a8f5 100644
--- a/clients/gopher/go500gw.c
+++ b/clients/gopher/go500gw.c
@@ -743,27 +743,6 @@ do_search( LDAP *ld, FILE *fp, char *query )
 	*filter++ = '\0';
 	base = query;
 
-#ifdef GO500GW_UFN
-	if ( strchr( filter, ',' ) != NULL ) {
-		ldap_ufn_setprefix( ld, base );
-		timeout.tv_sec = GO500GW_TIMEOUT;
-		timeout.tv_usec = 0;
-		ldap_ufn_timeout( (void *) &timeout );
-
-		deref = LDAP_DEREF_FINDING;
-		ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
-
-		if ( (rc = ldap_ufn_search_s( ld, filter, attrs, 0, &res ))
-		    != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
-			fprintf(fp,
-			    "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
-			    rc, myhost, myport );
-			return;
-		}
-
-		count = ldap_count_entries( ld, res );
-	} else {
-#endif
 		if ( (scope = make_scope( ld, base )) == -1 ) {
 			fprintf( fp, "3Bad scope\r\n" );
 			exit( EXIT_FAILURE );
@@ -801,9 +780,6 @@ do_search( LDAP *ld, FILE *fp, char *query )
 		deref = LDAP_DEREF_ALWAYS;
 		ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
 		ldap_getfilter_free( filtd );
-#ifdef GO500GW_UFN
-	}
-#endif
 
 	if ( count == 0 ) {
 		return;
diff --git a/clients/rcpt500/query.c b/clients/rcpt500/query.c
index 4e92f62a43370ab99486f64b115be4f548a467b1..f4b1d2acbce4f610885924e274efb5eef5bbb450 100644
--- a/clients/rcpt500/query.c
+++ b/clients/rcpt500/query.c
@@ -41,7 +41,7 @@ query_cmd( struct msginfo *msgp, char *reply )
     LDAP			*ldp;
     LDAPMessage			*ldmsgp, *entry;
     char			*dn;
-    int				matches, rc, ld_errno, ufn;
+    int				matches, rc, ld_errno;
     LDAPFiltDesc		*lfdp;
     LDAPFiltInfo		*lfi;
     struct ldap_disptmpl	*tmpllist = NULL;
@@ -51,8 +51,6 @@ query_cmd( struct msginfo *msgp, char *reply )
 #endif
 			NULL };
 
-    ufn = 0;
-
     if ( msgp->msg_arg == NULL ) {
 	return( help_cmd( msgp, reply ));
     }
@@ -95,23 +93,6 @@ query_cmd( struct msginfo *msgp, char *reply )
 
     matches = 0;
 
-#ifdef RCPT500_UFN
-    if ( strchr( msgp->msg_arg, ',' ) != NULL ) {
-	struct timeval	tv;
-
-	ldap_ufn_setprefix( ldp, searchbase );
-	if (( rc = ldap_ufn_search_s( ldp, msgp->msg_arg, attrs, 0, &ldmsgp ))
-		!= LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
-		&& rc != LDAP_TIMELIMIT_EXCEEDED ) {
-	    report_ldap_err( ldp, reply );
-	    close_ldap( ldp );
-	    ldap_getfilter_free( lfdp );
-	    return( 0 );
-	}
-	matches = ldap_count_entries( ldp, ldmsgp );
-	ufn = 1;
-    } else {
-#endif /* RCPT500_UFN */
     
 	for ( lfi = ldap_getfirstfilter( lfdp, "rcpt500", msgp->msg_arg );
 		lfi != NULL; lfi = ldap_getnextfilter( lfdp )) {
@@ -134,9 +115,6 @@ query_cmd( struct msginfo *msgp, char *reply )
 		ldap_msgfree( ldmsgp );
 	    }
 	}
-#ifdef RCPT500_UFN
-    }
-#endif /* RCPT500_UFN */
 
     if ( matches == 0 ) {
 	sprintf( buf, "No matches were found for '%s'\n", msgp->msg_arg );
@@ -156,7 +134,7 @@ query_cmd( struct msginfo *msgp, char *reply )
 
     if ( matches <= RCPT500_LISTLIMIT ) {
 	sprintf( buf, "%d %s match%s found for '%s':\n\n", matches,
-		ufn ? "UFN" : lfi->lfi_desc,
+		lfi->lfi_desc,
 		( matches > 1 ) ? "es" : "", msgp->msg_arg );
 	strcat( reply, buf );
 
@@ -184,7 +162,7 @@ query_cmd( struct msginfo *msgp, char *reply )
 
     } else {
 	sprintf( buf, "%d %s matches were found for '%s':\n",
-		matches, ufn ? "UFN" : lfi->lfi_desc, msgp->msg_arg );
+		matches, lfi->lfi_desc, msgp->msg_arg );
 	strcat( reply, buf );
 	append_entry_list( reply, msgp->msg_arg, ldp, ldmsgp );
 	ldap_msgfree( ldmsgp );
diff --git a/clients/ud/find.c b/clients/ud/find.c
index 9525c86b972ac44f2daa5623caad709eedf1d1d9..d5b85e9c21757f9b239111db9ccb73db00640287 100644
--- a/clients/ud/find.c
+++ b/clients/ud/find.c
@@ -199,48 +199,6 @@ find( char *who, int quiet )
 		search_attrs[k] = NULL;
 	}
 
-	/*
-	 *  If the user-supplied name has any commas in it, we
-	 *  assume that it is a UFN, and do everything right
-	 *  here.  If we don't find it, treat it as NOT a UFN.
-	 */
-	if (strchr(who, ',') != NULL) {
-		int	savederef, deref;
-#ifdef DEBUG
-		if (debug & D_FIND)
-			printf("\"%s\" appears to be a UFN\n", who);
-#endif
-		ldap_get_option(ld, LDAP_OPT_DEREF, &savederef);
-		deref = LDAP_DEREF_FINDING;
-		ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
-
-		if ((rc = ldap_ufn_search_s(ld, who, search_attrs, FALSE, &res)) !=
-		    LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED &&
-		    rc != LDAP_TIMELIMIT_EXCEEDED) {
-			ldap_perror(ld, "ldap_ufn_search_s");
-			ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
-			return(NULL);
-		}
-		if ((matches = ldap_count_entries(ld, res)) < 0) {
-			ldap_perror(ld, "ldap_count_entries");
-			ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
-			return(NULL);
-		} else if (matches == 1) {
-			dn = ldap_get_dn(ld, ldap_first_entry(ld, res));
-			rc = ldap_search_s(ld, dn, LDAP_SCOPE_BASE, NULL, read_attrs, FALSE, &res);
-			ldap_memfree(dn);
-			if (rc != LDAP_SUCCESS) {
-				ldap_perror(ld, "ldap_search_s");
-				return(NULL);
-			}
-			ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
-			return(res);
-		} else if (matches > 1 ) {
-			return disambiguate( res, matches, read_attrs, who );
-		}
-		ldap_set_option(ld, LDAP_OPT_DEREF, &savederef);
-	}
-
 	/*
 	 *  Old users of the MTS *USERDIRECTORY will likely wrap the name
 	 *  in quotes.  Not only is this unnecessary, but it also won't work.
@@ -255,9 +213,6 @@ find( char *who, int quiet )
 			break;
 	}
 
-	/*
-	 *  It wasn't a UFN, so look it up in the usual method.
-	 */
 	for (fi = ldap_getfirstfilter(lfdp, "ud", who); fi != NULL;
 	     fi = ldap_getnextfilter(lfdp)) {
 #ifdef DEBUG
diff --git a/doc/drafts/draft-rharrison-ldap-extpartresp-xx.txt b/doc/drafts/draft-rharrison-ldap-extpartresp-xx.txt
deleted file mode 100644
index 76a1a47c8c9992e5e77707858fcfd48bf335791d..0000000000000000000000000000000000000000
--- a/doc/drafts/draft-rharrison-ldap-extpartresp-xx.txt
+++ /dev/null
@@ -1,159 +0,0 @@
-
-Individual Submission to LDAPExt Working Group              R. Harrison
-Internet Draft                                             Novell, Inc.
-Document: draft-rharrison-ldap-extpartresp-01.txt            June, 2000
-Category: Proposed Standard
-
-
-                       Extended Partial Response
-                    Protocol Enhancement to LDAP v3
-
-
-Status of this Memo
-
-   This document is an Internet-Draft and is in full conformance with
-   all provisions of Section 10 of RFC2026 [1].
-
-   Internet-Drafts are working documents of the Internet Engineering
-   Task Force (IETF), its areas, and its working groups. Note that
-   other groups may also distribute working documents as Internet-
-   Drafts. Internet-Drafts are draft documents valid for a maximum of
-   six months and may be updated, replaced, or obsoleted by other
-   documents at any time. It is inappropriate to use Internet- Drafts
-   as reference material or to cite them other than as "work in
-   progress."
-   The list of current Internet-Drafts can be accessed at
-   http://www.ietf.org/ietf/1id-abstracts.txt
-   The list of Internet-Draft Shadow Directories can be accessed at
-   http://www.ietf.org/shadow.html.
-
-
-1. Abstract
-
-   This document describes the ExtendedPartialResponse, an element of
-   LDAP v3 protocol which allows multiple responses to LDAP v3 extended
-   requests.  Extended partial responses are backward compatible with
-   the existing LDAP v3 Extended Operation defined in [LDAPv3].
-
-2. Conventions used in this document
-
-   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
-   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in
-   this document are to be interpreted as described in [RFC2119].
-
-
-3. Motivation for the Extended Partial Response
-
-   The Extended Operation ([LDAPv3] Section 4.12) was defined in LDAP
-   v3 to allow additional operations to be defined as part of the
-   protocol without requiring a new revision of the protocol.
-
-   The LDAP v3 Extended Operation allows for a single extended response
-   to each extended request, but this paradigm may not be sufficient
-   for some directory operations.  For instance, the LDAP search
-   operation is a directory operation that is much more efficient when
-   multiple partial responses are used to service a single request. The
-
-                  LDAP v3 Extended Partial Response         June, 2000
-
-
-   extended partial response generalizes the current extended operation
-   definition to give LDAP server implementers the ability to make use
-   of a single-request-multiple-response paradigm for extended LDAP
-   operations that require it or that would benefit from it.
-
-4. Element of Protocol
-
-   The ExtendedPartialResponse is defined as
-
-   ExtendedPartialResponse ::= [APPLICATION 25] SEQUENCE {
-           responseName     [0] LDAPOID OPTIONAL,
-           response         [1] OCTET STRING OPTIONAL }
-
-   An LDAP server responds to an LDAP v3 ExtendedRequest with zero or
-   more ExtendedPartialResponses followed by one ExtendedResponse. This
-   ensures backward compatibility with existing LDAP extensions which
-   do not make use of the ExtendedPartialResponse.  As with all LDAP
-   extensions, LDAP extensions that make use of the
-   ExtendedPartialResponse have predefined syntax and semantics that
-   are defined in RFCs or are private to a particular implementation.
-
-5. Security Considerations
-
-   This draft describes an enhancement to the LDAP v3 protocol
-   [LDAPv3].  All security considerations of [LDAPv3] apply to this
-   draft, however it does not introduce any new security considerations
-   to the LDAP v3 protocol.
-
-6. References
-
-    [LDAPv3]
-        Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
-        Access Protocol (v3)", RFC 2251, December 1997.
-
-   [ReqsKeywords]
-        Scott Bradner. "Key Words for use in RFCs to Indicate
-        Requirement Levels". RFC 2119.
-
-
-7. Acknowledgments
-
-   The author would like to acknowledge the readers of the LDAP
-   Extensions working group mail list who responded to the suggestion
-   that a multiple-response paradigm might be useful for LDAP extended
-   requests.  Special thanks go to two individuals: David Wilbur who
-   first introduced the idea on the working group list, and Thomas
-   Salter, who succinctly summarized the discussion and suggested the
-   name ExtendedPartialResponse in his summary.
-
-8. Author's Addresses
-
-   Roger Harrison
-   Novell, Inc.
-
-                  LDAP v3 Extended Partial Response         June, 2000
-
-
-   1800 S. Novell Place
-   Provo, UT 84606
-   +1 801 861 2642
-   roger_harrison@novell.com
-
-
-Appendix A - Document Revision History
-
-A.1 draft-rharrison-ldap-extPartResp-00.doc
-
-   Initial revision of draft.
-
-A.2 draft-rharrison-ldap-extPartResp-01.doc
-
-   Changed responseName to be optional to align with [LDAPv3]
-   definition of ExtendedResponse.
-
-Full Copyright Statement
-
-   "Copyright (C) The Internet Society (date). All Rights Reserved.
-   This document and translations of it may be copied and furnished to
-   others, and derivative works that comment on or otherwise explain it
-   or assist in its implmentation may be prepared, copied, published
-   and distributed, in whole or in part, without restriction of any
-   kind, provided that the above copyright notice and this paragraph
-   are included on all such copies and derivative works. However, this
-   document itself may not be modified in any way, such as by removing
-   the copyright notice or references to the Internet Society or other
-   Internet organizations, except as needed for the purpose of
-   developing Internet standards in which case the procedures for
-   copyrights defined in the Internet Standards process must be
-   followed, or as required to translate it into languages other than
-   English.
-
-   The limited permissions granted above are perpetual and will not be
-   revoked by the Internet Society or its successors or assigns.
-
-   This document and the information contained herein is provided on an
-   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/include/ldap.h b/include/ldap.h
index 878d576e1148694e9a9a512280ebf7c30c62218d..1673ab63e0f1de4ef43da40f861185d4f437fe53 100644
--- a/include/ldap.h
+++ b/include/ldap.h
@@ -1326,57 +1326,6 @@ ldap_search_st LDAP_P((	/* deprecated */
 	struct timeval *timeout,
 	LDAPMessage **res ));
 
-
-/*
- * in ufn.c						 	
- *	(deprecated)
- */
-LDAP_F( int )
-ldap_ufn_search_c LDAP_P(( /* deprecated */
-	LDAP *ld,
-	LDAP_CONST char *ufn,
-	char **attrs,
-	int attrsonly,
-	LDAPMessage **res,
-	int (*cancelproc)( void *cl ),
-	void *cancelparm ));
-
-LDAP_F( int )
-ldap_ufn_search_ct LDAP_P(( /* deprecated */
-	LDAP *ld,
-	LDAP_CONST char *ufn,
-	char **attrs,
-	int attrsonly,
-	LDAPMessage **res,
-	int (*cancelproc)( void *cl ),
-	void *cancelparm,
-	char *tag1,
-	char *tag2,
-	char *tag3 ));
-
-LDAP_F( int )
-ldap_ufn_search_s LDAP_P(( /* deprecated */
-	LDAP *ld,
-	LDAP_CONST char *ufn,
-	char **attrs,
-	int attrsonly,
-	LDAPMessage **res ));
-
-LDAP_F( LDAPFiltDesc *)
-ldap_ufn_setfilter LDAP_P(( /* deprecated */
-	LDAP *ld,
-	LDAP_CONST char *fname ));
-
-LDAP_F( void )
-ldap_ufn_setprefix LDAP_P(( /* deprecated */
-	LDAP *ld,
-	LDAP_CONST char *prefix ));
-
-LDAP_F( int )
-ldap_ufn_timeout LDAP_P(( /* deprecated */
-	void *tvparam ));
-
-
 /*
  * in unbind.c
  */
diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h
index 75dc5bcaa6b55b92ffbdaa48e2163a0f524ce8f4..d926912f9ed59a648ed1f8099f79a224fb2bc6a7 100644
--- a/include/ldap_pvt.h
+++ b/include/ldap_pvt.h
@@ -148,6 +148,11 @@ LDAP_F (int) ldap_pvt_sasl_install LDAP_P(( struct sockbuf *, void * ));
 
 #define LDAP_PVT_SASL_LOCAL_SSF	71	/* SSF for Unix Domain Sockets */
 
+struct ldap;
+
+LDAP_F (int) ldap_open_internal_connection LDAP_P((
+	struct ldap **ldp, ber_socket_t *fdp ));
+
 /* search.c */
 LDAP_F( char * )
 ldap_pvt_find_wildcard LDAP_P((	const char *s ));
@@ -163,21 +168,21 @@ LDAP_F( char * )
 ldap_pvt_str2lower LDAP_P(( char *str ));
 
 /* tls.c */
-struct ldapoptions;
-struct ldap;
-
 LDAP_F (int) ldap_pvt_tls_init LDAP_P(( void ));
-LDAP_F (int) ldap_pvt_tls_connect LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg ));
+LDAP_F (int) ldap_pvt_tls_connect LDAP_P(( struct ldap *ld,
+	Sockbuf *sb, void *ctx_arg ));
 LDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg ));
 LDAP_F (void *) ldap_pvt_tls_sb_handle LDAP_P(( Sockbuf *sb ));
 LDAP_F (void *) ldap_pvt_tls_get_handle LDAP_P(( struct ldap *ld ));
-LDAP_F (const char *) ldap_pvt_tls_get_peer LDAP_P(( void *handle ));
+LDAP_F (char *) ldap_pvt_tls_get_peer LDAP_P(( void *handle ));
 LDAP_F (int) ldap_pvt_tls_get_strength LDAP_P(( void *handle ));
 LDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb ));
-LDAP_F (int) ldap_pvt_tls_start LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg ));
-
-LDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldapoptions *lo, int option, void *arg ));
-LDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldapoptions *lo, int option, void *arg ));
+LDAP_F (int) ldap_pvt_tls_start LDAP_P(( struct ldap *ld,
+	Sockbuf *sb, void *ctx_arg ));
+LDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldap *ld,
+	int option, void *arg ));
+LDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldap *ld,
+	int option, void *arg ));
 
 /*  
  * UTF-8 (in utf-8.c)
diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in
index 2be2d6f9256bb448c56081d46641f1e26bdb66fb..996f11046c29efe0f2a8b408d57de8992450f42a 100644
--- a/libraries/libldap/Makefile.in
+++ b/libraries/libldap/Makefile.in
@@ -11,7 +11,7 @@ PROGRAMS = apitest ltest ttest
 
 SRCS	= bind.c open.c result.c error.c compare.c search.c \
 	controls.c messages.c references.c extended.c cyrus.c \
-	modify.c add.c modrdn.c delete.c abandon.c ufn.c cache.c \
+	modify.c add.c modrdn.c delete.c abandon.c cache.c \
 	getfilter.c sasl.c sbind.c kbind.c unbind.c friendly.c \
 	free.c disptmpl.c srchpref.c dsparse.c tmplout.c sort.c \
 	getdn.c getentry.c getattr.c getvalues.c addentry.c \
@@ -21,7 +21,7 @@ SRCS	= bind.c open.c result.c error.c compare.c search.c \
 	utf-8.c
 OBJS	= bind.lo open.lo result.lo error.lo compare.lo search.lo \
 	controls.lo messages.lo references.lo extended.lo cyrus.lo \
-	modify.lo add.lo modrdn.lo delete.lo abandon.lo ufn.lo cache.lo \
+	modify.lo add.lo modrdn.lo delete.lo abandon.lo cache.lo \
 	getfilter.lo sasl.lo sbind.lo kbind.lo unbind.lo friendly.lo \
 	free.lo disptmpl.lo srchpref.lo dsparse.lo tmplout.lo sort.lo \
 	getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c
index fbb184722a5357553da576b82ea5873972c6a6ca..8220e47a99672fe6accb95c81a7cfc3e57717545 100644
--- a/libraries/libldap/abandon.c
+++ b/libraries/libldap/abandon.c
@@ -56,8 +56,13 @@ ldap_abandon_ext(
 	LDAPControl **sctrls,
 	LDAPControl **cctrls )
 {
+	int rc;
 	Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	return do_abandon( ld, msgid, msgid, sctrls, cctrls );
 }
 
@@ -77,7 +82,7 @@ int
 ldap_abandon( LDAP *ld, int msgid )
 {
 	Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
-	return do_abandon( ld, msgid, msgid, NULL, NULL ) == LDAP_SUCCESS
+	return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
 		? 0 : -1;
 }
 
diff --git a/libraries/libldap/add.c b/libraries/libldap/add.c
index 5ae74605276966a7786d2d4eb8e1d388b73a0afc..a8281f4c0eb6fb5a8cb059850c533187ae9b26d7 100644
--- a/libraries/libldap/add.c
+++ b/libraries/libldap/add.c
@@ -105,6 +105,10 @@ ldap_add_ext(
 	assert( dn != NULL );
 	assert( msgidp != NULL );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/* create a message to send */
 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
 		ld->ld_errno = LDAP_NO_MEMORY;
diff --git a/libraries/libldap/compare.c b/libraries/libldap/compare.c
index a48dda120f335884d2fe9494fac39122e6656991..2b890b1fe9d7af4f47646f54b9bb5f93b162121c 100644
--- a/libraries/libldap/compare.c
+++ b/libraries/libldap/compare.c
@@ -51,6 +51,7 @@ ldap_compare_ext(
 	LDAPControl **cctrls,
 	int	*msgidp )
 {
+	int rc;
 	BerElement	*ber;
 
 	Debug( LDAP_DEBUG_TRACE, "ldap_compare\n", 0, 0, 0 );
@@ -61,6 +62,10 @@ ldap_compare_ext(
 	assert( attr != NULL );
 	assert( msgidp != NULL );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/* create a message to send */
 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
 		return( LDAP_NO_MEMORY );
diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c
index 58ca93e81a39720707543ae07a6c757f65449c98..6dcf7364ecbc63d34f64d9e463107875f4a7e150 100644
--- a/libraries/libldap/controls.c
+++ b/libraries/libldap/controls.c
@@ -441,3 +441,34 @@ ldap_create_control(
 	*ctrlp = ctrl;
 	return LDAP_SUCCESS;
 }
+
+/*
+ * check for critical client controls and bitch if present
+ * if we ever support critical controls, we'll have to
+ * find a means for maintaining per API call control
+ * information.
+ */
+int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
+{
+	LDAPControl *const *c;
+
+	assert( ld != NULL );
+
+	if( ctrls == NULL ) {
+		/* use default server controls */
+		ctrls = ld->ld_cctrls;
+	}
+
+	if( ctrls == NULL || *ctrls == NULL ) {
+		return LDAP_SUCCESS;
+	}
+
+	for( c = ctrls ; *c != NULL; c++ ) {
+		if( (*c)->ldctl_iscritical ) {
+			ld->ld_errno = LDAP_NOT_SUPPORTED;
+			return ld->ld_errno;
+		}
+	}
+
+	return LDAP_SUCCESS;
+}
diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c
index fcca106b7d3b6dbf11d9f9f8e12a27d4a80fa8b9..af3d1ab3829c9b866c8ad5a193af14009b3ea661 100644
--- a/libraries/libldap/cyrus.c
+++ b/libraries/libldap/cyrus.c
@@ -424,7 +424,7 @@ ldap_int_sasl_open(
 		return ld->ld_errno;
 	}
 
-	Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: %s\n",
+	Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n",
 		host, 0, 0 );
 
 	lc->lconn_sasl_ctx = ctx;
diff --git a/libraries/libldap/delete.c b/libraries/libldap/delete.c
index 714acc5a5a2e966fbe2ac6c914178c354d3bee1b..8397b735cc393b07f7090a3527c5f48f2f837902 100644
--- a/libraries/libldap/delete.c
+++ b/libraries/libldap/delete.c
@@ -45,6 +45,7 @@ ldap_delete_ext(
 	LDAPControl **cctrls,
 	int *msgidp )
 {
+	int rc;
 	BerElement	*ber;
 
 	Debug( LDAP_DEBUG_TRACE, "ldap_delete\n", 0, 0, 0 );
@@ -54,6 +55,10 @@ ldap_delete_ext(
 	assert( dn != NULL );
 	assert( msgidp != NULL );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/* create a message to send */
 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
 		ld->ld_errno = LDAP_NO_MEMORY;
diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c
index 3ed841ab5eb22261622e7bc92fb2a908ab531923..90be4755534525cfc2b9bc2339ab95e80851fc29 100644
--- a/libraries/libldap/getdn.c
+++ b/libraries/libldap/getdn.c
@@ -54,88 +54,41 @@ ldap_get_dn( LDAP *ld, LDAPMessage *entry )
 char *
 ldap_dn2ufn( LDAP_CONST char *dn )
 {
-	char	*p, *ufn, *r;
-	int	state;
+	char	*ufn;
+	char	**vals;
+	int i;
 
 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
 
+	/* produces completely untyped UFNs */
+
 	if( dn == NULL ) {
 		return NULL;
 	}
 
-	if ( ( p = ldap_utf8_strpbrk( dn, "=" ) ) == NULL ) {
-		return( LDAP_STRDUP( dn ) );
+	vals = ldap_explode_dn( dn , 0 );
+	if( vals == NULL ) {
+		return NULL;
 	}
-	ufn = LDAP_STRDUP( ++p );
-
-	if( ufn == NULL ) return NULL;
-
-#define INQUOTE		1
-#define OUTQUOTE	2
-	state = OUTQUOTE;
-	for ( p = ufn, r = ufn; *p; LDAP_UTF8_INCR(p) ) {
-		switch ( *p ) {
-		case '\\':
-			if ( p[1] != '\0' ) {
-				*r++ = '\\';
-				LDAP_UTF8_COPY(r,++p);
-				LDAP_UTF8_INCR(r);
-			}
-			break;
-
-		case '"':
-			if ( state == INQUOTE )
-				state = OUTQUOTE;
-			else
-				state = INQUOTE;
-			*r++ = *p;
-			break;
 
-		case ';':
-		case ',':
-			if ( state == OUTQUOTE )
-				*r++ = ',';
-			else
-				*r++ = *p;
-			break;
-
-		case '=':
-			if ( state == INQUOTE ) {
-				*r++ = *p;
-			} else {
-				char	*rsave = r;
-
-				*r = '\0';
-				LDAP_UTF8_DECR( r );
+	for ( i = 0; vals[i]; i++ ) {
+		char **rvals;
 
-				while ( !ldap_utf8_isspace( r )
-					&& *r != ';' && *r != ',' && r > ufn )
-				{
-					LDAP_UTF8_DECR( r );
-				}
-				LDAP_UTF8_INCR( r );
-
-				if ( strcasecmp( r, "c" )
-				    && strcasecmp( r, "o" )
-				    && strcasecmp( r, "ou" )
-				    && strcasecmp( r, "st" )
-				    && strcasecmp( r, "l" )
-				    && strcasecmp( r, "cn" ) ) {
-					r = rsave;
-					*r++ = '=';
-				}
-			}
-			break;
-
-		default:
-			LDAP_UTF8_COPY(r, p);
-			LDAP_UTF8_INCR(r);
-			break;
+		rvals = ldap_explode_rdn( vals[i] , 1 );
+		if ( rvals == NULL ) {
+			LDAP_VFREE( vals );
+			return NULL;
 		}
+
+		LDAP_FREE( vals[i] );
+		vals[i] = ldap_charray2str( rvals, " + " );
+		LDAP_VFREE( rvals );
 	}
-	*r = '\0';
 
-	return( ufn );
+	ufn = ldap_charray2str( vals, ", " );
+
+	LDAP_VFREE( vals );
+	return ufn;
 }
 
 char **
@@ -237,6 +190,9 @@ ldap_dcedn2dn( LDAP_CONST char *dce )
 	return dn;
 }
 
+#define INQUOTE		1
+#define OUTQUOTE	2
+
 static char **
 explode_name( const char *name, int notypes, int is_type )
 {
diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c
index ae70a5830ec2780c0cc79235aa7dafce88a96cdc..85c9ded5bcd9407fada98cb8ded1d4be6cd6aef6 100644
--- a/libraries/libldap/init.c
+++ b/libraries/libldap/init.c
@@ -26,7 +26,7 @@ struct ldapoptions ldap_int_global_options =
 #define ATTR_INT	2
 #define ATTR_KV		3
 #define ATTR_STRING	4
-#define ATTR_URIS	5
+#define ATTR_OPTION	5
 
 #define ATTR_SASL	6
 #define ATTR_TLS	7
@@ -63,8 +63,8 @@ static const struct ol_attribute {
 		offsetof(struct ldapoptions, ldo_defbase)},
 	{0, ATTR_INT,		"PORT",			NULL,		/* deprecated */
 		offsetof(struct ldapoptions, ldo_defport)},
-	{0, ATTR_URIS,		"HOST",			NULL,	1},	/* deprecated */
-	{0, ATTR_URIS,		"URI",			NULL,	0}, /* replaces HOST/URI */
+	{0, ATTR_OPTION,	"HOST",			NULL,	LDAP_OPT_HOST_NAME}, /* deprecated */
+	{0, ATTR_OPTION,	"URI",			NULL,	LDAP_OPT_URI}, /* replaces HOST/PORT */
 	{0, ATTR_BOOL,		"REFERRALS",	NULL,	LDAP_BOOL_REFERRALS},
 	{0, ATTR_BOOL,		"RESTART",		NULL,	LDAP_BOOL_RESTART},
 
@@ -211,12 +211,8 @@ static void openldap_ldap_init_w_conf(
 				if (* (char**) p != NULL) LDAP_FREE(* (char**) p);
 				* (char**) p = LDAP_STRDUP(opt);
 				break;
-			case ATTR_URIS:
-				if (attrs[i].offset == 0) {
-					ldap_set_option( NULL, LDAP_OPT_URI, opt );
-				} else {
-					ldap_set_option( NULL, LDAP_OPT_HOST_NAME, opt );
-				}
+			case ATTR_OPTION:
+				ldap_set_option( NULL, attrs[i].offset, opt );
 				break;
 			case ATTR_SASL:
 #ifdef HAVE_CYRUS_SASL
@@ -351,12 +347,8 @@ static void openldap_ldap_init_w_env(
 				* (char**) p = LDAP_STRDUP(value);
 			}
 			break;
-		case ATTR_URIS:
-			if (attrs[i].offset == 0) {
-				ldap_set_option( NULL, LDAP_OPT_URI, value );
-			} else {
-				ldap_set_option( NULL, LDAP_OPT_HOST_NAME, value );
-			}
+		case ATTR_OPTION:
+			ldap_set_option( NULL, attrs[i].offset, value );
 			break;
 		case ATTR_SASL:
 #ifdef HAVE_CYRUS_SASL
@@ -418,12 +410,7 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
 		SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
 #endif
 
-#ifdef HAVE_TLS
-   	gopts->ldo_tls_ctx = NULL;
-#endif
-
 	gopts->ldo_valid = LDAP_INITIALIZED;
-
    	return;
 }
 
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
index c8cc179171940af3eb8e9101c2c8a382c3e6269a..d752b62e06759a330ae3ac016a125c55d41ab8be 100644
--- a/libraries/libldap/ldap-int.h
+++ b/libraries/libldap/ldap-int.h
@@ -122,6 +122,10 @@ struct ldapoptions {
 	ber_int_t		ldo_timelimit;
 	ber_int_t		ldo_sizelimit;
 
+#ifdef HAVE_TLS
+   	int			ldo_tls_mode;
+#endif
+
 	LDAPURLDesc *ldo_defludp;
 	int		ldo_defport;
 	char*	ldo_defbase;
@@ -146,32 +150,22 @@ struct ldapoptions {
 	/* LDAP rebind callback function */
 	LDAP_REBIND_PROC		*ldo_rebindproc;
 
-#ifdef HAVE_TLS
-   	/* tls context */
-   	void		*ldo_tls_ctx;
-   	int		ldo_tls_mode;
-#endif
 	LDAP_BOOLEANS ldo_booleans;	/* boolean options */
 };
 
 
-/*
- * structure for tracking LDAP server host, ports, DNs, etc.
- */
-typedef struct ldap_server {
-	char			*lsrv_host;
-	char			*lsrv_dn;	/* if NULL, use default */
-	int			lsrv_port;
-	struct ldap_server	*lsrv_next;
-} LDAPServer;
-
-
 /*
  * structure for representing an LDAP server connection
  */
 typedef struct ldap_conn {
 	Sockbuf		*lconn_sb;
+#ifdef HAVE_TLS
+   	/* tls context */
+   	void		*lconn_tls_ctx;
+#endif
+#ifdef HAVE_CYRUS_SASL
 	void		*lconn_sasl_ctx;
+#endif
 	int			lconn_refcnt;
 	time_t		lconn_lastused;	/* time */
 	int			lconn_rebind_inprogress;	/* set if rebind in progress */
@@ -184,8 +178,9 @@ typedef struct ldap_conn {
 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
 	char			*lconn_krbinstance;
 #endif
+	BerElement		*lconn_ber;	/* ber receiving on this conn. */
+
 	struct ldap_conn	*lconn_next;
-	BerElement		*lconn_ber;/* ber receiving on this conn. */
 } LDAPConn;
 
 
@@ -269,9 +264,6 @@ struct ldap {
 
 #define ld_version		ld_options.ldo_version
 
-	char	*ld_host;
-	int		ld_port;
-
 	unsigned short	ld_lberoptions;
 
 	LDAPFiltDesc	*ld_filtd;	/* from getfilter for ufn searches */
@@ -373,6 +365,9 @@ LDAP_F (int) ldap_int_put_controls LDAP_P((
 	LDAPControl *const *ctrls,
 	BerElement *ber ));
 
+LDAP_F (int) ldap_int_client_controls LDAP_P((
+	LDAP *ld,
+	LDAPControl **ctrlp ));
 
 /*
  * in dsparse.c
@@ -408,10 +403,11 @@ LDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb,
 	int proto, const char *host, unsigned long address, int port,
 	int async );
 
-#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
+#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) || \
+	defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
 LDAP_V (char *) ldap_int_hostname;
 LDAP_F (char *) ldap_host_connected_to( Sockbuf *sb );
-#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND */
+#endif
 
 LDAP_F (void) ldap_int_ip_init( void );
 LDAP_F (int) do_ldap_select( LDAP *ld, struct timeval *timeout );
@@ -540,7 +536,7 @@ LDAP_F (int) ldap_int_sasl_config LDAP_P(( struct ldapoptions *lo,
 	int option, const char *arg ));
 
 LDAP_F (int) ldap_int_sasl_bind LDAP_P((
-	struct ldap *ld,
+	LDAP *ld,
 	const char *,
 	const char *,
 	LDAPControl **, LDAPControl **,
@@ -553,7 +549,11 @@ LDAP_F (int) ldap_int_sasl_bind LDAP_P((
 /*
  * in tls.c
  */
-LDAP_F (int) ldap_int_tls_config LDAP_P(( struct ldapoptions *lo, int option, const char *arg ));
+LDAP_F (int) ldap_int_tls_config LDAP_P(( LDAP *ld,
+	int option, const char *arg ));
+
+LDAP_F (int) ldap_int_tls_start LDAP_P(( LDAP *ld,
+	LDAPConn *conn ));
 
 LDAP_END_DECL
 
diff --git a/libraries/libldap/modify.c b/libraries/libldap/modify.c
index da8b0e602795b5eb3a4cc54dc1698bde04759e62..8ef0098c70b8b6d09bd892816e64a831cabc722c 100644
--- a/libraries/libldap/modify.c
+++ b/libraries/libldap/modify.c
@@ -73,6 +73,10 @@ ldap_modify_ext( LDAP *ld,
 
 	Debug( LDAP_DEBUG_TRACE, "ldap_modify_ext\n", 0, 0, 0 );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/* create a message to send */
 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
 		return( LDAP_NO_MEMORY );
diff --git a/libraries/libldap/modrdn.c b/libraries/libldap/modrdn.c
index 13678ef0411c7e825636475fef631b49c50a8442..54a3303a9f01ed1a67c211e4ebe8eaa2c62209c7 100644
--- a/libraries/libldap/modrdn.c
+++ b/libraries/libldap/modrdn.c
@@ -70,6 +70,10 @@ ldap_rename(
 
 	Debug( LDAP_DEBUG_TRACE, "ldap_rename\n", 0, 0, 0 );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/* create a message to send */
 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
 		return( LDAP_NO_MEMORY );
diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c
index a86b872e0c14fd6e7eb1ea27058bd2aeaa05943d..b48ae051c4c61c6bfd6b2130d27fc69faed10a42 100644
--- a/libraries/libldap/open.c
+++ b/libraries/libldap/open.c
@@ -54,9 +54,11 @@ ldap_open( LDAP_CONST char *host, int port )
 	int rc;
 	LDAP		*ld;
 
-	Debug( LDAP_DEBUG_TRACE, "ldap_open\n", 0, 0, 0 );
+	Debug( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n",
+		host, port, 0 );
 
-	if (( ld = ldap_init( host, port )) == NULL ) {
+	ld = ldap_init( host, port );
+	if ( ld == NULL ) {
 		return( NULL );
 	}
 
@@ -64,13 +66,13 @@ ldap_open( LDAP_CONST char *host, int port )
 
 	if( rc < 0 ) {
 		ldap_ld_free( ld, 0, NULL, NULL );
-		return( NULL );
+		ld = NULL;
 	}
 
-	Debug( LDAP_DEBUG_TRACE, "ldap_open successful, ld_host is %s\n",
-		( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
+	Debug( LDAP_DEBUG_TRACE, "ldap_open: %s\n",
+		ld == NULL ? "succeeded" : "failed", 0, 0 );
 
-	return( ld );
+	return ld;
 }
 
 
@@ -329,14 +331,10 @@ ldap_int_open_connection(
 	if (ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
 		strcmp( srv->lud_scheme, "ldaps" ) == 0 )
 	{
-		LDAPConn	*savedefconn = ld->ld_defconn;
 		++conn->lconn_refcnt;	/* avoid premature free */
-		ld->ld_defconn = conn;
 
-		rc = ldap_pvt_tls_start( ld, conn->lconn_sb,
-			ld->ld_options.ldo_tls_ctx );
+		rc = ldap_int_tls_start( ld, conn );
 
-		ld->ld_defconn = savedefconn;
 		--conn->lconn_refcnt;
 
 		if (rc != LDAP_SUCCESS) {
diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c
index 041897494dc6c9fa1ae8140e4883b34a69962b0e..7aeac91e3c334ad45995efbfce6ee8a325afb4a6 100644
--- a/libraries/libldap/options.c
+++ b/libraries/libldap/options.c
@@ -281,12 +281,14 @@ ldap_get_option(
 
 	default:
 #ifdef HAVE_TLS
-	   	if ( ldap_pvt_tls_get_option((struct ldapoptions *)lo, option, outvalue ) == 0 )
-	     		return LDAP_OPT_SUCCESS;
+		if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
+			return LDAP_OPT_SUCCESS;
+		}
 #endif
 #ifdef HAVE_CYRUS_SASL
-	   	if ( ldap_int_sasl_get_option(ld, option, outvalue ) == 0 )
-	     		return LDAP_OPT_SUCCESS;
+		if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
+			return LDAP_OPT_SUCCESS;
+		}
 #endif
 		/* bad param */
 		break;
@@ -579,7 +581,7 @@ ldap_set_option(
 
 	default:
 #ifdef HAVE_TLS
-		if ( ldap_pvt_tls_set_option( lo, option, (void	*)invalue ) == 0 )
+		if ( ldap_pvt_tls_set_option( ld, option, (void *)invalue ) == 0 )
 	     	return LDAP_OPT_SUCCESS;
 #endif
 #ifdef HAVE_CYRUS_SASL
diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c
index 30f4b3c3e559e0e4e654595dce8b0322fd8161bd..79bd49af9fb7d9048a3091cd3e346dfdd80c4cc1 100644
--- a/libraries/libldap/os-ip.c
+++ b/libraries/libldap/os-ip.c
@@ -294,7 +294,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
 	struct hostent		*hp = NULL;
 	char   			*ha_buf=NULL, *p, *q;
 
-	osip_debug(ld, "ldap_connect_to_host\n",0,0,0);
+	osip_debug(ld, "ldap_connect_to_host: %s\n",host,0,0);
 	
 	if (host != NULL) {
 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
@@ -423,8 +423,8 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
 	return rc;
 }
 
-#if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND ) \
-	|| defined( HAVE_TLS ) || defined( HAVE_CYRUS_SASL )
+#if defined( LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND ) || \
+	defined( HAVE_CYRUS_SASL )
 char *
 ldap_host_connected_to( Sockbuf *sb )
 {
@@ -510,7 +510,7 @@ ldap_host_connected_to( Sockbuf *sb )
 	LDAP_FREE( ha_buf );
 	return host;
 }
-#endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND || HAVE_TLS */
+#endif
 
 
 /* for UNIX */
diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c
index b1e7e170c29033d79b6d72606801247bcf5d99a6..9d87cd21beb80dcb9e292eef22fa5631d9adaf1b 100644
--- a/libraries/libldap/request.c
+++ b/libraries/libldap/request.c
@@ -95,8 +95,8 @@ ldap_send_initial_request(
 		}
 
 		Debug( LDAP_DEBUG_TRACE,
-			"ldap_delayed_open successful, ld_host is %s\n",
-			( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
+			"ldap_open_defconn: successful\n",
+			0, 0, 0 );
 	}
 
 	{
diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c
index 12cb3816638676ba485978f53ffef7c5731fa1a6..8945d957331159d1a61b272e67128582f27ca23b 100644
--- a/libraries/libldap/sasl.c
+++ b/libraries/libldap/sasl.c
@@ -67,6 +67,10 @@ ldap_sasl_bind(
 	assert( LDAP_VALID( ld ) );
 	assert( msgidp != NULL );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	if( msgidp == NULL ) {
 		ld->ld_errno = LDAP_PARAM_ERROR;
 		return ld->ld_errno;
diff --git a/libraries/libldap/search.c b/libraries/libldap/search.c
index 2d2071030261cf7545a8e2f6dfd624717a169639..5adb5b8ed2d7aa976264eb91664b6c5df1d1f745 100644
--- a/libraries/libldap/search.c
+++ b/libraries/libldap/search.c
@@ -91,6 +91,7 @@ ldap_search_ext(
 	int sizelimit,
 	int *msgidp )
 {
+	int rc;
 	BerElement	*ber;
 	int timelimit;
 
@@ -99,6 +100,10 @@ ldap_search_ext(
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
 
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	/*
 	 * if timeout is provided, both tv_sec and tv_usec must
 	 * be non-zero
diff --git a/libraries/libldap/test.c b/libraries/libldap/test.c
index a64dfc6b45b17ea6867ea0f8a2eb22efda7a80f5..42506dcd9d4ac2024e181f8d60ad5270d41e9f49 100644
--- a/libraries/libldap/test.c
+++ b/libraries/libldap/test.c
@@ -599,37 +599,6 @@ main( int argc, char **argv )
 			timeout.tv_sec = atoi( line );
 			break;
 
-		case 'U':	/* set ufn search prefix */
-			getline( line, sizeof(line), stdin, "ufn prefix? " );
-			ldap_ufn_setprefix( ld, line );
-			break;
-
-		case 'u':	/* user friendly search w/optional timeout */
-			getline( dn, sizeof(dn), stdin, "ufn? " );
-			strcat( dn, dnsuffix );
-			types = get_list( "attrs to return? " );
-			getline( line, sizeof(line), stdin,
-			    "attrsonly (0=attrs&values, 1=attrs only)? " );
-			attrsonly = atoi( line );
-
-			if ( command2 == 't' ) {
-				id = ldap_ufn_search_c( ld, dn, types,
-				    attrsonly, &res, ldap_ufn_timeout,
-				    &timeout );
-			} else {
-				id = ldap_ufn_search_s( ld, dn, types,
-				    attrsonly, &res );
-			}
-			if ( res == NULL )
-				ldap_perror( ld, "ldap_ufn_search" );
-			else {
-				printf( "\nresult: err %d\n", id );
-				handle_result( ld, res );
-				res = NULL;
-			}
-			free_list( types );
-			break;
-
 		case 'l':	/* URL search */
 			getline( line, sizeof(line), stdin,
 			    "attrsonly (0=attrs&values, 1=attrs only)? " );
diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c
index f74c56ff99299f84862673011f00e3c0d792a8fa..6053ef85cbf062b322c6e15694bc3c9067a1628b 100644
--- a/libraries/libldap/tls.c
+++ b/libraries/libldap/tls.c
@@ -553,16 +553,19 @@ BIO_METHOD ldap_pvt_sb_bio_method =
  *		and call again.
  */
 
-int
-ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg )
+static int
+ldap_int_tls_connect( LDAP *ld, LDAPConn *conn )
 {
+	Sockbuf *sb = conn->lconn_sb;
+	void *ctx = ld->ld_defconn->lconn_tls_ctx;
+
 	int	err;
 	SSL	*ssl;
 
 	if ( HAS_TLS( sb ) ) {
 		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
 	} else {
-		ssl = alloc_handle( ctx_arg );
+		ssl = alloc_handle( ctx );
 		if ( ssl == NULL )
 			return -1;
 #ifdef LDAP_DEBUG
@@ -652,7 +655,7 @@ ldap_pvt_tls_inplace ( Sockbuf *sb )
 }
 
 void *
-ldap_pvt_tls_sb_handle( Sockbuf *sb )
+ldap_pvt_tls_sb_ctx( Sockbuf *sb )
 {
 	void			*p;
 	
@@ -664,12 +667,6 @@ ldap_pvt_tls_sb_handle( Sockbuf *sb )
 	return NULL;
 }
 
-void *
-ldap_pvt_tls_get_handle( LDAP *ld )
-{
-	return ldap_pvt_tls_sb_handle( ld->ld_sb );
-}
-
 int
 ldap_pvt_tls_get_strength( void *s )
 {
@@ -680,7 +677,7 @@ ldap_pvt_tls_get_strength( void *s )
 }
 
 
-const char *
+char *
 ldap_pvt_tls_get_peer( void *s )
 {
     X509 *x;
@@ -698,12 +695,33 @@ ldap_pvt_tls_get_peer( void *s )
     return p;
 }
 
+char *
+ldap_pvt_tls_get_peer_dn( void *s )
+{
+	X509 *x;
+	X509_NAME *xn;
+	char buf[2048], *p, *dn;
+
+	x = SSL_get_peer_certificate((SSL *)s);
+
+	if (!x) return NULL;
+    
+	xn = X509_get_subject_name(x);
+	p = X509_NAME_oneline(xn, buf, sizeof(buf));
+
+	dn = ldap_dcedn2dn( p );
+
+	X509_free(x);
+	return dn;
+}
+
 char *
 ldap_pvt_tls_get_peer_hostname( void *s )
 {
 	X509 *x;
 	X509_NAME *xn;
 	char buf[2048], *p;
+	int ret;
 
 	x = SSL_get_peer_certificate((SSL *)s);
 
@@ -712,7 +730,8 @@ ldap_pvt_tls_get_peer_hostname( void *s )
 	
 	xn = X509_get_subject_name(x);
 
-	if ( X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)) == -1 ) {
+	ret = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf));
+	if( ret == -1 ) {
 		X509_free(x);
 		return NULL;
 	}
@@ -745,7 +764,7 @@ ldap_pvt_tls_get_peer_issuer( void *s )
 }
 
 int
-ldap_int_tls_config( struct ldapoptions *lo, int option, const char *arg )
+ldap_int_tls_config( LDAP *ld, int option, const char *arg )
 {
 	int i;
 
@@ -756,11 +775,13 @@ ldap_int_tls_config( struct ldapoptions *lo, int option, const char *arg )
 	case LDAP_OPT_X_TLS_KEYFILE:
 	case LDAP_OPT_X_TLS_RANDOM_FILE:
 		return ldap_pvt_tls_set_option( NULL, option, (void *) arg );
+
 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
 		i = ( ( strcasecmp( arg, "on" ) == 0 ) ||
 		      ( strcasecmp( arg, "yes" ) == 0) ||
 		      ( strcasecmp( arg, "true" ) == 0 ) );
 		return ldap_pvt_tls_set_option( NULL, option, (void *) &i );
+
 	case LDAP_OPT_X_TLS:
 		i = -1;
 		if ( strcasecmp( arg, "never" ) == 0 )
@@ -773,8 +794,10 @@ ldap_int_tls_config( struct ldapoptions *lo, int option, const char *arg )
 			i = LDAP_OPT_X_TLS_TRY ;
 		if ( strcasecmp( arg, "hard" ) == 0 )
 			i = LDAP_OPT_X_TLS_HARD ;
-		if (i >= 0)
-			return ldap_pvt_tls_set_option( lo, option, &i );
+
+		if (i >= 0) {
+			return ldap_pvt_tls_set_option( ld, option, &i );
+		}
 		return -1;
 	}
 
@@ -782,17 +805,35 @@ ldap_int_tls_config( struct ldapoptions *lo, int option, const char *arg )
 }
 
 int
-ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg )
+ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
 {
+	struct ldapoptions *lo;
+
+	/* Get pointer to global option structure */
+	lo = LDAP_INT_GLOBAL_OPT();   
+	if (NULL == lo)	{
+		return LDAP_NO_MEMORY;
+	}
+
+	if(ld != NULL) {
+		assert( LDAP_VALID( ld ) );
+
+		if( !LDAP_VALID( ld ) ) {
+			return LDAP_OPT_ERROR;
+		}
+
+		lo = &ld->ld_options;
+	}
+
 	switch( option ) {
 	case LDAP_OPT_X_TLS:
 		*(int *)arg = lo->ldo_tls_mode;
 		break;
-	case LDAP_OPT_X_TLS_CERT:
-		if ( lo == NULL )
+	case LDAP_OPT_X_TLS_CTX:
+		if ( ld == NULL )
 			*(void **)arg = (void *) tls_def_ctx;
 		else
-			*(void **)arg = lo->ldo_tls_ctx;
+			*(void **)arg = ld->ld_defconn->lconn_tls_ctx;
 		break;
 	case LDAP_OPT_X_TLS_CACERTFILE:
 		*(char **)arg = tls_opt_cacertfile ?
@@ -823,8 +864,26 @@ ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg )
 }
 
 int
-ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
+ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
 {
+	struct ldapoptions *lo;
+
+	/* Get pointer to global option structure */
+	lo = LDAP_INT_GLOBAL_OPT();   
+	if (NULL == lo)	{
+		return LDAP_NO_MEMORY;
+	}
+
+	if(ld != NULL) {
+		assert( LDAP_VALID( ld ) );
+
+		if( !LDAP_VALID( ld ) ) {
+			return LDAP_OPT_ERROR;
+		}
+
+		lo = &ld->ld_options;
+	}
+
 	switch( option ) {
 	case LDAP_OPT_X_TLS:
 		switch( *(int *) arg ) {
@@ -841,12 +900,12 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
 		}
 		return -1;
 
-	case LDAP_OPT_X_TLS_CERT:
-		if ( lo == NULL ) {
+	case LDAP_OPT_X_TLS_CTX:
+		if ( ld == NULL ) {
 			tls_def_ctx = (SSL_CTX *) arg;
 
 		} else {
-			lo->ldo_tls_ctx = arg;
+			ld->ld_defconn->lconn_tls_ctx = arg;
 		}
 		return 0;
 	}
@@ -890,9 +949,13 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg )
 }
 
 int
-ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
+ldap_int_tls_start ( LDAP *ld, LDAPConn *conn )
 {
-	char *peer_cert_cn, *peer_hostname;
+	Sockbuf *sb = conn->lconn_sb;
+	char *host = conn->lconn_server->lud_host;
+	void *ctx = ld->ld_defconn->lconn_tls_ctx;
+
+	char *peer_cert_cn;
 	void *ssl;
 
 	(void) ldap_pvt_tls_init();
@@ -900,14 +963,17 @@ ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
 	/*
 	 * Fortunately, the lib uses blocking io...
 	 */
-	if ( ldap_pvt_tls_connect( ld, sb, ctx_arg ) < 0 ) {
+	if ( ldap_int_tls_connect( ld, conn ) < 0 ) {
 		return LDAP_CONNECT_ERROR;
 	}
 
-	ssl = (void *) ldap_pvt_tls_sb_handle( sb );
+	ssl = (void *) ldap_pvt_tls_sb_ctx( sb );
+	assert( ssl != NULL );
+
 	/* 
-	 * compare hostname of server with name in certificate 
+	 * compare host with name in certificate 
 	 */
+
 	peer_cert_cn = ldap_pvt_tls_get_peer_hostname( ssl );
 	if ( !peer_cert_cn ) {
 		/* could not get hostname from peer certificate */
@@ -916,30 +982,17 @@ ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg )
 			0, 0, 0 );
 		return LDAP_LOCAL_ERROR;
 	}
-	
-	peer_hostname = ldap_host_connected_to( sb );
-	if ( !peer_hostname ) {
-		/* could not lookup hostname */
-		Debug( LDAP_DEBUG_ANY,
-			"TLS: unable to reverse lookup peer hostname.\n",
-			0, 0, 0 );
-		LDAP_FREE( peer_cert_cn );
-		return LDAP_LOCAL_ERROR;
-	}
 
-	if ( strcasecmp(peer_hostname, peer_cert_cn) != 0 ) {
+	if ( strcasecmp( host, peer_cert_cn ) != 0 ) {
 		Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
 			"common name in certificate (%s).\n", 
-			peer_hostname, peer_cert_cn, 0 );
+			host, peer_cert_cn, 0 );
 		LDAP_FREE( peer_cert_cn );
-		LDAP_FREE( peer_hostname );
 		return LDAP_CONNECT_ERROR;
-
-	} else {
-		LDAP_FREE( peer_cert_cn );
-		LDAP_FREE( peer_hostname );
 	}
 
+	LDAP_FREE( peer_cert_cn );
+
 	/*
 	 * set SASL properties to TLS ssf and authid
 	 */
@@ -1128,12 +1181,13 @@ ldap_start_tls_s ( LDAP *ld,
 	LDAPControl **serverctrls,
 	LDAPControl **clientctrls )
 {
-#ifdef HAVE_TLS
 	int rc;
+
+#ifdef HAVE_TLS
 	char *rspoid = NULL;
 	struct berval *rspdata = NULL;
 
-	/* XXYYZ: this initiates operaton only on default connection! */
+	/* XXYYZ: this initiates operation only on default connection! */
 
 	if ( ldap_pvt_tls_inplace( ld->ld_sb ) != 0 ) {
 		return LDAP_LOCAL_ERROR;
@@ -1153,10 +1207,10 @@ ldap_start_tls_s ( LDAP *ld,
 		ber_bvfree( rspdata );
 	}
 
-	rc = ldap_pvt_tls_start( ld, ld->ld_sb, ld->ld_options.ldo_tls_ctx );
-	return rc;
+	rc = ldap_int_tls_start( ld, ld->ld_defconn );
 #else
-	return LDAP_NOT_SUPPORTED;
+	rc = LDAP_NOT_SUPPORTED;
 #endif
+	return rc;
 }
 
diff --git a/libraries/libldap/ufn.c b/libraries/libldap/ufn.c
deleted file mode 100644
index ec79348fec07bafe4a57ec13f923f5deb2e0862d..0000000000000000000000000000000000000000
--- a/libraries/libldap/ufn.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/* $OpenLDAP$ */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
- */
-/*  Portions
- *  Copyright (c) 1990 Regents of the University of Michigan.
- *  All rights reserved.
- *
- *  ufn.c
- */
-
-#include "portable.h"
-
-#include <stdio.h>
-
-#include <ac/stdlib.h>
-
-#include <ac/socket.h>
-#include <ac/string.h>
-#include <ac/time.h>
-
-#include "ldap-int.h"
-#include "ldap_defaults.h"
-
-typedef int (*cancelptype) LDAP_P(( void *cancelparm ));
-
-/* local functions */
-static int ldap_ufn_search_ctx LDAP_P(( LDAP *ld, char **ufncomp, int ncomp, 
-	char *prefix, char **attrs, int attrsonly, LDAPMessage **res, 
-	cancelptype cancelproc, void *cancelparm, char *tag1, char *tag2,
-	char *tag3 ));
-static LDAPMessage *ldap_msg_merge LDAP_P(( LDAP *ld, LDAPMessage *a, LDAPMessage *b ));
-static LDAPMessage *ldap_ufn_expand LDAP_P(( LDAP *ld, cancelptype cancelproc,
-	void *cancelparm, char **dns, char *filter, int scope,
-	char **attrs, int aonly, int *err ));
-
-/*
- * ldap_ufn_search_ctx - do user friendly searching; provide cancel feature;
- *			specify ldapfilter.conf tags for each phase of search
- *
- *	ld		LDAP descriptor
- *	ufncomp		the exploded user friendly name to look for
- *	ncomp		number of elements in ufncomp
- *	prefix		where to start searching
- *	attrs		list of attribute types to return for matches
- *	attrsonly	1 => attributes only 0 => attributes and values
- *	res		will contain the result of the search
- *	cancelproc	routine that returns non-zero if operation should be
- *			cancelled.  This can be a null function pointer.  If
- *			it is not 0, the routine will be called periodically.
- *	cancelparm	void * that is passed to cancelproc
- *	tag[123]	the ldapfilter.conf tag that will be used in phases
- *			1, 2, and 3 of the search, respectively
- *
- * Example:
- *	char		*attrs[] = { "mail", "title", 0 };
- *	char		*ufncomp[] = { "howes", "umich", "us", 0 }
- *	LDAPMessage	*res;
- *	error = ldap_ufn_search_ctx( ld, ufncomp, 3, NULL, attrs, attrsonly,
- *			&res, acancelproc, along, "ufn first",
- *			"ufn intermediate", "ufn last" );
- */
-
-static int
-ldap_ufn_search_ctx( LDAP *ld, char **ufncomp, int ncomp, char *prefix,
-	char **attrs, int attrsonly, LDAPMessage **res, cancelptype cancelproc,
-	void *cancelparm, char *tag1, char *tag2, char *tag3 )
-{
-	char		*dn, *ftag = NULL;
-	char		**dns = NULL;
-	int		max, i, err, scope = 0, phase, tries;
-	LDAPFiltInfo	*fi;
-	LDAPMessage	*tmpcand;
-	LDAPMessage	*candidates;
-	static char	*objattrs[] = { "objectClass", NULL };
-
-	/* 
-	 * look up ufn components from most to least significant.
-	 * there are 3 phases.  
-	 * 	phase 1	search the root for orgs or countries
-	 * 	phase 2	search for orgs
-	 * 	phase 3	search for a person
-	 * in phases 1 and 2, we are building a list of candidate DNs,
-	 * below which we will search for the final component of the ufn.
-	 * for each component we try the filters listed in the
-	 * filterconfig file, first one-level (except the last compoment),
-	 * then subtree.  if any of them produce any results, we go on to
-	 * the next component.
-	 */
-
-	*res = NULL;
-	candidates = NULL;
-	phase = 1;
-	for ( ncomp--; ncomp != -1; ncomp-- ) {
-		if ( *ufncomp[ncomp] == '"' ) {
-			char	*quote;
-
-			if ( (quote = strrchr( ufncomp[ncomp], '"' )) != NULL )
-				*quote = '\0';
-			AC_MEMCPY( ufncomp[ncomp], ufncomp[ncomp] + 1,
-				    strlen( ufncomp[ncomp] + 1 ) + 1 );
-		}
-		if ( ncomp == 0 )
-			phase = 3;
-
-		switch ( phase ) {
-		case 1:
-			ftag = tag1;
-			scope = LDAP_SCOPE_ONELEVEL;
-			break;
-		case 2:
-			ftag = tag2;
-			scope = LDAP_SCOPE_ONELEVEL;
-			break;
-		case 3:
-			ftag = tag3;
-			scope = LDAP_SCOPE_SUBTREE;
-			break;
-		}
-
-		/*
-		 * construct an array of DN's to search below from the
-		 * list of candidates.
-		 */
-
-		if ( candidates == NULL ) {
-			if ( prefix != NULL ) {
-				if ( (dns = (char **) LDAP_MALLOC( sizeof(char *)
-				    * 2 )) == NULL ) {
-					return( ld->ld_errno = LDAP_NO_MEMORY );
-				}
-				dns[0] = LDAP_STRDUP( prefix );
-				dns[1] = NULL;
-			} else {
-				dns = NULL;
-			}
-		} else {
-			i = 0, max = 0;
-			for ( tmpcand = candidates; tmpcand != NULL &&
-			    tmpcand->lm_msgtype != LDAP_RES_SEARCH_RESULT;
-			    tmpcand = tmpcand->lm_chain )
-			{
-				if ( (dn = ldap_get_dn( ld, tmpcand )) == NULL )
-					continue;
-
-				if ( dns == NULL ) {
-					if ( (dns = (char **) LDAP_MALLOC(
-					    sizeof(char *) * 8 )) == NULL ) {
-						ld->ld_errno = LDAP_NO_MEMORY;
-						return( LDAP_NO_MEMORY );
-					}
-					max = 8;
-				} else if ( i >= max ) {
-					if ( (dns = (char **) LDAP_REALLOC( dns,
-					    sizeof(char *) * 2 * max ))
-					    == NULL )
-					{
-						ld->ld_errno = LDAP_NO_MEMORY;
-						return( LDAP_NO_MEMORY );
-					}
-					max *= 2;
-				}
-				dns[i++] = dn;
-				dns[i] = NULL;
-			}
-			ldap_msgfree( candidates );
-			candidates = NULL;
-		}
-		tries = 0;
-	tryagain:
-		tries++;
-		for ( fi = ldap_getfirstfilter( ld->ld_filtd, ftag,
-		    ufncomp[ncomp] ); fi != NULL;
-		    fi = ldap_getnextfilter( ld->ld_filtd ) )
-		{
-			if ( (candidates = ldap_ufn_expand( ld, cancelproc,
-			    cancelparm, dns, fi->lfi_filter, scope,
-			    phase == 3 ? attrs : objattrs,
-			    phase == 3 ? attrsonly : 1, &err )) != NULL )
-			{
-				break;
-			}
-
-			if ( err == -1 || err == LDAP_USER_CANCELLED ) {
-				if ( dns != NULL ) {
-					LDAP_VFREE( dns );
-					dns = NULL;
-				}
-				return( err );
-			}
-		}
-
-		if ( candidates == NULL ) {
-			if ( tries < 2 && phase != 3 ) {
-				scope = LDAP_SCOPE_SUBTREE;
-				goto tryagain;
-			} else {
-				if ( dns != NULL ) {
-					LDAP_VFREE( dns );
-					dns = NULL;
-				}
-				return( err );
-			}
-		}
-
-		/* go on to the next component */
-		if ( phase == 1 )
-			phase++;
-		if ( dns != NULL ) {
-			LDAP_VFREE( dns );
-			dns = NULL;
-		}
-	}
-	*res = candidates;
-
-	return( err );
-}
-
-int
-ldap_ufn_search_ct(
-	LDAP *ld, LDAP_CONST char *ufn, char **attrs, int attrsonly,
-	LDAPMessage **res, cancelptype cancelproc, void *cancelparm,
-	char *tag1, char *tag2, char *tag3 )
-{
-	char	**ufncomp, **prefixcomp;
-	char	*pbuf;
-	int	ncomp, pcomp, i, err = 0;
-
-	/* initialize the getfilter stuff if it's not already */
-	if ( ld->ld_filtd == NULL && ldap_ufn_setfilter( ld, FILTERFILE )
-	    == NULL ) {
-		return( ld->ld_errno = LDAP_LOCAL_ERROR );
-	}
-
-	/* call ldap_explode_dn() to break the ufn into its components */
-	if ( (ufncomp = ldap_explode_dn( ufn, 0 )) == NULL )
-		return( ld->ld_errno = LDAP_LOCAL_ERROR );
-	for ( ncomp = 0; ufncomp[ncomp] != NULL; ncomp++ )
-		;	/* NULL */
-
-	/* more than two components => try it fully qualified first */
-	if ( ncomp > 2 || ld->ld_ufnprefix == NULL ) {
-		err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, NULL, attrs,
-		    attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
-
-		if ( ldap_count_entries( ld, *res ) > 0 ) {
-			LDAP_VFREE( ufncomp );
-			return( err );
-		} else {
-			ldap_msgfree( *res );
-			*res = NULL;
-		}
-	}
-
-	if ( ld->ld_ufnprefix == NULL ) {
-		LDAP_VFREE( ufncomp );
-		return( err );
-	}
-
-	/* if that failed, or < 2 components, use the prefix */
-	if ( (prefixcomp = ldap_explode_dn( ld->ld_ufnprefix, 0 )) == NULL ) {
-		LDAP_VFREE( ufncomp );
-		return( ld->ld_errno = LDAP_LOCAL_ERROR );
-	}
-	for ( pcomp = 0; prefixcomp[pcomp] != NULL; pcomp++ )
-		;	/* NULL */
-	if ( (pbuf = (char *) LDAP_MALLOC( strlen( ld->ld_ufnprefix ) + 1 ))
-	    == NULL ) {	
-		LDAP_VFREE( ufncomp );
-		LDAP_VFREE( prefixcomp );
-		return( ld->ld_errno = LDAP_NO_MEMORY );
-	}
-
-	for ( i = 0; i < pcomp; i++ ) {
-		int	j;
-
-		*pbuf = '\0';
-		for ( j = i; j < pcomp; j++ ) {
-			strcat( pbuf, prefixcomp[j] );
-			if ( j + 1 < pcomp )
-				strcat( pbuf, "," );
-		}
-		err = ldap_ufn_search_ctx( ld, ufncomp, ncomp, pbuf, attrs,
-		    attrsonly, res, cancelproc, cancelparm, tag1, tag2, tag3 );
-
-		if ( ldap_count_entries( ld, *res ) > 0 ) {
-			break;
-		} else {
-			ldap_msgfree( *res );
-			*res = NULL;
-		}
-	}
-
-	LDAP_VFREE( ufncomp );
-	LDAP_VFREE( prefixcomp );
-	LDAP_FREE( pbuf );
-
-	return( err );
-}
-
-/*
- * same as ldap_ufn_search_ct, except without the ability to specify
- * ldapfilter.conf tags.
- */
-int
-ldap_ufn_search_c(
-	LDAP *ld, LDAP_CONST char *ufn, char **attrs, int attrsonly,
-	LDAPMessage **res, cancelptype cancelproc, void *cancelparm )
-{
-	return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res, cancelproc,
-	    cancelparm, "ufn first", "ufn intermediate", "ufn last" ) );
-}
-
-/*
- * same as ldap_ufn_search_c without the cancel function
- */
-int
-ldap_ufn_search_s(
-	LDAP *ld, LDAP_CONST char *ufn, char **attrs, int attrsonly,
-	LDAPMessage **res )
-{
-	struct timeval	tv;
-
-	tv.tv_sec = ld->ld_timelimit;
-
-	return( ldap_ufn_search_ct( ld, ufn, attrs, attrsonly, res,
-		ld->ld_timelimit ? ldap_ufn_timeout : NULL,
-		ld->ld_timelimit ? (void *) &tv : NULL,
-		"ufn first", "ufn intermediate", "ufn last" ) );
-}
-
-
-/*
- * ldap_msg_merge - merge two ldap search result chains.  the more
- * serious of the two error result codes is kept.
- */
-
-static LDAPMessage *
-ldap_msg_merge( LDAP *ld, LDAPMessage *a, LDAPMessage *b )
-{
-	LDAPMessage	*end, *aprev, *aend, *bprev, *bend;
-
-	if ( a == NULL )
-		return( b );
-
-	if ( b == NULL )
-		return( a );
-
-	/* find the ends of the a and b chains */
-	aprev = NULL;
-	for ( aend = a; aend->lm_chain != NULL; aend = aend->lm_chain )
-		aprev = aend;
-	bprev = NULL;
-	for ( bend = b; bend->lm_chain != NULL; bend = bend->lm_chain )
-		bprev = bend;
-
-	/* keep result a */
-	if ( ldap_result2error( ld, aend, 0 ) != LDAP_SUCCESS ) {
-		/* remove result b */
-		ldap_msgfree( bend );
-		if ( bprev != NULL )
-			bprev->lm_chain = NULL;
-		else
-			b = NULL;
-		end = aend;
-		if ( aprev != NULL )
-			aprev->lm_chain = NULL;
-		else
-			a = NULL;
-	/* keep result b */
-	} else {
-		/* remove result a */
-		ldap_msgfree( aend );
-		if ( aprev != NULL )
-			aprev->lm_chain = NULL;
-		else
-			a = NULL;
-		end = bend;
-		if ( bprev != NULL )
-			bprev->lm_chain = NULL;
-		else
-			b = NULL;
-	}
-
-	if ( (a == NULL && b == NULL) || (a == NULL && bprev == NULL) ||
-	    (b == NULL && aprev == NULL) )
-		return( end );
-
-	if ( a == NULL ) {
-		bprev->lm_chain = end;
-		return( b );
-	} else if ( b == NULL ) {
-		aprev->lm_chain = end;
-		return( a );
-	} else {
-		bprev->lm_chain = end;
-		aprev->lm_chain = b;
-		return( a );
-	}
-}
-
-static LDAPMessage *
-ldap_ufn_expand( LDAP *ld, cancelptype cancelproc, void *cancelparm,
-	char **dns, char *filter, int scope, char **attrs, int aonly,
-	int *err )
-{
-	LDAPMessage	*tmpcand, *tmpres;
-	char		*dn;
-	int		i, msgid;
-	struct timeval	tv;
-
-	/* search for this component below the current candidates */
-	tmpcand = NULL;
-	i = 0;
-	do {
-		if ( dns != NULL )
-			dn = dns[i];
-		else
-			dn = "";
-
-		if (( msgid = ldap_search( ld, dn, scope, filter, attrs,
-		    aonly )) == -1 ) {
-			ldap_msgfree( tmpcand );
-			*err = ld->ld_errno;
-			return( NULL );
-		}
-
-		tv.tv_sec = 0;
-		tv.tv_usec = 100000;	/* 1/10 of a second */
-
-		do {
-			*err = ldap_result( ld, msgid, 1, &tv, &tmpres );
-			if ( *err == 0 && cancelproc != 0 &&
-			    (*cancelproc)( cancelparm ) != 0 ) {
-				ldap_abandon( ld, msgid );
-				*err = LDAP_USER_CANCELLED;
-				ld->ld_errno = LDAP_USER_CANCELLED;
-			}
-		} while ( *err == 0 );
-
-		if ( *err == LDAP_USER_CANCELLED || *err < 0 ||
-		    ( *err = ldap_result2error( ld, tmpres, 0 )) == -1 ) {
-			ldap_msgfree( tmpcand );
-			return( NULL );
-		}
-		
-		tmpcand = ldap_msg_merge( ld, tmpcand, tmpres );
-
-		i++;
-	} while ( dns != NULL && dns[i] != NULL );
-
-	if ( ldap_count_entries( ld, tmpcand ) > 0 ) {
-		return( tmpcand );
-	} else {
-		ldap_msgfree( tmpcand );
-		return( NULL );
-	}
-}
-
-/*
- * ldap_ufn_setfilter - set the filter config file used in ufn searching
- */
-
-LDAPFiltDesc *
-ldap_ufn_setfilter( LDAP *ld, LDAP_CONST char *fname )
-{
-	if ( ld->ld_filtd != NULL )
-		ldap_getfilter_free( ld->ld_filtd );
-
-	return( ld->ld_filtd = ldap_init_getfilter( fname ) );
-}
-
-void
-ldap_ufn_setprefix( LDAP *ld, LDAP_CONST char *prefix )
-{
-	if ( ld->ld_ufnprefix != NULL )
-		LDAP_FREE( ld->ld_ufnprefix );
-
-	ld->ld_ufnprefix = prefix == NULL
-		? NULL : LDAP_STRDUP( prefix );
-}
-
-int
-ldap_ufn_timeout( void *tvparam )
-{
-	struct timeval	*tv;
-
-	tv = (struct timeval *)tvparam;
-
-	if ( tv->tv_sec != 0 ) {
-		tv->tv_usec = tv->tv_sec * 1000000;	/* sec => micro sec */
-		tv->tv_sec = 0;
-	}
-	tv->tv_usec -= 100000;	/* 1/10 of a second */
-
-	return( tv->tv_usec <= 0 ? 1 : 0 );
-}
diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c
index 5c6c324eefbe6d70091ca41abf8b431658e6e1df..0d5f3fe46ac3204488e8d7443cc2514fbb3e6a83 100644
--- a/libraries/libldap/unbind.c
+++ b/libraries/libldap/unbind.c
@@ -34,6 +34,12 @@ ldap_unbind_ext(
 	LDAPControl **sctrls,
 	LDAPControl **cctrls )
 {
+	int rc;
+
+	/* check client controls */
+	rc = ldap_int_client_controls( ld, cctrls );
+	if( rc != LDAP_SUCCESS ) return rc;
+
 	return ldap_ld_free( ld, 1, sctrls, cctrls );
 }
 
@@ -99,21 +105,6 @@ ldap_ld_free(
 		ld->ld_matched = NULL;
 	}
 
-	if ( ld->ld_host != NULL ) {
-		LDAP_FREE( ld->ld_host );
-		ld->ld_host = NULL;
-	}
-
-	if ( ld->ld_ufnprefix != NULL ) {
-		LDAP_FREE( ld->ld_ufnprefix );
-		ld->ld_ufnprefix = NULL;
-	}
-
-	if ( ld->ld_filtd != NULL ) {
-		ldap_getfilter_free( ld->ld_filtd );
-		ld->ld_filtd = NULL;
-	}
-
 	if ( ld->ld_abandoned != NULL ) {
 		LDAP_FREE( ld->ld_abandoned );
 		ld->ld_abandoned = NULL;
diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in
index 82321679c5f2b81cbf1b70eb2cac4d39bd92d73a..c45eb367f5ecd577688facbb93a3ab3d154445b2 100644
--- a/libraries/libldap_r/Makefile.in
+++ b/libraries/libldap_r/Makefile.in
@@ -12,7 +12,7 @@ PROGRAMS = apitest ltest ttest
 XXDIR = $(srcdir)/../libldap
 XXSRCS	= apitest.c test.c tmpltest.c extended.c \
 	bind.c controls.c open.c result.c error.c compare.c search.c \
-	modify.c add.c modrdn.c delete.c abandon.c ufn.c cache.c cyrus.c \
+	modify.c add.c modrdn.c delete.c abandon.c cache.c cyrus.c \
 	getfilter.c sasl.c sbind.c kbind.c unbind.c friendly.c \
 	free.c disptmpl.c srchpref.c dsparse.c tmplout.c sort.c \
 	getdn.c getentry.c getattr.c getvalues.c addentry.c \
@@ -28,7 +28,7 @@ OBJS	= threads.lo rdwr.lo tpool.lo  \
 	thr_pth.lo thr_stub.lo \
 	extended.lo \
 	bind.lo controls.lo open.lo result.lo error.lo compare.lo search.lo \
-	modify.lo add.lo modrdn.lo delete.lo abandon.lo ufn.lo cache.lo cyrus.lo \
+	modify.lo add.lo modrdn.lo delete.lo abandon.lo cache.lo cyrus.lo \
 	getfilter.lo sasl.lo sbind.lo kbind.lo unbind.lo friendly.lo \
 	free.lo disptmpl.lo srchpref.lo dsparse.lo tmplout.lo sort.lo \
 	getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
diff --git a/servers/slapd/charray.c b/servers/slapd/charray.c
index b51659141a24ccfe13a5fb12d7a16c9d12ec0da5..c8790791be00470ea8ecca4f218f5d38941d37ce 100644
--- a/servers/slapd/charray.c
+++ b/servers/slapd/charray.c
@@ -38,6 +38,33 @@ charray_add(
 	(*a)[n] = NULL;
 }
 
+void
+charray_add_n(
+    char	***a,
+    const char	*s,
+    int         l
+)
+{
+	int	n;
+
+	if ( *a == NULL ) {
+		*a = (char **) ch_malloc( 2 * sizeof(char *) );
+		n = 0;
+	} else {
+		for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+			;	/* NULL */
+		}
+
+		*a = (char **) ch_realloc( (char *) *a,
+		    (n + 2) * sizeof(char *) );
+	}
+
+	(*a)[n] = (char *) ch_malloc( ( l + 1 ) * sizeof( char ) );
+	strncpy( (*a)[n], s, l );
+	(*a)[n][l] = '\0';
+	(*a)[++n] = NULL;
+}
+
 void
 charray_merge(
     char	***a,
@@ -151,3 +178,38 @@ str2charray( const char *str_in, const char *brkstr )
 	free( str );
 	return( res );
 }
+
+
+int
+charray_strcmp( const char **a1, const char **a2 )
+{
+	for ( ; a1[0] && a2[0]; a1++, a2++ ) {
+		if ( strcmp( a1[0], a2[0] ) ) {
+			return( !0 );
+		}
+	}
+
+	if ( ! ( a1[0] && a2[0] ) ) {
+		return( !0 );
+	}
+
+	return 0;
+}
+
+
+int
+charray_strcasecmp( const char **a1, const char **a2 )
+{
+	for ( ; a1[0] && a2[0]; a1++, a2++ ) {
+		if ( strcasecmp( a1[0], a2[0] ) ) {
+			return( !0 );
+		}
+	}
+
+	if ( ! ( a1[0] && a2[0] ) ) {
+		return( !0 );
+	}
+
+	return 0;
+}
+
diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c
index 262304a514770b265a6c4e134c09bb862caaaef3..bdf06f5335e430d3786858b24869a873e98b1d70 100644
--- a/servers/slapd/compare.c
+++ b/servers/slapd/compare.c
@@ -94,7 +94,7 @@ do_compare(
 		goto cleanup;
 	}
 
-	if( ndn == '\0' ) {
+	if( *ndn == '\0' ) {
 		Debug( LDAP_DEBUG_ANY, "do_compare: root dse!\n", 0, 0, 0 );
 		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
 			NULL, "compare upon the root DSE not supported", NULL, NULL );
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
index 0d95090815d1662aaaa7be18f199b71fbdff9d6f..2c0b3597f5ad5c7dfcf5512c7d8762cf54c9ae24 100644
--- a/servers/slapd/connection.c
+++ b/servers/slapd/connection.c
@@ -969,7 +969,7 @@ int connection_read(ber_socket_t s)
 			c->c_needs_tls_accept = 0;
 
 			/* we need to let SASL know */
-			ssl = (void *)ldap_pvt_tls_sb_handle( c->c_sb );
+			ssl = (void *)ldap_pvt_tls_sb_ctx( c->c_sb );
 
 			c->c_tls_ssf = (slap_ssf_t) ldap_pvt_tls_get_strength( ssl );
 			if( c->c_tls_ssf > c->c_ssf ) {
diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c
index c253949f7b5b08af03bb68fc1dd1a11222132dd5..4b6caecdfcde24b453fb889e24ecdebc05d75c67 100644
--- a/servers/slapd/delete.c
+++ b/servers/slapd/delete.c
@@ -66,7 +66,7 @@ do_delete(
 		goto cleanup;
 	}
 
-	if( ndn == '\0' ) {
+	if( *ndn == '\0' ) {
 		Debug( LDAP_DEBUG_ANY, "do_delete: root dse!\n", 0, 0, 0 );
 		/* protocolError would likely be a more appropriate error */
 		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c
index c70bb2d9af25b02d4f783c18d91fea34f3e64902..6334a7679cc951bfa60cc58d3092ee6e02c1f23e 100644
--- a/servers/slapd/modify.c
+++ b/servers/slapd/modify.c
@@ -152,7 +152,7 @@ do_modify(
 		goto cleanup;
 	}
 
-	if( ndn == '\0' ) {
+	if( *ndn == '\0' ) {
 		Debug( LDAP_DEBUG_ANY, "do_modify: root dse!\n", 0, 0, 0 );
 
 		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c
index 7bcf98ecf63bf35daa8d821dc38252ffeeba6475..c4fffbbf84f5eeba6dac806682d45803bbb9d130 100644
--- a/servers/slapd/modrdn.c
+++ b/servers/slapd/modrdn.c
@@ -151,7 +151,7 @@ do_modrdn(
 		goto cleanup;
 	}
 
-	if( ndn == '\0' ) {
+	if( *ndn == '\0' ) {
 		Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 );
 		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
 			NULL, "cannot rename the root DSE", NULL, NULL );
diff --git a/servers/slapd/starttls.c b/servers/slapd/starttls.c
index 97bbab084ac9dd34cbd9fd11cb3a06b1333133b0..b5582e765254f2b22f38f0386dea1bdc53dae7d4 100644
--- a/servers/slapd/starttls.c
+++ b/servers/slapd/starttls.c
@@ -75,7 +75,7 @@ starttls_extop (
 	}
 
 	/* fail if TLS could not be initialized */
-	if (ldap_pvt_tls_get_option(NULL, LDAP_OPT_X_TLS_CERT, &ctx) != 0
+	if (ldap_pvt_tls_get_option( NULL, LDAP_OPT_X_TLS_CTX, &ctx ) != 0
 		|| ctx == NULL)
 	{
 		if (default_referral != NULL) {