diff --git a/configure b/configure
index 12be49680c2d90ae72c3a8dfb0b591d9a7d2f11c..27d34f6d3670fd8ba9bad5b927453cca6ba0ef93 100755
--- a/configure
+++ b/configure
@@ -40,6 +40,8 @@ ac_help="$ac_help
   --enable-referrals	enable V2 Referrals extension (yes)"
 ac_help="$ac_help
   --enable-cldap	enable connectionless ldap (no)"
+ac_help="$ac_help
+  --enable-ldapi	enable domain socket (PF_LOCAL) transport (no)"
 ac_help="$ac_help
   --enable-x-compile	enable cross compiling (no)"
 ac_help="$ac_help
@@ -1305,6 +1307,26 @@ else
   	ol_enable_cldap="no"
 fi
 # end --enable-cldap
+# OpenLDAP --enable-ldapi
+	# Check whether --enable-ldapi or --disable-ldapi was given.
+if test "${enable_ldapi+set}" = set; then
+  enableval="$enable_ldapi"
+  
+	ol_arg=invalid
+	for ol_val in auto yes no ; do
+		if test "$enableval" = "$ol_val" ; then
+			ol_arg="$ol_val"
+		fi
+	done
+	if test "$ol_arg" = "invalid" ; then
+		{ echo "configure: error: bad value $enableval for --enable-ldapi" 1>&2; exit 1; }
+	fi
+	ol_enable_ldapi="$ol_arg"
+
+else
+  	ol_enable_ldapi="no"
+fi
+# end --enable-ldapi
 # OpenLDAP --enable-x_compile
 	# Check whether --enable-x_compile or --disable-x_compile was given.
 if test "${enable_x_compile+set}" = set; then
@@ -1347,8 +1369,8 @@ else
 fi
 # end --enable-dmalloc
 
-# OpenLDAP --with-cyrus_sasl
-	# Check whether --with-cyrus_sasl or --without-cyrus_sasl was given.
+# OpenLDAP --with-cyrus-sasl
+	# Check whether --with-cyrus-sasl or --without-cyrus_sasl was given.
 if test "${with_cyrus_sasl+set}" = set; then
   withval="$with_cyrus_sasl"
   
@@ -1359,14 +1381,14 @@ if test "${with_cyrus_sasl+set}" = set; then
 		fi
 	done
 	if test "$ol_arg" = "invalid" ; then
-		{ echo "configure: error: bad value $withval for --with-cyrus_sasl" 1>&2; exit 1; }
+		{ echo "configure: error: bad value $withval for --with-cyrus-sasl" 1>&2; exit 1; }
 	fi
 	ol_with_cyrus_sasl="$ol_arg"
 
 else
   	ol_with_cyrus_sasl="auto"
 fi
-# end --with-cyrus_sasl
+# end --with-cyrus-sasl
 
 # OpenLDAP --with-fetch
 	# Check whether --with-fetch or --without-fetch was given.
@@ -4601,6 +4623,7 @@ for ac_hdr in \
 	sys/resource.h	\
 	sys/select.h	\
 	sys/socket.h	\
+	sys/un.h	\
 	sys/syslog.h	\
 	sys/time.h		\
 	sys/types.h		\
@@ -14909,7 +14932,12 @@ if test "$ol_enable_cldap" != no ; then
 EOF
 
 fi
+if test "$ol_enable_ldapi" != no ; then
+	cat >> confdefs.h <<\EOF
+#define LDAP_PF_LOCAL 1
+EOF
 
+fi
 if test "$ol_enable_crypt" != no ; then
 	cat >> confdefs.h <<\EOF
 #define SLAPD_CRYPT 1
diff --git a/configure.in b/configure.in
index 8b4439f8ed56d62607cd418cd5c3db36bbc4db9f..75bbc1aeda7d205bbb82537abf07dd287542db79 100644
--- a/configure.in
+++ b/configure.in
@@ -97,6 +97,7 @@ OL_ARG_ENABLE(cache,[  --enable-cache	enable caching], yes)dnl
 OL_ARG_ENABLE(dns,[  --enable-dns		enable V2 DX Referrals extension], no)dnl
 OL_ARG_ENABLE(referrals,[  --enable-referrals	enable V2 Referrals extension], yes)dnl
 OL_ARG_ENABLE(cldap,[  --enable-cldap	enable connectionless ldap], no)dnl
+OL_ARG_ENABLE(ldapi,[  --enable-ldapi	enable domain socket (PF_LOCAL) ldap], no)dnl
 OL_ARG_ENABLE(x_compile,[  --enable-x-compile	enable cross compiling],
 	no, [yes no])dnl
 
@@ -2079,6 +2080,9 @@ fi
 if test "$ol_enable_cldap" != no ; then
 	AC_DEFINE(LDAP_CONNECTIONLESS,1,[define to support CLDAP])
 fi
+if test "$ol_enable_ldapi" != no; then
+	AC_DEFINE(USE_PF_LOCAL,1,[define to support PF_LOCAL transport])
+fi
 
 if test "$ol_enable_crypt" != no ; then
 	AC_DEFINE(SLAPD_CRYPT,1,[define to support crypt(3) passwords])
diff --git a/include/ac/socket.h b/include/ac/socket.h
index 35c5ba3b3556a8976aa732405a236444eeffc9ca..5e20569f54f6f3bf115464232413577a7857501a 100644
--- a/include/ac/socket.h
+++ b/include/ac/socket.h
@@ -20,6 +20,10 @@
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
diff --git a/include/ldap.h b/include/ldap.h
index 57ee5715b4f0d525675384cd3bfeb5e96e969cb9..d2f1a145e37f7cf5f77f0b23ecbc3cbc4d5da77a 100644
--- a/include/ldap.h
+++ b/include/ldap.h
@@ -487,17 +487,27 @@ typedef struct ldap_friendly {
  * types for ldap URL handling
  */
 typedef struct ldap_url_desc {
-	struct ldap_url_desc *lud_next;
-	int		lud_ldaps;
+    struct ldap_url_desc *lud_next;
+    unsigned long lud_properties;
+    int		lud_protocol;
     char	*lud_host;
     int		lud_port;
     char	*lud_dn;
     char	**lud_attrs;
     int		lud_scope;
     char	*lud_filter;
-	char	**lud_exts;
+    char	**lud_exts;
 } LDAPURLDesc;
 
+/* lud_properties */
+#define	LDAP_URL_USE_SSL		0x00000001
+#define LDAP_URL_USE_SSL_UNSPECIFIED	0x00000002
+
+/* lud_protocol */
+#define LDAP_PROTO_TCP			0x00
+#define LDAP_PROTO_UDP			0x01	
+#define LDAP_PROTO_LOCAL		0x02
+
 #define LDAP_URL_SUCCESS		0x00	/* Success */
 #define LDAP_URL_ERR_MEM		0x01	/* can't allocate memory space */
 #define LDAP_URL_ERR_PARAM		0x02	/* parameter is bad */
@@ -637,6 +647,17 @@ ldap_sasl_bind LDAP_P((
 	LDAPControl		**clientctrls,
 	int				*msgidp ));
 
+LIBLDAP_F( int )
+ldap_negotiated_sasl_bind_s LDAP_P((
+	LDAP *ld,
+	LDAP_CONST char *dn, /* usually NULL */
+	LDAP_CONST char *authorizationId,
+	LDAP_CONST char *authenticationId, /* usually NULL */
+	LDAP_CONST char *saslMechanism,
+	struct berval *passPhrase,
+	LDAPControl **serverControls,
+	LDAPControl **clientControls ));
+
 LIBLDAP_F( int )
 ldap_sasl_bind_s LDAP_P((
 	LDAP			*ld,
@@ -1126,6 +1147,11 @@ LIBLDAP_F( int )
 ldap_is_dns_dn LDAP_P((	/* deprecated */
 	LDAP_CONST char *dn ));
 
+LIBLDAP_F( char * )
+ldap_dn2dcedn LDAP_P(( LDAP_CONST char *dn ));
+
+LIBLDAP_F( char * )
+ldap_dcedn2dn LDAP_P(( LDAP_CONST char *dce ));
 
 /*
  * in getattr.c
diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h
index 632652cd64a7afeb7a30a88d2928194dd56346fb..8e21b5df7ddd94fb605fed83ab2e25226dca7ee2 100644
--- a/include/ldap_pvt.h
+++ b/include/ldap_pvt.h
@@ -100,6 +100,13 @@ LIBLDAP_F (int) ldap_pvt_unhex( int c );
 
 #define LDAP_NEEDSESCAPE(c)	((c) == '\\' || (c) == '"')
 
+#ifdef HAVE_CYRUS_SASL
+/* sasl.c */
+LIBLDAP_F (int) ldap_pvt_sasl_init LDAP_P(( void )); /* clientside init */
+LIBLDAP_F (int) ldap_pvt_sasl_install LDAP_P(( Sockbuf *, void * ));
+LIBLDAP_F (int) ldap_pvt_sasl_err2ldap LDAP_P(( int ));
+#endif /* HAVE_CYRUS_SASL */
+
 /* search.c */
 LIBLDAP_F( char * )
 ldap_pvt_find_wildcard LDAP_P((	char *s ));
diff --git a/include/portable.h.in b/include/portable.h.in
index bff5d52a4bfaaa80644bc1901fc2915cd5d3ca46..7faa3ce31686c75fcab6bc69f416cd3046cdf676 100644
--- a/include/portable.h.in
+++ b/include/portable.h.in
@@ -531,6 +531,9 @@
 /* Define if you have the <sys/types.h> header file.  */
 #undef HAVE_SYS_TYPES_H
 
+/* Define if you have the <sys/un.h> header file.  */
+#undef HAVE_SYS_UN_H
+
 /* Define if you have the <sysexits.h> header file.  */
 #undef HAVE_SYSEXITS_H
 
@@ -834,6 +837,9 @@
 /* define to support CLDAP */
 #undef LDAP_CONNECTIONLESS
 
+/* define to support domain sockets */
+#undef LDAP_PF_LOCAL
+
 /* define to support crypt(3) passwords */
 #undef SLAPD_CRYPT
 
diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in
index 764c29346e5cc4124f961e285154797f93ad19e4..43bd9e71615257ad4e1134d1f121f7b22245b632 100644
--- a/libraries/libldap/Makefile.in
+++ b/libraries/libldap/Makefile.in
@@ -17,7 +17,7 @@ SRCS	= bind.c open.c result.c error.c compare.c search.c \
 	getdn.c getentry.c getattr.c getvalues.c addentry.c \
 	request.c getdxbyname.c os-ip.c url.c charset.c \
 	init.c options.c print.c string.c util-int.c schema.c \
-	charray.c digest.c tls.c dn.c
+	charray.c digest.c tls.c dn.c os-local.c
 OBJS	= bind.lo open.lo result.lo error.lo compare.lo search.lo \
 	controls.lo messages.lo references.lo extended.lo \
 	modify.lo add.lo modrdn.lo delete.lo abandon.lo ufn.lo cache.lo \
@@ -26,7 +26,7 @@ OBJS	= bind.lo open.lo result.lo error.lo compare.lo search.lo \
 	getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
 	request.lo getdxbyname.lo os-ip.lo url.lo charset.lo \
 	init.lo options.lo print.lo string.lo util-int.lo schema.lo \
-	charray.lo digest.lo tls.lo dn.lo
+	charray.lo digest.lo tls.lo dn.lo os-local.lo
 
 LDAP_INCDIR= ../../include       
 LDAP_LIBDIR= ../../libraries
diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c
index 0110e298e719649340db1af1513c6c3e8072fc37..f03be3b455d15a1c7039cc41e20f0bb1882eca6f 100644
--- a/libraries/libldap/getdn.c
+++ b/libraries/libldap/getdn.c
@@ -23,6 +23,10 @@
 
 #include "ldap-int.h"
 
+#define DN_TYPE_LDAP_RDN	0
+#define DN_TYPE_LDAP_DN		1
+#define DN_TYPE_DCE_DN		2
+
 static char **explode_name( const char *name, int notypes, int is_dn );
 
 char *
@@ -180,14 +184,98 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes )
 	if ( ldap_is_dns_dn( dn ) ) {
 		return( ldap_explode_dns( dn ) );
 	}
-	return explode_name( dn, notypes, 1 );
+	return explode_name( dn, notypes, DN_TYPE_LDAP_DN );
 }
 
 char **
 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
 {
 	Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
-	return explode_name( rdn, notypes, 0 );
+	return explode_name( rdn, notypes, DN_TYPE_LDAP_RDN );
+}
+
+char *
+ldap_dn2dcedn( LDAP_CONST char *dn )
+{
+	char *dce, *q, **rdns, **p;
+	int len = 0;
+
+	Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
+
+	rdns = explode_name( dn, 0, DN_TYPE_LDAP_DN );
+	if ( rdns == NULL ) {
+		return NULL;
+	}
+	
+	for ( p = rdns; *p != NULL; p++ ) {
+		len += strlen( *p ) + 1;
+	}
+
+	q = dce = LDAP_MALLOC( len + 1 );
+	if ( dce == NULL ) {
+		return NULL;
+	}
+
+	p--; /* get back past NULL */
+
+	for ( ; p != rdns; p-- ) {
+		strcpy( q, "/" );
+		q++;
+		strcpy( q, *p );
+		q += strlen( *p );
+	}
+
+	strcpy( q, "/" );
+	q++;
+	strcpy( q, *p );
+	
+	return dce;
+}
+
+char *
+ldap_dcedn2dn( LDAP_CONST char *dce )
+{
+	char *dn, *q, **rdns, **p;
+	int len;
+
+	Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
+
+	rdns = explode_name( dce, 0, DN_TYPE_DCE_DN );
+	if ( rdns == NULL ) {
+		return NULL;
+	}
+
+	len = 0;
+
+	for ( p = rdns; *p != NULL; p++ ) {
+		len += strlen( *p ) + 1;
+	}
+
+	q = dn = LDAP_MALLOC( len );
+	if ( dn == NULL ) {
+		return NULL;
+	}
+
+	p--;
+
+	for ( ; p != rdns; p-- ) {
+		strcpy( q, *p );
+		q += strlen( *p );
+		strcpy( q, "," );
+		q++;
+	}
+
+	if ( *dce == '/' ) {
+		/* the name was fully qualified, thus the most-significant
+		 * RDN was empty. trash the last comma */
+		q--;
+		*q = '\0';
+	} else {
+		/* the name was relative. copy the most significant RDN */
+		strcpy( q, *p );
+	}
+
+	return dn;
 }
 
 static char **
@@ -215,14 +303,18 @@ explode_name( const char *name, int notypes, int is_dn )
 				state = INQUOTE;
 			break;
 		case '+':
-			if (!is_dn)
+			if (is_dn == DN_TYPE_LDAP_RDN)
+				goto end_part;
+			break;
+		case '/':
+			if (is_dn == DN_TYPE_DCE_DN)
 				goto end_part;
 			break;
 		case ';':
 		case ',':
-			if (!is_dn)
-				break;
-			goto end_part;
+			if (is_dn == DN_TYPE_LDAP_DN)
+				goto end_part;
+			break;
 		case '\0':
 		end_part:
 			if ( state == OUTQUOTE ) {
diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c
index e7a8f0174b73c2b800915ef979412694a6621a1d..5628eea1e7cb04b24f6331d7b77f139509de8e45 100644
--- a/libraries/libldap/init.c
+++ b/libraries/libldap/init.c
@@ -343,6 +343,10 @@ void ldap_int_initialize( void )
    	ldap_pvt_tls_init();
 #endif
 
+#ifdef HAVE_CYRUS_SASL
+	ldap_pvt_sasl_init();
+#endif
+
 	if ( ldap_int_tblsize == 0 )
 		ldap_int_ip_init();
 
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
index 04c1b3147fbd0193db8d3230b94b742203964ef9..eca39c573f2347ef83b286b83374b06f588338cd 100644
--- a/libraries/libldap/ldap-int.h
+++ b/libraries/libldap/ldap-int.h
@@ -30,12 +30,20 @@
 
 #include "ldap_pvt.h"
 
+#ifdef HAVE_CYRUS_SASL
+#include <sasl.h>
+#endif /* HAVE_CYRUS_SASL */
+
 LDAP_BEGIN_DECL
 
 #define LDAP_URL_PREFIX         "ldap://"
 #define LDAP_URL_PREFIX_LEN     (sizeof(LDAP_URL_PREFIX)-1)
 #define LDAPS_URL_PREFIX		"ldaps://"
 #define LDAPS_URL_PREFIX_LEN	(sizeof(LDAPS_URL_PREFIX)-1)
+#define LDAPI_URL_PREFIX	"ldapi://"
+#define LDAPI_URL_PREFIX_LEN	(sizeof(LDAPI_URL_PREFIX)-1)
+#define LDAPIS_URL_PREFIX	"ldapis://"
+#define LDAPIS_URL_PREFIX_LEN	(sizeof(LDAPIS_URL_PREFIX)-1)
 #define LDAP_URL_URLCOLON		"URL:"
 #define LDAP_URL_URLCOLON_LEN	(sizeof(LDAP_URL_URLCOLON)-1)
 #define NULLLDAPURLDESC ((LDAPURLDesc *)NULL)
@@ -132,6 +140,7 @@ typedef struct ldap_server {
 	char			*lsrv_host;
 	char			*lsrv_dn;	/* if NULL, use default */
 	int			lsrv_port;
+/*	int			lsrv_protocol; */
 	struct ldap_server	*lsrv_next;
 } LDAPServer;
 
@@ -266,6 +275,9 @@ struct ldap {
 	int		(*ld_rebindproc)( struct ldap *ld, char **dnp,
 				char **passwdp, int *authmethodp, int freeit );
 				/* routine to get info needed for re-bind */
+#ifdef HAVE_CYRUS_SASL
+	sasl_conn_t		*ld_sasl_context;
+#endif /* HAVE_CYRUS_SASL */
 };
 #define LDAP_VALID(ld)	( (ld)->ld_valid == LDAP_VALID_SESSION )
 
@@ -355,7 +367,6 @@ LIBLDAP_F (char *) ldap_get_kerberosv4_credentials LDAP_P((
 LIBLDAP_F (int) ldap_open_defconn( LDAP *ld );
 LIBLDAP_F (int) open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srvlist, char **krbinstancep, int async );
 
-
 /*
  * in os-ip.c
  */
@@ -365,7 +376,7 @@ LIBLDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host, u
 
 LIBLDAP_F (void) ldap_close_connection( Sockbuf *sb );
 
-#ifdef HAVE_KERBEROS
+#if defined(HAVE_KERBEROS) || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
 LIBLDAP_F (char *) ldap_host_connected_to( Sockbuf *sb );
 #endif /* HAVE_KERBEROS */
 
@@ -379,6 +390,12 @@ LIBLDAP_F (void) ldap_mark_select_clear( LDAP *ld, Sockbuf *sb );
 LIBLDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb );
 LIBLDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb );
 
+#ifdef LDAP_PF_LOCAL 
+/*
+ * in os-local.c
+ */
+LIBLDAP_F (int) ldap_connect_to_path( LDAP *ld, Sockbuf *sb, const char *path, int async );
+#endif /* LDAP_PF_LOCAL */
 
 /*
  * in request.c
@@ -395,7 +412,6 @@ LIBLDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr );
 LIBLDAP_F (void) ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind );
 LIBLDAP_F (void) ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all );
 LIBLDAP_F (void) ldap_dump_requests_and_responses( LDAP *ld );
-
 LIBLDAP_F (int) ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp );
 LIBLDAP_F (int) ldap_append_referral( LDAP *ld, char **referralsp, char *s );
 
diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c
index 43c7b80a92fe9fd6b3a9adf414badc2d8bf64eee..462b60b39401c20da206e3b76fecfbb827c7d623 100644
--- a/libraries/libldap/open.c
+++ b/libraries/libldap/open.c
@@ -287,7 +287,19 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv,
 	if ( srv->lud_host == NULL || *srv->lud_host == 0 )
 		addr = htonl( INADDR_LOOPBACK );
 
-	rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async );
+	switch ( srv->lud_protocol ) {
+		case LDAP_PROTO_TCP:
+		case LDAP_PROTO_UDP:
+			rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async );
+			break;
+		case LDAP_PROTO_LOCAL:
+			rc = ldap_connect_to_path( ld, sb, srv->lud_host, async );
+			break;
+		default:
+			rc = -1;
+			break;
+	}
+
 	if ( rc == -1 ) {
 		return( rc );
 	}
@@ -295,9 +307,10 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv,
    	ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
 
 #ifdef HAVE_TLS
-	tls = srv->lud_ldaps;
-	if (tls == -1)
-		tls = ld->ld_options.ldo_tls_mode;
+	tls = (srv->lud_properties & LDAP_URL_USE_SSL);
+	if (tls == 0)
+		tls = (srv->lud_properties & LDAP_URL_USE_SSL_UNSPECIFIED);
+
 	if ( tls != 0 ) {
 		rc = ldap_pvt_tls_start( sb, ld->ld_options.ldo_tls_ctx );
 		if (rc != LDAP_SUCCESS)
diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c
index 4a908d05755ed4ff62adb235a31024223975f455..530c9299dcea66b3a1f7041b179b98205ed960a1 100644
--- a/libraries/libldap/os-ip.c
+++ b/libraries/libldap/os-ip.c
@@ -333,7 +333,7 @@ ldap_close_connection( Sockbuf *sb )
 }
 
 
-#if defined( HAVE_KERBEROS ) || defined( HAVE_TLS )
+#if defined( HAVE_KERBEROS ) || defined( HAVE_TLS ) || defined( HAVE_CYRUS_SASL )
 char *
 ldap_host_connected_to( Sockbuf *sb )
 {
diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c
new file mode 100644
index 0000000000000000000000000000000000000000..5d2a21f8f90a63ebcfb16769ff2123e96102ac52
--- /dev/null
+++ b/libraries/libldap/os-local.c
@@ -0,0 +1,219 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/*  Portions
+ *  Copyright (c) 1995 Regents of the University of Michigan.
+ *  All rights reserved.
+ *  Copyright (c) 1999 PADL Software Pty Ltd.
+ *  os-ip.c -- platform-specific domain socket code
+ */
+
+
+#include "portable.h"
+
+#ifdef LDAP_PF_LOCAL
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/errno.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+#include <ac/unistd.h>
+
+/* XXX non-portable */
+#include <sys/stat.h>
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif /* HAVE_IO_H */
+
+#include "ldap-int.h"
+
+/* int ldap_int_tblsize = 0; */
+
+#define oslocal_debug(ld,fmt,arg1,arg2,arg3) \
+do { \
+	ldap_log_printf(ld, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
+} while(0)
+
+static void
+ldap_pvt_set_errno(int err)
+{
+	errno = err;
+}
+
+static int
+ldap_pvt_ndelay_on(LDAP *ld, int fd)
+{
+	oslocal_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
+	return ber_pvt_socket_set_nonblock( fd, 1 );
+}
+   
+static int
+ldap_pvt_ndelay_off(LDAP *ld, int fd)
+{
+	oslocal_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
+	return ber_pvt_socket_set_nonblock( fd, 0 );
+}
+
+static ber_socket_t
+ldap_pvt_socket(LDAP *ld)
+{
+	ber_socket_t s = socket(AF_UNIX, SOCK_STREAM, 0);
+	oslocal_debug(ld, "ldap_new_socket: %d\n",s,0,0);
+	return ( s );
+}
+
+static int
+ldap_pvt_close_socket(LDAP *ld, int s)
+{
+	oslocal_debug(ld, "ldap_close_socket: %d\n",s,0,0);
+	return tcp_close(s);
+}
+
+#undef TRACE
+#define TRACE do { \
+	oslocal_debug(ld, \
+		"ldap_is_socket_ready: errror on socket %d: errno: %d (%s)\n", \
+		s, \
+		errno, \
+		strerror(errno) ); \
+} while( 0 )
+
+/*
+ * check the socket for errors after select returned.
+ */
+static int
+ldap_pvt_is_socket_ready(LDAP *ld, int s)
+{
+	oslocal_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
+
+#if defined( notyet ) /* && defined( SO_ERROR ) */
+{
+	int so_errno;
+	int dummy = sizeof(so_errno);
+	if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == -1 ) {
+		return -1;
+	}
+	if ( so_errno ) {
+		ldap_pvt_set_errno(so_errno);
+		TRACE;
+		return -1;
+	}
+	return 0;
+}
+#else
+{
+	/* error slippery */
+	struct sockaddr_un sun;
+	char ch;
+	int dummy = sizeof(sun);
+	if ( getpeername( s, (struct sockaddr *) &sun, &dummy ) == -1 ) {
+		/* XXX: needs to be replace with ber_stream_read() */
+		read(s, &ch, 1);
+		TRACE;
+		return -1;
+	}
+	return 0;
+}
+#endif
+	return -1;
+}
+#undef TRACE
+
+static int
+ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sun, int async)
+{
+	struct timeval	tv, *opt_tv=NULL;
+	fd_set		wfds, *z=NULL;
+
+	if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) {
+		tv.tv_usec = opt_tv->tv_usec;
+		tv.tv_sec = opt_tv->tv_sec;
+	}
+
+	oslocal_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n",
+			s, opt_tv ? tv.tv_sec : -1L, async);
+
+	if ( ldap_pvt_ndelay_on(ld, s) == -1 )
+		return ( -1 );
+
+	if ( connect(s, (struct sockaddr *) sun, sizeof(struct sockaddr_un)) == 0 )
+	{
+		if ( ldap_pvt_ndelay_off(ld, s) == -1 )
+			return ( -1 );
+		return ( 0 );
+	}
+
+	if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
+		return ( -1 );
+	}
+	
+#ifdef notyet
+	if ( async ) return ( -2 );
+#endif
+
+	FD_ZERO(&wfds);
+	FD_SET(s, &wfds );
+
+	if ( select(ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL) == -1)
+		return ( -1 );
+
+	if ( FD_ISSET(s, &wfds) ) {
+		if ( ldap_pvt_is_socket_ready(ld, s) == -1 )
+			return ( -1 );
+		if ( ldap_pvt_ndelay_off(ld, s) == -1 )
+			return ( -1 );
+		return ( 0 );
+	}
+	oslocal_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0);
+	ldap_pvt_set_errno( ETIMEDOUT );
+	return ( -1 );
+}
+
+int
+ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async)
+{
+	struct sockaddr_un	server;
+	ber_socket_t		s = AC_SOCKET_INVALID;
+	int			rc, i, len;
+	char   			*ha_buf=NULL, *p, *q;
+
+	oslocal_debug(ld, "ldap_connect_to_path\n",0,0,0);
+
+	if ( (s = ldap_pvt_socket( ld )) == -1 ) {
+		return -1;
+	}
+
+	if ( path == NULL || path[0] == '\0' ) {
+		path = "/tmp/.ldap-sock";
+	} else {
+		if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) {
+			ldap_pvt_set_errno( ENAMETOOLONG );
+			return -1;
+		}
+	}
+
+	oslocal_debug(ld, "ldap_connect_to_path: Trying %s\n", path, 0, 0);
+
+	memset( &server, 0, sizeof(server) );
+	server.sun_family = AF_UNIX;
+	strcpy( server.sun_path, path );
+
+	rc = ldap_pvt_connect(ld, s, &server, async);
+
+	if (rc == 0) {
+		ber_pvt_sb_set_desc( sb, s );
+	} else {
+		ldap_pvt_close_socket(ld, s);
+	}
+	return rc;
+}
+#else
+static int dummy;
+#endif /* LDAP_PF_LOCAL */
diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c
index badd2468a6a5333705a99ec2631fa716b3c58187..30c8887beb7c9e2c08b7c011e11c6de0c6af610a 100644
--- a/libraries/libldap/request.c
+++ b/libraries/libldap/request.c
@@ -96,7 +96,6 @@ ldap_send_initial_request(
 			( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
 	}
 
-
 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_DNS
 	if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_DNS )
 		&& ldap_is_dns_dn( dn ) )
@@ -254,7 +253,6 @@ ldap_send_server_request(
 	return( msgid );
 }
 
-
 LDAPConn *
 ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb,
 	int connect, int bind )
diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c
index 28e36768b39b3db712ae912332def7a931ae3a57..a5cfa17675ea81ffbd032230bc85a8c9a1307006 100644
--- a/libraries/libldap/sasl.c
+++ b/libraries/libldap/sasl.c
@@ -148,16 +148,6 @@ ldap_sasl_bind(
 	return LDAP_SUCCESS;
 }
 
-/*
- * ldap_sasl_bind_s - bind to the ldap server (and X.500) using simple
- * authentication.  The dn and password of the entry to which to bind are
- * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
- * otherwise.
- *
- * Example:
- *	ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us",
- *	    "mechanism", "secret", NULL, NULL, &servercred )
- */
 
 int
 ldap_sasl_bind_s(
@@ -221,18 +211,18 @@ ldap_sasl_bind_s(
 
 
 /*
- * Parse BindResponse:
- *
- *   BindResponse ::= [APPLICATION 1] SEQUENCE {
- *     COMPONENTS OF LDAPResult,
- *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
- *
- *   LDAPResult ::= SEQUENCE {
- *     resultCode      ENUMERATED,
- *     matchedDN       LDAPDN,
- *     errorMessage    LDAPString,
- *     referral        [3] Referral OPTIONAL }
- */
+* Parse BindResponse:
+*
+*   BindResponse ::= [APPLICATION 1] SEQUENCE {
+*     COMPONENTS OF LDAPResult,
+*     serverSaslCreds  [7] OCTET STRING OPTIONAL }
+*
+*   LDAPResult ::= SEQUENCE {
+*     resultCode      ENUMERATED,
+*     matchedDN       LDAPDN,
+*     errorMessage    LDAPString,
+*     referral        [3] Referral OPTIONAL }
+*/
 
 int
 ldap_parse_sasl_bind_result(
@@ -350,3 +340,486 @@ ldap_parse_sasl_bind_result(
 
 	return( ld->ld_errno );
 }
+
+#ifdef HAVE_CYRUS_SASL
+/*
+* Various Cyrus SASL related stuff.
+*/
+
+static int sasl_setup( Sockbuf *sb, void *arg );
+static int sasl_remove( Sockbuf *sb );
+static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
+static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
+static int sasl_close( Sockbuf *sb );
+
+static Sockbuf_IO sasl_io=
+{
+sasl_setup,
+sasl_remove,
+sasl_read,
+sasl_write,
+sasl_close
+}; 
+
+#define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
+
+static char *
+array2str( char **a )
+{
+	char *s, **v, *p;
+	int len = 0;
+
+	for ( v = a; *v != NULL; v++ ) {
+		len += strlen( *v ) + 1; /* for a space */
+	}
+
+	if ( len == 0 ) {
+		return NULL;
+	}
+
+	s = LDAP_MALLOC ( len ); /* last space holds \0 */
+
+	if ( s == NULL ) {
+		return NULL;	
+	}
+
+	p = s;
+	for ( v = a; *v != NULL; v++ ) {
+		int len;
+
+		if ( v != a ) {
+			strncpy( p, " ", 1 );
+			++p;
+		}
+		len = strlen( *v );
+		strncpy( p, *v, len );
+		p += len;
+	}
+
+	*p = '\0';
+
+	return s;
+}
+
+int ldap_pvt_sasl_init( void )
+{
+	/* XXX not threadsafe */
+	static int sasl_initialized = 0;
+
+	if ( sasl_initialized ) {
+		return -1;
+	}
+#ifndef CSRIMALLOC
+	sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
+#endif /* CSRIMALLOC */
+
+	if ( sasl_client_init( NULL ) == SASL_OK ) {
+		sasl_initialized = 1;
+		return 0;
+	}
+
+	return -1;
+}
+
+int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
+{
+	/* don't install the stuff unless security has been negotiated */
+
+	if ( !HAS_SASL( sb ) ) {
+		ber_pvt_sb_clear_io( sb );
+		ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
+	}
+
+	return 0;
+}
+
+static int sasl_setup( Sockbuf *sb, void *arg )
+{
+	sb->sb_iodata = arg;
+	return 0;
+}
+
+static int sasl_remove( Sockbuf *sb )
+{
+	return 0;
+}
+
+static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
+{
+	char *recv_tok;
+	unsigned recv_tok_len;
+	sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
+
+	if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
+		return -1;
+	}
+
+	if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
+		return -1;
+	}
+
+	if ( recv_tok_len > buflen ) {
+		LDAP_FREE( recv_tok );
+		return -1;
+	}
+
+	memcpy( buf, recv_tok, recv_tok_len );	
+
+	LDAP_FREE( recv_tok );
+
+	return recv_tok_len;
+}
+
+static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
+{
+	char *wrapped_tok;
+	unsigned wrapped_tok_len;
+	sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
+
+	if ( sasl_encode( conn, (const char *)buf, len,
+		&wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
+		return -1;
+	}
+
+	if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
+		LDAP_FREE( wrapped_tok );
+		return -1;
+	}
+
+	LDAP_FREE( wrapped_tok );
+
+	return len;
+}
+
+static int sasl_close( Sockbuf *sb )
+{
+	(ber_pvt_sb_io_tcp.sbi_close)( sb );
+}
+
+int
+ldap_pvt_sasl_err2ldap( int saslerr )
+{
+	int rc;
+
+	switch (saslerr) {
+		case SASL_CONTINUE:
+			rc = LDAP_SASL_BIND_IN_PROGRESS;
+			break;
+		case SASL_OK:
+			rc = LDAP_SUCCESS;
+			break;
+		case SASL_FAIL:
+			rc = LDAP_OPERATIONS_ERROR;
+			break;
+		case SASL_NOMEM:
+			rc = LDAP_NO_MEMORY;
+			break;
+		case SASL_NOMECH:
+			rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+			break;
+		case SASL_BADAUTH:
+			rc = LDAP_INVALID_CREDENTIALS;
+			break;
+		case SASL_NOAUTHZ:
+			rc = LDAP_INSUFFICIENT_ACCESS;
+			break;
+		case SASL_TOOWEAK:
+		case SASL_ENCRYPT:
+			rc = LDAP_INAPPROPRIATE_AUTH;
+			break;
+		default:
+			rc = LDAP_OPERATIONS_ERROR;
+			break;
+	}
+
+	return rc;
+}
+
+int
+ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
+{
+	/* we need to query the server for supported mechs anyway */
+	LDAPMessage *res, *e;
+	char *attrs[] = { "supportedSASLMechanisms", NULL };
+	char **values, *mechlist, **p;
+	int rc;
+
+	rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
+		"(objectclass=*)", attrs, 0, &res );
+
+	if ( rc != LDAP_SUCCESS ) {
+		return ld->ld_errno;
+	}
+		
+	e = ldap_first_entry( ld, res );
+	if ( e == NULL ) {
+		if ( ld->ld_errno == LDAP_SUCCESS ) {
+			ld->ld_errno = LDAP_UNAVAILABLE;
+		}
+		return ld->ld_errno;
+	}
+
+	values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
+	if ( values == NULL ) {
+		ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
+		ldap_msgfree( res );
+		return ld->ld_errno;
+	}
+
+	if ( desired != NULL ) {
+		rc = LDAP_INAPPROPRIATE_AUTH;
+
+		for ( p = values; *p != NULL; p++ ) {
+			if ( !strcmp( *p, desired ) == 0 ) {
+				rc = LDAP_SUCCESS;
+				break;
+			}
+		}
+
+		if ( rc == LDAP_SUCCESS ) {
+			/* just return this */
+			*pmechlist = LDAP_STRDUP( desired );
+			return LDAP_SUCCESS;
+		} else {
+			/* couldn't find it */
+			ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
+			return ld->ld_errno;
+		}
+	}
+
+	mechlist = array2str( values );
+	if ( mechlist == NULL ) {
+		ld->ld_errno = LDAP_NO_MEMORY;
+		ldap_value_free( values );
+		ldap_msgfree( res );
+		return ld->ld_errno;
+	} 
+
+	ldap_value_free( values );
+	ldap_msgfree( res );
+
+	*pmechlist = mechlist;
+
+	return LDAP_SUCCESS;
+}
+
+int
+ldap_pvt_sasl_bind(
+	LDAP			*ld,
+	LDAP_CONST char		*dn,
+	LDAP_CONST char		*mechanism,
+	const sasl_callback_t	*callbacks,
+	LDAPControl		**sctrls,
+	LDAPControl		**cctrls )
+{
+	int	saslrc, rc, msgid, ssf = 0;
+	struct berval ccred, *scred;
+	char *mechlist = NULL;
+	char *host;
+	sasl_interact_t *client_interact = NULL;
+
+	Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
+
+	/* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
+	if (ld->ld_version < LDAP_VERSION3) {
+		ld->ld_errno = LDAP_NOT_SUPPORTED;
+		return ld->ld_errno;
+	}
+
+	/*
+	 * This connects to the host, side effect being that
+	 * ldap_host_connected_to() works.
+	 */
+	rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
+	if ( rc != LDAP_SUCCESS ) {
+		return ld->ld_errno;
+	}
+
+	/* XXX this doesn't work with PF_LOCAL hosts */
+	host = ldap_host_connected_to( &ld->ld_sb );
+
+	if ( host == NULL ) {
+		LDAP_FREE( mechlist );
+		ld->ld_errno = LDAP_UNAVAILABLE;
+		return ld->ld_errno;
+	}
+
+	if ( ld->ld_sasl_context != NULL ) {
+		LDAP_FREE( mechlist );
+		sasl_dispose( &ld->ld_sasl_context );
+	}
+
+	saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
+
+	LDAP_FREE( host );
+
+	if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+		LDAP_FREE( mechlist );
+		ld->ld_errno = ldap_pvt_sasl_err2ldap( rc );
+		sasl_dispose( &ld->ld_sasl_context );
+		return ld->ld_errno;
+	}
+
+	ccred.bv_val = NULL;
+	ccred.bv_len = 0;
+
+	saslrc = sasl_client_start( ld->ld_sasl_context,
+		mechlist,
+		NULL,
+		&client_interact,
+		&ccred.bv_val,
+		(unsigned int *)&ccred.bv_len,
+		&mechanism );
+
+	LDAP_FREE( mechlist );
+
+	if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+		ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
+		sasl_dispose( &ld->ld_sasl_context );
+		return ld->ld_errno;
+	}
+
+	scred = NULL;
+
+	do {
+		sasl_interact_t *client_interact = NULL;
+
+		rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
+		if ( rc == LDAP_SUCCESS ) {
+			break;
+		} else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
+			if ( ccred.bv_val != NULL ) {
+				LDAP_FREE( ccred.bv_val );
+			}
+			sasl_dispose( &ld->ld_sasl_context );
+			return ld->ld_errno;
+		}
+
+		if ( ccred.bv_val != NULL ) {
+			LDAP_FREE( ccred.bv_val );
+			ccred.bv_val = NULL;
+		}
+
+		saslrc = sasl_client_step( ld->ld_sasl_context,
+			(scred == NULL) ? NULL : scred->bv_val,
+			(scred == NULL) ? 0 : scred->bv_len,
+			&client_interact,
+			&ccred.bv_val,
+			(unsigned int *)&ccred.bv_len );
+
+		ber_bvfree( scred );
+
+		if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
+			ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
+			sasl_dispose( &ld->ld_sasl_context );
+			return ld->ld_errno;
+		}
+	} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
+
+	assert ( rc == LDAP_SUCCESS );
+
+	if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
+		== SASL_OK && ssf ) {
+		ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
+	}
+
+	return rc;
+}
+
+/* based on sample/sample-client.c */
+static int
+ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
+{
+	struct berval *passphrase = (struct berval *)context;
+	size_t len;           
+
+	if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
+		return SASL_BADPARAM;
+	}
+
+	len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
+
+	*psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
+	if ( *psecret == NULL ) {
+		return SASL_NOMEM;
+	}
+
+	(*psecret)->len = passphrase->bv_len;
+
+	if ( passphrase != NULL ) {
+		memcpy((*psecret)->data, passphrase->bv_val, len);
+	}
+
+	return SASL_OK;
+}
+
+static int
+ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
+{
+	const char *value = (const char *)context;
+
+	if ( result == NULL ) {
+		return SASL_BADPARAM;
+	}
+
+	switch ( id ) {
+		case SASL_CB_USER:
+		case SASL_CB_AUTHNAME:
+			*result = value;
+			if ( len )
+				*len = value ? strlen( value ) : 0;
+			break;
+		case SASL_CB_LANGUAGE:
+			*result = NULL;
+			if ( len )
+				*len = 0;
+			break;
+		default:
+			return SASL_BADPARAM;
+	}
+
+	return SASL_OK;
+}
+
+/*
+ * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500) using SASL
+ * authentication.  The dn and password of the entry to which to bind are
+ * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ *
+ * Example:
+ *	ldap_negotiated_sasl_bind_s( ld, NULL,
+ *	    "dn:cn=manager", NULL, "GSSAPI", NULL, NULL, NULL );
+ */
+int
+ldap_negotiated_sasl_bind_s(
+        LDAP *ld,
+	LDAP_CONST char *dn, /* usually NULL */
+        LDAP_CONST char *authorizationId,
+        LDAP_CONST char *authenticationId,  
+        LDAP_CONST char *saslMechanism,     
+        struct berval *passPhrase,        
+        LDAPControl **serverControls,
+        LDAPControl **clientControls)
+{
+	sasl_callback_t callbacks[4];
+	int rc;
+
+	callbacks[0].id = SASL_CB_USER;
+	callbacks[0].proc = ldap_pvt_sasl_getsimple;
+	callbacks[0].context = (void *)authorizationId;
+	callbacks[1].id = SASL_CB_AUTHNAME;
+	callbacks[1].proc = ldap_pvt_sasl_getsimple;
+	callbacks[1].context = (void *)authenticationId;
+	callbacks[2].id = SASL_CB_PASS;
+	callbacks[2].proc = ldap_pvt_sasl_getsecret;
+	callbacks[2].context = (void *)passPhrase;
+	callbacks[3].id = SASL_CB_LIST_END;
+	callbacks[3].proc = NULL;
+	callbacks[3].context = NULL;
+
+	rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks, serverControls, clientControls);
+
+	return rc;
+}
+#endif /* HAVE_CYRUS_SASL */
diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c
index 24c43b454caa95661c853fc8a7eb8bcdc1e44bc8..c4222fe4ab7e90978e3a44ee95c60fd9eff51688 100644
--- a/libraries/libldap/unbind.c
+++ b/libraries/libldap/unbind.c
@@ -139,6 +139,12 @@ ldap_ld_free(
 		ld->ld_options.ldo_tm_net = NULL;
 	}
 
+#ifdef HAVE_CYRUS_SASL
+	if ( ld->ld_sasl_context != NULL ) {
+		sasl_dispose( &ld->ld_sasl_context );
+	}
+#endif 
+
 	ber_pvt_sb_destroy( &(ld->ld_sb) );   
    
 	LDAP_FREE( (char *) ld );
diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c
index a4309bfcf621b67c39b50cf2b4e3651fc5ee2420..9d29cc41208d5a40b658f5fcd8b87918d2498db9 100644
--- a/libraries/libldap/url.c
+++ b/libraries/libldap/url.c
@@ -40,48 +40,51 @@
 static const char* skip_url_prefix LDAP_P((
 	const char *url,
 	int *enclosedp,
-	int *ldaps ));
+	unsigned long *properties,
+	int *protocol));
 
 
 int
 ldap_is_ldap_url( LDAP_CONST char *url )
 {
-	int	enclosed;
-	int ldaps;
+	int	enclosed, protocol;
+	unsigned long properties;
 
 	if( url == NULL ) {
 		return 0;
 	}
 
-	if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) {
+	if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) {
 		return 0;
 	}
 
-	return !ldaps;
+	return !(properties & LDAP_URL_USE_SSL);
 }
 
 int
 ldap_is_ldaps_url( LDAP_CONST char *url )
 {
-	int	enclosed;
-	int ldaps;
+	int	enclosed, protocol;
+	unsigned long properties;
 
 	if( url == NULL ) {
 		return 0;
 	}
 
-	if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) {
+	if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) {
 		return 0;
 	}
 
-	return ldaps;
+	return (properties & LDAP_URL_USE_SSL);
 }
 
 static const char*
 skip_url_prefix(
 	const char *url,
 	int *enclosedp,
-	int *ldaps )
+	unsigned long *properties,
+	int *protocol
+	)
 {
 /*
  * return non-zero if this looks like a LDAP URL; zero if not
@@ -109,11 +112,13 @@ skip_url_prefix(
 		p += LDAP_URL_URLCOLON_LEN;
 	}
 
+	*properties = 0;
+
 	/* check for "ldap://" prefix */
 	if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
 		/* skip over "ldap://" prefix and return success */
 		p += LDAP_URL_PREFIX_LEN;
-		*ldaps = 0;
+		*protocol = LDAP_PROTO_TCP;
 		return( p );
 	}
 
@@ -121,7 +126,25 @@ skip_url_prefix(
 	if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
 		/* skip over "ldaps://" prefix and return success */
 		p += LDAPS_URL_PREFIX_LEN;
-		*ldaps = 1;
+		*protocol = LDAP_PROTO_TCP;
+		*properties |= LDAP_URL_USE_SSL;
+		return( p );
+	}
+
+	/* check for "ldapi://" prefix */
+	if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
+		/* skip over "ldapi://" prefix and return success */
+		p += LDAPI_URL_PREFIX_LEN;
+		*protocol = LDAP_PROTO_LOCAL;
+		return( p );
+	}
+
+	/* check for "ldapis://" prefix: should this be legal? */
+	if ( strncasecmp( p, LDAPIS_URL_PREFIX, LDAPIS_URL_PREFIX_LEN ) == 0 ) {
+		/* skip over "ldapis://" prefix and return success */
+		p += LDAPIS_URL_PREFIX_LEN;
+		*protocol = LDAP_PROTO_LOCAL;
+		*properties |= LDAP_URL_USE_SSL;
 		return( p );
 	}
 
@@ -160,7 +183,8 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
 
 	LDAPURLDesc	*ludp;
 	char	*p, *q;
-	int		i, enclosed, ldaps;
+	int		i, enclosed, protocol;
+	unsigned long properties;
 	const char *url_tmp;
 	char *url;
 
@@ -172,7 +196,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
 
 	*ludpp = NULL;	/* pessimistic */
 
-	url_tmp = skip_url_prefix( url_in, &enclosed, &ldaps );
+	url_tmp = skip_url_prefix( url_in, &enclosed, &properties, &protocol );
 
 	if ( url_tmp == NULL ) {
 		return LDAP_URL_ERR_NOTLDAP;
@@ -205,10 +229,11 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
 	ludp->lud_next = NULL;
 	ludp->lud_host = NULL;
 	ludp->lud_port = 0;
-    ludp->lud_dn = NULL;
-    ludp->lud_attrs = NULL;
-    ludp->lud_filter = NULL;
-	ludp->lud_ldaps = ldaps;
+	ludp->lud_dn = NULL;
+	ludp->lud_attrs = NULL;
+	ludp->lud_filter = NULL;
+	ludp->lud_properties = properties;
+	ludp->lud_protocol = protocol;
 	ludp->lud_scope = LDAP_SCOPE_BASE;
 
 	ludp->lud_filter = LDAP_STRDUP("(objectClass=*)");
@@ -468,7 +493,6 @@ ldap_url_dup ( LDAPURLDesc *ludp )
 		}
 	}
 
-	dest->lud_ldaps = ludp->lud_ldaps;
 	dest->lud_port = ludp->lud_port;
 	dest->lud_scope = ludp->lud_scope;
 
@@ -567,7 +591,8 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts )
 			ludp->lud_port = atoi(p);
 		}
 		ldap_pvt_hex_unescape(ludp->lud_host);
-		ludp->lud_ldaps = -1;	/* unknown (use TLS default) */
+		ludp->lud_protocol = LDAP_PROTO_TCP;
+		ludp->lud_properties = LDAP_URL_USE_SSL_UNSPECIFIED;
 		ludp->lud_next = *ludlist;
 		*ludlist = ludp;
 	}
@@ -635,7 +660,7 @@ ldap_url_list2urls (LDAPURLDesc *ludlist)
 
 	p = s;
 	for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
-		p += sprintf(p, "ldap%s://%s", (ludp->lud_ldaps == 1) ? "s" : "", ludp->lud_host);
+		p += sprintf(p, "ldap%s://%s", (ludp->lud_properties & LDAP_URL_USE_SSL) ? "s" : "", ludp->lud_host);
 		if (ludp->lud_port != 0)
 			p += sprintf(p, ":%d", ludp->lud_port);
 		*p++ = '/';
@@ -767,9 +792,9 @@ void
 ldap_pvt_hex_unescape( char *s )
 {
 /*
- * Remove URL hex escapes from s... done in place.  The basic concept for
- * this routine is borrowed from the WWW library HTUnEscape() routine.
- */
+* Remove URL hex escapes from s... done in place.  The basic concept for
+* this routine is borrowed from the WWW library HTUnEscape() routine.
+*/
 	char	*p;
 
 	for ( p = s; *s != '\0'; ++s ) {
diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in
index 7f66bac8d94665cc734c25b6060ae94d928fbbf2..3454faefeeb62d79060e02296136fdfdb2825b31 100644
--- a/libraries/libldap_r/Makefile.in
+++ b/libraries/libldap_r/Makefile.in
@@ -16,7 +16,7 @@ XXSRCS	= apitest.c test.c tmpltest.c extended.c \
 	getdn.c getentry.c getattr.c getvalues.c addentry.c \
 	request.c getdxbyname.c os-ip.c url.c charset.c \
 	init.c options.c print.c string.c util-int.c schema.c \
-	charray.c digest.c tls.c dn.c
+	charray.c digest.c tls.c dn.c os-local.c
 SRCS	= thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \
 	thr_pth.c thr_sleep.c thr_stub.c rdwr.c
 OBJS	= extended.lo \
@@ -29,7 +29,7 @@ OBJS	= extended.lo \
 	init.lo options.lo print.lo string.lo util-int.lo schema.lo \
 	thr_posix.lo thr_cthreads.lo thr_thr.lo thr_lwp.lo thr_nt.lo \
 	thr_pth.lo thr_sleep.lo thr_stub.lo rdwr.lo \
-	charray.lo digest.lo tls.lo dn.lo
+	charray.lo digest.lo tls.lo dn.lo os-local.lo
 
 LDAP_INCDIR= ../../include       
 LDAP_LIBDIR= ../../libraries
diff --git a/servers/slapd/back-ldbm/Makefile.in b/servers/slapd/back-ldbm/Makefile.in
index 15211cb0f77d4f962f91a7febe90c7b717a00c2d..ec0ecc97343d398cbdb86bc3927b80e7bb8cc529 100644
--- a/servers/slapd/back-ldbm/Makefile.in
+++ b/servers/slapd/back-ldbm/Makefile.in
@@ -4,12 +4,12 @@ SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c entry.c id2entry.c \
 		index.c id2children.c nextid.c abandon.c compare.c group.c \
 		modify.c modrdn.c delete.c init.c config.c bind.c attr.c \
 		filterindex.c unbind.c close.c alias.c tools.c \
-		extended.c passwd.c
+		extended.c passwd.c sasl.c
 OBJS = idl.lo add.lo search.lo cache.lo dbcache.lo dn2id.lo entry.lo id2entry.lo \
 		index.lo id2children.lo nextid.lo abandon.lo compare.lo group.lo \
 		modify.lo modrdn.lo delete.lo init.lo config.lo bind.lo attr.lo \
 		filterindex.lo unbind.lo close.lo alias.lo tools.lo \
-		extended.lo passwd.lo
+		extended.lo passwd.lo sasl.lo
 
 LDAP_INCDIR= ../../../include       
 LDAP_LIBDIR= ../../../libraries
diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c
index 3935179bc6c3874113bd367325cbd8fd9363880a..acec9dd5a18da7c8fab53403d76005f4869acecc 100644
--- a/servers/slapd/back-ldbm/bind.c
+++ b/servers/slapd/back-ldbm/bind.c
@@ -85,6 +85,10 @@ ldbm_back_bind(
 			}
 
 		} else if ( method == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+			rc = sasl_bind( be, conn, op, 
+				dn, ndn, mech, cred, edn );
+#else
 			if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) {
 				/* insert DIGEST calls here */
 				send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
@@ -94,7 +98,7 @@ ldbm_back_bind(
 				send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
 					NULL, NULL, NULL, NULL );
 			}
-
+#endif /* HAVE_CYRUS_SASL */
 		} else if ( refs != NULL ) {
 			send_ldap_result( conn, op, LDAP_REFERRAL,
 				matched_dn, NULL, refs, NULL );
@@ -241,7 +245,7 @@ ldbm_back_bind(
 
 		if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
 			/*
-			 * no krbName values present:  check against DN
+			 * no krbname values present:  check against DN
 			 */
 			if ( strcasecmp( dn, krbname ) == 0 ) {
 				rc = 0;
@@ -252,7 +256,7 @@ ldbm_back_bind(
 			rc = 1;
 			goto return_results;
 
-		} else {	/* look for krbName match */
+		} else {	/* look for krbname match */
 			struct berval	krbval;
 
 			krbval.bv_val = krbname;
@@ -279,7 +283,12 @@ ldbm_back_bind(
 
 	case LDAP_AUTH_SASL:
 		/* insert SASL code here */
-
+#ifdef HAVE_CYRUS_SASL
+		/* this may discard edn as we always prefer the SASL authzid
+		 * because it may be sealed.
+		 */
+		rc = sasl_bind( be, conn, op, dn, ndn, mech, cred, edn );
+#endif /* HAVE_CYRUS_SASL */
 	default:
 		send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
 		    NULL, "auth method not supported", NULL, NULL );
diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c
index 7d59f5dde0d271860d865e0aca71b2ca3eb84b07..c50800681f40c9599d2a412be64bd500238662fc 100644
--- a/servers/slapd/back-ldbm/init.c
+++ b/servers/slapd/back-ldbm/init.c
@@ -82,6 +82,12 @@ ldbm_back_initialize(
 	bi->bi_tool_index_change = ldbm_tool_index_change;
 	bi->bi_tool_sync = ldbm_tool_sync;
 
+#ifdef HAVE_CYRUS_SASL
+	bi->bi_sasl_authorize = 0; /* ldbm_sasl_authorize; */
+	bi->bi_sasl_getsecret = 0; /* ldbm_sasl_getsecret; */
+	bi->bi_sasl_putsecret = 0; /* ldbm_sasl_putsecret; */
+#endif
+
 	bi->bi_connection_init = 0;
 	bi->bi_connection_destroy = 0;
 
diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h
index c9ebbae66edb5932effe3f4f6cd329ff0672e3c6..85bfff8dfe0b3b589ddfc01246283289c22e2d0f 100644
--- a/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -178,6 +178,30 @@ int ldbm_modify_internal LDAP_P((Backend *be,
 	Connection *conn, Operation *op,
 	char *dn, LDAPModList *mods, Entry *e ));
 
+#ifdef HAVE_CYRUS_SASL
+/*
+ * sasl.c
+ */
+int ldbm_sasl_authorize LDAP_P((
+        BackendDB *be,
+        const char *auth_identity,
+        const char *requested_user,
+        const char **user,
+        const char **errstring ));
+int ldbm_sasl_getsecret LDAP_P((
+        Backend *be,
+        const char *mechanism,
+        const char *auth_identity,
+        const char *realm,
+        sasl_secret_t **secret ));
+int ldbm_sasl_putsecret LDAP_P((
+        Backend *be,
+        const char *mechanism,
+        const char *auth_identity,
+        const char *realm,
+        const sasl_secret_t *secret ));
+#endif /* HAVE_CYRUS_SASL */
+
 /*
  * nextid.c
  */
diff --git a/servers/slapd/back-ldbm/sasl.c b/servers/slapd/back-ldbm/sasl.c
new file mode 100644
index 0000000000000000000000000000000000000000..a1dc6f6b1b95a42ec7a35c4da8d0ab53d96cfbfc
--- /dev/null
+++ b/servers/slapd/back-ldbm/sasl.c
@@ -0,0 +1,59 @@
+/* bind.c - ldbm backend bind and unbind routines */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#ifdef HAVE_CYRUS_SASL
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/krb.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include "slap.h"
+#include "back-ldbm.h"
+#include "proto-back-ldbm.h"
+
+int
+back_ldbm_sasl_authorize(
+	BackendDB *be,
+	const char *auth_identity,
+	const char *requested_user,
+	const char **user,
+	const char **errstring)
+{
+	return SASL_FAIL;
+}
+
+int
+back_ldbm_sasl_getsecret(
+	Backend *be,
+	const char *mechanism,
+	const char *auth_identity,
+	const char *realm,
+	sasl_secret_t **secret)
+{
+	return SASL_FAIL;
+}
+
+int
+back_ldbm_sasl_putsecret(
+	Backend *be,
+	const char *mechanism,
+	const char *auth_identity,
+	const char *realm,
+	const sasl_secret_t *secret)
+{
+	return SASL_FAIL;
+}
+
+#else
+static int dummy = 1;
+#endif
+
diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c
index 9be3d11c8a2135472f92dc119a945642b0b1755e..881c2c773306b186b1e47ed614a7885056d0ad26 100644
--- a/servers/slapd/bind.c
+++ b/servers/slapd/bind.c
@@ -226,7 +226,6 @@ do_bind(
 			assert( conn->c_authstate == NULL );
 #endif
 		}
-
 	} else {
 		ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
@@ -305,6 +304,10 @@ do_bind(
 			method, mech, &cred, &edn );
 
 		if ( ret == 0 ) {
+#ifdef HAVE_CYRUS_SASL
+			int ssf = 0;
+#endif
+
 			ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
 			conn->c_cdn = dn;
@@ -326,6 +329,14 @@ do_bind(
 			send_ldap_result( conn, op, LDAP_SUCCESS,
 				NULL, NULL, NULL, NULL );
 
+#ifdef HAVE_CYRUS_SASL
+			if ( conn->c_sasl_context != NULL && 
+				sasl_getprop( conn->c_sasl_context, SASL_SSF, (void **)&ssf )
+					== SASL_OK && ssf ) {
+				/* Enable encode/decode */
+				ldap_pvt_sasl_install( conn->c_sb, conn->c_sasl_context );
+			}
+#endif
 		} else if (edn != NULL) {
 			free( edn );
 		}
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
index 3f116b6eccd1a2d1c58d4fe5a251467584b488d2..6f4ebf0a63c6761da07e62d0ae2ccc08a02b9b38 100644
--- a/servers/slapd/connection.c
+++ b/servers/slapd/connection.c
@@ -368,7 +368,7 @@ long connection_init(
 
 #ifdef HAVE_CYRUS_SASL
 		c->c_sasl_context = NULL;
-#endif
+#endif /* HAVE_CYRUS_SASL */
 
         c->c_sb = ber_sockbuf_alloc( );
 		c->c_currentber = NULL;
@@ -485,6 +485,19 @@ connection_destroy( Connection *c )
 		c->c_peer_domain = NULL;
 	}
 	if(c->c_peer_name != NULL) {
+#ifdef LDAP_PF_LOCAL
+		/*
+		 * If peer was a domain socket, unlink. Mind you,
+		 * they may be un-named. Should we leave this to
+		 * the client?
+		 */
+		if (strncmp(c->c_peer_name, "PATH=", 5) == 0) {
+			char *path = c->c_peer_name + 5;
+			if (path != '\0') {
+				(void)unlink(path);
+			}
+		}
+#endif /* LDAP_PF_LOCAL */
 		free(c->c_peer_name);
 		c->c_peer_name = NULL;
 	}
@@ -506,7 +519,9 @@ connection_destroy( Connection *c )
 		sasl_dispose( &c->c_sasl_context );
 		c->c_sasl_context = NULL;
 	}
-#endif
+#endif /* HAVE_CYRUS_SASL */
+
+	c->c_bind_in_progress = 0;
 
 	if ( c->c_currentber != NULL ) {
 		ber_free( c->c_currentber, 1 );
@@ -795,7 +810,13 @@ connection_operation( void *arg_v )
 		if( conn->c_conn_state == SLAP_C_BINDING) {
 			conn->c_conn_state = SLAP_C_ACTIVE;
 		}
-		conn->c_bind_in_progress = ( rc == LDAP_SASL_BIND_IN_PROGRESS );
+		/*
+		 * Is this ever the case? For now, rely on
+		 * the backend to set this.
+		 */
+		if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) {
+			conn->c_bind_in_progress = 1;
+		}
 	}
 
 	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c
index 56c0afe37eb9753bbb6f1e36f94e57c842f0928c..9a55fc277b638713b1f19a7cc37c2c6f57cd37e2 100644
--- a/servers/slapd/daemon.c
+++ b/servers/slapd/daemon.c
@@ -27,10 +27,22 @@ int allow_severity = LOG_INFO;
 int deny_severity = LOG_NOTICE;
 #endif /* TCP Wrappers */
 
+#ifdef LDAP_PF_LOCAL
+#include <sys/stat.h>
+#endif /* LDAP_PF_LOCAL */
+
 /* globals */
 time_t starttime;
 ber_socket_t dtblsize;
 
+#ifdef LDAP_PF_LOCAL
+typedef union slap_sockaddr {
+	struct sockaddr sa_addr;
+	struct sockaddr_in sa_in_addr;
+	struct sockaddr_un sa_un_addr;
+} Sockaddr;
+#endif /* LDAP_PF_LOCAL */
+
 typedef struct slap_listener {
 	char* sl_url;
 	char* sl_name;
@@ -38,7 +50,12 @@ typedef struct slap_listener {
 	int		sl_is_tls;
 #endif
 	ber_socket_t		sl_sd;
+#ifdef LDAP_PF_LOCAL
+	Sockaddr sl_sa;
+#define sl_addr	sl_sa.sa_in_addr
+#else	
 	struct sockaddr_in	sl_addr;
+#endif /* LDAP_PF_LOCAL */
 } Listener;
 
 Listener **slap_listeners = NULL;
@@ -196,7 +213,7 @@ static Listener * open_listener( const char* url )
 	}
 
 #ifndef HAVE_TLS
-	if( lud->lud_ldaps ) {
+	if( lud->lud_properties & LDAP_URL_USE_SSL ) {
 		Debug( LDAP_DEBUG_ANY,
 			"daemon: TLS not supported (%s)\n",
 			url, 0, 0 );
@@ -209,13 +226,42 @@ static Listener * open_listener( const char* url )
 	}
 
 #else
-	l.sl_is_tls = lud->lud_ldaps;
+	l.sl_is_tls = (lud->lud_properties & LDAP_URL_USE_SSL);
 
 	if(! lud->lud_port ) {
-		lud->lud_port = lud->lud_ldaps ? LDAPS_PORT : LDAP_PORT;
+		lud->lud_port = (lud->lud_properties & LDAP_URL_USE_SSL) ? LDAPS_PORT : LDAP_PORT;
 	}
 #endif
 
+#ifdef LDAP_PF_LOCAL
+	if (lud->lud_protocol == LDAP_PROTO_LOCAL) {
+		port = 0;
+		(void) memset( (void *)&l.sl_sa.sa_un_addr, '\0', sizeof(l.sl_sa.sa_un_addr) );
+
+		l.sl_sa.sa_un_addr.sun_family = AF_UNIX;
+
+		/* hack: overload the host to be the path */
+		if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
+			strcpy( l.sl_sa.sa_un_addr.sun_path, "/tmp/.ldap-sock" );
+		} else {
+			if ( strlen(lud->lud_host) > (sizeof(l.sl_sa.sa_un_addr.sun_path) - 1) ) {
+				Debug( LDAP_DEBUG_ANY, "domain socket path (%s) too long in URL: %s",
+					lud->lud_host, url, 0);
+				ldap_free_urldesc( lud );
+				return NULL;
+			}
+			strcpy( l.sl_sa.sa_un_addr.sun_path, lud->lud_host );
+		}
+		unlink( l.sl_sa.sa_un_addr.sun_path ); 
+#if 0
+		/* I don't think we need to set this. */
+		l.sl_sa.sa_un_addr.sun_len = sizeof( l.sl_sa.sa_un_addr.sun_len ) +
+			sizeof( l.sl_sa.sa_un_addr.sun_family ) +
+			strlen( l.sl_sa.sa_un_addr.sun_path ) + 1;
+#endif
+	} else {
+#endif /* LDAP_PF_LOCAL */
+
 	port = lud->lud_port;
 
 	(void) memset( (void*) &l.sl_addr, '\0', sizeof(l.sl_addr) );
@@ -243,11 +289,18 @@ static Listener * open_listener( const char* url )
 			       sizeof( l.sl_addr.sin_addr ) );
 		}
 	}
+#ifdef LDAP_PF_LOCAL
+	}
+#endif /* LDAP_PF_LOCAL */
 
 	ldap_free_urldesc( lud );
 
-
+#ifdef LDAP_PF_LOCAL
+	l.sl_sd = socket( l.sl_sa.sa_addr.sa_family, SOCK_STREAM, 0 );
+	if ( l.sl_sd == AC_SOCKET_INVALID ) {
+#else
 	if ( (l.sl_sd = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) {
+#endif /* LDAP_PF_LOCAL */
 		int err = sock_errno();
 		Debug( LDAP_DEBUG_ANY,
 			"daemon: socket() failed errno=%d (%s)\n", err,
@@ -265,6 +318,11 @@ static Listener * open_listener( const char* url )
 	}
 #endif
 
+#ifdef LDAP_PF_LOCAL
+	/* for IP sockets only */
+	if ( l.sl_sa.sa_addr.sa_family == AF_INET ) {
+#endif /* LDAP_PF_LOCAL */
+
 #ifdef SO_REUSEADDR
 	/* enable address reuse */
 	tmp = 1;
@@ -302,7 +360,27 @@ static Listener * open_listener( const char* url )
 	}
 #endif
 
+#ifdef LDAP_PF_LOCAL
+	/* close conditional */
+	}
+
+	switch ( l.sl_sa.sa_addr.sa_family ) {
+		case AF_UNIX:
+			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
+				sizeof(l.sl_sa.sa_un_addr) );
+			break;
+		case AF_INET:
+			rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa,
+				sizeof(l.sl_sa.sa_in_addr) );
+			break;
+		default:
+			rc = AC_SOCKET_ERROR;
+			errno = EINVAL;
+			break;
+	}
+#else
 	rc = bind( l.sl_sd, (struct sockaddr *) &l.sl_addr, sizeof(l.sl_addr) );
+#endif /* LDAP_PF_LOCAL */
 	if ( rc == AC_SOCKET_ERROR ) {
 		int err = sock_errno();
 		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
@@ -310,13 +388,40 @@ static Listener * open_listener( const char* url )
 		tcp_close( l.sl_sd );
 		return NULL;
 	}
-
+#ifdef LDAP_PF_LOCAL
+	if ( l.sl_sa.sa_addr.sa_family == AF_UNIX ) {
+		if ( chmod( l.sl_sa.sa_un_addr.sun_path, S_IRWXU ) < 0 ) {
+			int err = sock_errno();
+			Debug( LDAP_DEBUG_ANY, "daemon: fchmod(%ld) failed errno=%d (%s)",
+				(long) l.sl_sd, err, sock_errstr(err) );
+			tcp_close( l.sl_sd );
+			return NULL;
+		}
+	}
+#endif /* LDAP_PF_LOACL */
 	l.sl_url = ch_strdup( url );
-
+#ifdef LDAP_PF_LOCAL
+	switch ( l.sl_sa.sa_addr.sa_family ) {
+		case AF_UNIX:
+			l.sl_name = ch_malloc( strlen(l.sl_sa.sa_un_addr.sun_path) + sizeof("PATH=") );
+			sprintf( l.sl_name, "PATH=%s", l.sl_sa.sa_un_addr.sun_path );
+			break;
+		case AF_INET:
+			l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") );
+			s = inet_ntoa( l.sl_addr.sin_addr );
+			sprintf( l.sl_name, "IP=%s:%d",
+				s != NULL ? s : "unknown" , port );
+			break;
+		default:
+			l.sl_name = ch_strdup( "UNKNOWN" );
+			break;
+	}
+#else
 	l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") );
 	s = inet_ntoa( l.sl_addr.sin_addr );
 	sprintf( l.sl_name, "IP=%s:%d",
 		s != NULL ? s : "unknown" , port );
+#endif /* LDAP_PF_LOCAL */
 
 	li = ch_malloc( sizeof( Listener ) );
 	*li = l;
@@ -476,8 +581,14 @@ slapd_daemon_task(
 
 		fd_set			readfds;
 		fd_set			writefds;
-
+#ifdef LDAP_PF_LOCAL
+		Sockaddr		from;
+/* minimize impact, undefine later. */
+#define	sin_addr sa_in_addr.sin_addr
+#define	sin_port sa_in_addr.sin_port
+#else
 		struct sockaddr_in	from;
+#endif /* LDAP_PF_LOCAL */
 #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
         struct hostent		*hp;
 #endif
@@ -611,9 +722,11 @@ slapd_daemon_task(
 
 			char	*dnsname;
 			char	*peeraddr;
-
+#ifdef LDAP_PF_LOCAL
+			char	peername[MAXPATHLEN + sizeof("PATH=")];
+#else
 			char	peername[sizeof("IP=255.255.255.255:65336")];
-
+#endif /* LDAP_PF_LOCAL */
 			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
 				continue;
 
@@ -668,6 +781,13 @@ slapd_daemon_task(
 				continue;
 			}
 
+#ifdef LDAP_PF_LOCAL
+			switch ( from.sa_addr.sa_family ) {
+			case AF_UNIX:
+				sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
+				break;
+			case AF_INET:
+#endif /* LDAP_PF_LOCAL */
 			peeraddr = inet_ntoa( from.sin_addr );
 			sprintf( peername, "IP=%s:%d",
 				peeraddr != NULL ? peeraddr : "unknown",
@@ -706,6 +826,15 @@ slapd_daemon_task(
 				continue;
 			}
 #endif /* HAVE_TCPD */
+#ifdef LDAP_PF_LOCAL
+				break;
+			default:
+				slapd_close(s);
+				continue;
+			}
+#undef	sin_addr
+#undef	sin_port
+#endif /* LDAP_PF_LOCAL */
 
 			if( (id = connection_init(s,
 				slap_listeners[l]->sl_url,
@@ -881,6 +1010,11 @@ slapd_daemon_task(
 
 	for ( l = 0; slap_listeners[l] != NULL; l++ ) {
 		if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) {
+#ifdef LDAP_PF_LOCAL
+			if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_UNIX ) {
+				unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path );
+			}
+#endif /* LDAP_PF_LOCAL */
 			slapd_close( slap_listeners[l]->sl_sd );
 			break;
 		}
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 49d4c544e062385113534fbd431bd44387961b8d..a70cb37d31a7a436e8dd4d16e4385feda1c770bf 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -264,6 +264,9 @@ typedef int (*SLAP_EXTOP_MAIN_FN) LDAP_P((
 typedef int (*SLAP_EXTOP_GETOID_FN) LDAP_P((
 	int index, char *oid, int blen ));
 
+LIBSLAPD_F (int) load_extension LDAP_P((const void *module, const char *file_name));
+LIBSLAPD_F (char *) get_supported_extension LDAP_P((int index));
+
 LIBSLAPD_F (int) load_extop LDAP_P((
 	const char *ext_oid,
 	SLAP_EXTOP_MAIN_FN ext_main ));
@@ -424,6 +427,12 @@ LIBSLAPD_F (char **) supportedSASLMechanisms;
 
 LIBSLAPD_F (int) sasl_init(void);
 LIBSLAPD_F (int) sasl_destroy(void);
+#ifdef HAVE_CYRUS_SASL
+LIBSLAPD_F (int) sasl_errldap LDAP_P(( int ));
+LIBSLAPD_F (int) sasl_bind LDAP_P((Backend *, 
+	Connection *, Operation *, 
+	char *, char *, char *, struct berval *, char **));
+#endif
 
 /*
  * schema.c
diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c
index 6eb8eea57034f81b0840df2585ae18c3fe5ee995..433cb9d9e46696f6647f929e16a54166713976ab 100644
--- a/servers/slapd/sasl.c
+++ b/servers/slapd/sasl.c
@@ -18,9 +18,32 @@
 char **supportedSASLMechanisms = NULL;
 
 #ifdef HAVE_CYRUS_SASL
-static sasl_callback_t callbacks[] = {
-	{ SASL_CB_LIST_END, NULL, NULL }
-};
+static void *sasl_pvt_mutex_new(void)
+{
+	ldap_pvt_thread_mutex_t *mutex;
+
+	mutex = (ldap_pvt_thread_mutex_t *)ch_malloc( sizeof(ldap_pvt_thread_mutex_t) );
+	if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
+		return mutex;
+	}
+	return NULL;
+}
+
+static int sasl_pvt_mutex_lock(void *mutex)
+{
+	return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex );
+}
+
+static int sasl_pvt_mutex_unlock(void *mutex)
+{
+	return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex );
+}
+
+static void sasl_pvt_mutex_dispose(void *mutex)
+{
+	(void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
+	free( mutex );
+}
 
 int sasl_init( void )
 {
@@ -28,7 +51,12 @@ int sasl_init( void )
 	char *mechs;
 	sasl_conn_t *server = NULL;
 
-	rc = sasl_server_init( callbacks, "slapd" );
+	sasl_set_alloc( ch_malloc, ch_calloc, ch_realloc, ch_free ); 
+
+	sasl_set_mutex( sasl_pvt_mutex_new, sasl_pvt_mutex_lock,
+		sasl_pvt_mutex_unlock, sasl_pvt_mutex_dispose );
+
+	rc = sasl_server_init( NULL, "slapd" );
 
 	if( rc != SASL_OK ) {
 		Debug( LDAP_DEBUG_ANY, "sasl_server_init failed\n",
@@ -88,6 +116,113 @@ int sasl_destroy( void )
 	return 0;
 }
 
+#ifdef HAVE_CYRUS_SASL
+int sasl_bind(
+    Backend             *be,
+    Connection          *conn,
+    Operation           *op,  
+    char                *dn,  
+    char                *ndn,
+    char                *mech,
+    struct berval       *cred,
+    char                **edn)
+{
+	struct berval response;
+	const char *errstr;
+	int sc;
+	int rc = 1;
+
+	Debug(LDAP_DEBUG_ARGS, "==> sasl_bind: dn=%s, mech=%s, cred->bv_len=%d\n",
+		dn, mech, cred ? cred->bv_len : 0 );
+
+	if ( conn->c_sasl_context == NULL ) {
+		sasl_callback_t callbacks[4];
+		int cbnum = 0;
+
+		if (be->be_sasl_authorize) {
+			callbacks[cbnum].id = SASL_CB_PROXY_POLICY;
+			callbacks[cbnum].proc = be->be_sasl_authorize;
+			callbacks[cbnum].context = be;
+			++cbnum;
+		}
+
+		if (be->be_sasl_getsecret) {
+			callbacks[cbnum].id = SASL_CB_SERVER_GETSECRET;
+			callbacks[cbnum].proc = be->be_sasl_getsecret;
+			callbacks[cbnum].context = be;
+			++cbnum;
+		}
+
+		if (be->be_sasl_putsecret) {
+			callbacks[cbnum].id = SASL_CB_SERVER_PUTSECRET;
+			callbacks[cbnum].proc = be->be_sasl_putsecret;
+			callbacks[cbnum].context = be;
+			++cbnum;
+		}
+		callbacks[cbnum].id = SASL_CB_LIST_END;
+		callbacks[cbnum].proc = NULL;
+		callbacks[cbnum].context = NULL;
+	
+		if ( sasl_server_new( "ldap", NULL, be->be_realm,
+			callbacks, SASL_SECURITY_LAYER, &conn->c_sasl_context ) != SASL_OK ) {
+			send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+				NULL, NULL, NULL, NULL );
+		} else {
+			conn->c_authmech = ch_strdup( mech );
+			sc = sasl_server_start( conn->c_sasl_context, conn->c_authmech,
+				cred->bv_val, cred->bv_len, (char **)&response.bv_val,
+				(unsigned *)&response.bv_len, &errstr );
+			if ( (sc != SASL_OK) && (sc != SASL_CONTINUE) ) {
+				send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ),
+					NULL, errstr, NULL, NULL );
+			}
+		}
+	} else {
+		sc = sasl_server_step( conn->c_sasl_context, cred->bv_val, cred->bv_len,
+			(char **)&response.bv_val, (unsigned *)&response.bv_len, &errstr );
+		if ( (sc != SASL_OK) && (sc != SASL_CONTINUE) ) {
+			send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ),
+				NULL, errstr, NULL, NULL );
+		}
+	}
+	if ( sc == SASL_OK ) {
+		char *authzid;
+
+		if ( ( sc = sasl_getprop( conn->c_sasl_context, SASL_USERNAME,
+			(void **)&authzid ) ) != SASL_OK ) {
+			send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ),
+				NULL, NULL, NULL, NULL );
+		} else {
+			if ( *edn != NULL ) {
+				free( *edn );
+			}
+			if ( strcasecmp( authzid, "anonymous" ) == 0 ) {
+				*edn = ch_strdup( "" );
+			} else {
+				*edn = ch_malloc( strlen( authzid ) + sizeof( "authzid=" ) );
+				strcpy( *edn, "authzid=" );
+				strcat( *edn, authzid );
+			}
+			/* let FE send result */
+			rc = 0;
+		}
+	} else if ( sc == SASL_CONTINUE ) {
+		/*
+		 * We set c_bind_in_progress because it doesn't appear
+		 * that connection.c sets this (unless do_bind() itself
+		 * returns LDAP_SASL_BIND_IN_PROGRESS).
+		 */
+		conn->c_bind_in_progress = 1;
+		send_ldap_sasl( conn, op, LDAP_SASL_BIND_IN_PROGRESS,
+			/* matched */ NULL, /* text */ NULL, /* refs */ NULL, /* controls */ NULL,  &response );
+	} 
+
+	Debug(LDAP_DEBUG_TRACE, "<== sasl_bind: rc=%d\n", rc, 0, 0);
+
+	return rc;
+}
+#endif /* HAVE_CYRUS_SASL */
+
 #else
 /* no SASL support */
 int sasl_init( void ) { return 0; }
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 6ab1017b5340210ce48b78edc3b894b869d9d14a..a9b82c60156894c8fa82065801493fb3b0a1dccb 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -500,6 +500,12 @@ struct slap_backend_db {
 #define		be_index_attr bd_info->bi_tool_index_attr
 #define		be_index_change bd_info->bi_tool_index_change
 #define		be_sync bd_info->bi_tool_sync
+#endif
+
+#ifdef HAVE_CYRUS_SASL
+#define		be_sasl_authorize bd_info->bi_sasl_authorize
+#define		be_sasl_getsecret bd_info->bi_sasl_getsecret
+#define		be_sasl_putsecret bd_info->bi_sasl_putsecret
 #endif
 
 	/* these should be renamed from be_ to bd_ */
@@ -656,6 +662,18 @@ struct slap_backend_info {
 		struct berval **bv, ID id, int op ));
 	int (*bi_tool_sync) LDAP_P(( BackendDB *be ));
 
+#ifdef HAVE_CYRUS_SASL
+	int (*bi_sasl_authorize) LDAP_P(( BackendDB *be,
+		const char *authnid, const char *authzid,
+		const char **canon_authzid, const char **errstr ));
+	int (*bi_sasl_getsecret) LDAP_P(( BackendDB *be,
+		const char *mechanism, const char *authzid,
+		const char *realm, sasl_secret_t **secret ));
+	int (*bi_sasl_putsecret) LDAP_P(( BackendDB *be,
+		const char *mechanism, const char *auth_identity,
+		const char *realm, const sasl_secret_t *secret ));
+#endif /* HAVE_CYRUS_SASL */
+
 #define SLAP_INDEX_ADD_OP		0x0001
 #define SLAP_INDEX_DELETE_OP	0x0002
 
diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c
index 03d91a25a90bf15621989a8235581e072b2ead8a..3bb5fc93f7384b519d413beff0c8aeb26f279a20 100644
--- a/servers/slapd/tools/mimic.c
+++ b/servers/slapd/tools/mimic.c
@@ -143,3 +143,18 @@ int sasl_init(void) {
 int sasl_destroy(void) {
 	return 0;
 }
+
+#ifdef HAVE_CYRUS_SASL
+int sasl_bind(
+    Backend             *be,
+    Connection          *conn,
+    Operation           *op,
+    char                *dn,
+    char                *ndn,
+    char                *mech,
+    struct berval       *cred,
+    char                **edn)
+{
+	return -1;
+}
+#endif