diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c
index f55cb80aa15d2bc2bf83bfc057d768979e58e4b8..427952c5fa027e43b57a931f692257a0a923287f 100644
--- a/clients/tools/ldapmodify.c
+++ b/clients/tools/ldapmodify.c
@@ -103,12 +103,14 @@ usage( const char *prog )
 "	specified by \"-f file\".\n"
 "Add or modify options:\n"
 "  -a         add values (default%s)\n"
+"  -c         continuous operation mode (do not stop on errors)\n"
+"  -f file    read operations from `file'\n"
 "  -F         force all changes records to be used\n"
+"  -S file    write skipped modifications to `file'\n"
 
 "Common options:\n"
 "  -d level   set LDAP debugging level to `level'\n"
 "  -D binddn  bind DN\n"
-"  -f file    read operations from `file'\n"
 "  -h host    LDAP server\n"
 "  -H URI     LDAP Uniform Resource Indentifier(s)\n"
 "  -I         use SASL Interactive mode\n"
@@ -138,10 +140,11 @@ usage( const char *prog )
 int
 main( int argc, char **argv )
 {
-    char		*infile, *rbuf, *start;
-    FILE		*fp;
+    char		*infile, *rejfile, *rbuf, *start, *rejbuf;
+    FILE		*fp, *rejfp;
+	char		*matched_msg = NULL, *error_msg = NULL;
 	int		rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals;
-	int count;
+	int count, len;
 
     if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
 	prog = argv[ 0 ];
@@ -156,12 +159,13 @@ main( int argc, char **argv )
     ldapadd = ( strncmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
 
     infile = NULL;
+    rejfile = NULL;
     not = verbose = want_bindpw = debug = manageDSAit = referrals = 0;
     authmethod = -1;
 	version = -1;
 
     while (( i = getopt( argc, argv, "acrf:F"
-		"Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF )
+		"Cd:D:h:H:IkKMnO:p:P:QR:S:U:vw:WxX:Y:Z" )) != EOF )
 	{
 	switch( i ) {
 	/* Modify Options */
@@ -403,6 +407,13 @@ main( int argc, char **argv )
 		return( EXIT_FAILURE );
 #endif
 		break;
+	case 'S':	/* skipped modifications to file */
+		if( rejfile != NULL ) {
+			fprintf( stderr, "%s: -S previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		rejfile = strdup( optarg );
+		break;
 	case 'U':
 #ifdef HAVE_CYRUS_SASL
 		if( sasl_authc_id != NULL ) {
@@ -539,6 +550,15 @@ main( int argc, char **argv )
 	if ( argc != optind )
 	usage( prog );
 
+    if ( rejfile != NULL ) {
+	if (( rejfp = fopen( rejfile, "w" )) == NULL ) {
+	    perror( rejfile );
+	    return( EXIT_FAILURE );
+	}
+    } else {
+	rejfp = NULL;
+    }
+
     if ( infile != NULL ) {
 	if (( fp = fopen( infile, "r" )) == NULL ) {
 	    perror( infile );
@@ -671,6 +691,7 @@ main( int argc, char **argv )
 			ldap_perror( ld, "ldap_bind" );
 			return( EXIT_FAILURE );
 		}
+
 	}
 
     }
@@ -707,10 +728,33 @@ main( int argc, char **argv )
 
 	start = rbuf;
 
+	if ( rejfp ) {
+		len = strlen( rbuf );
+		if (( rejbuf = (char *)malloc( len+1 )) == NULL ) {
+			perror( "realloc" );
+			exit( EXIT_FAILURE );
+		}
+		memcpy( rejbuf, rbuf, len+1 );
+	}
+
     rc = process_ldif_rec( start, count );
 
-	if( rc )
-		fprintf( stderr, "ldif_record() = %d\n", rc );
+	if ( rc && rejfp ) {
+		fprintf(rejfp, "# Error: %s (%d)", ldap_err2string(rc), rc);
+
+		ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg);
+		if ( matched_msg != NULL && *matched_msg != '\0' ) {
+			fprintf( rejfp, ", matched DN: %s", matched_msg );
+		}
+
+		ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &error_msg);
+		if ( error_msg != NULL && *error_msg != '\0' ) {
+			fprintf( rejfp, ", additional info: %s", error_msg );
+		}
+		fprintf( rejfp, "\n%s\n", rejbuf );
+	}
+		if (rejfp) 
+			free( rejbuf );
 		free( rbuf );
     }
 
@@ -718,6 +762,10 @@ main( int argc, char **argv )
 		ldap_unbind( ld );
     }
 
+    if ( rejfp != NULL ) {
+	    fclose( rejfp );
+    }
+
 	return( rc );
 }
 
diff --git a/doc/devel/args b/doc/devel/args
index ea02cfa4f42b29bc149ef7cb40d1ddf91ba19b60..e000234440bafbba36332d93f384a1ed179576e1 100644
--- a/doc/devel/args
+++ b/doc/devel/args
@@ -1,6 +1,6 @@
 Tools           ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
 ldapdelete       *CDE *HI*K M*OPQR  U*WXYZ  cdef*h**k *n*p*    vwx*
-ldapmodify       *CDEF*HI*K M*OPQR  U*WXYZabcdef*h**k *n*p*r t vwx*
+ldapmodify       *CDEF*HI*K M*OPQRS U*WXYZabcdef*h**k *n*p*r t vwx*
 ldapmodrdn       *CDE *HI*K M*OPQR  U*WXYZ  cdef*h**k *n*p*rs  vwx*
 ldappasswd      A*CDE *HI*   *O QRS U*WXYZa  de *h**  * * * s  vwx*  
 ldapsearch      A*CDE *HI*KLM*OPQRSTU*WXYZab*def*h**kl*n*p* stuvwx*z
diff --git a/doc/man/man1/ldapmodify.1 b/doc/man/man1/ldapmodify.1
index 3ffbe59a92f63c27156d2ad78e69edb06a2bb692..139753363277a7a1d0f0658884a00e6c5d5e949c 100644
--- a/doc/man/man1/ldapmodify.1
+++ b/doc/man/man1/ldapmodify.1
@@ -1,36 +1,113 @@
-.TH LDAPMODIFY 1 "13 November 1995" "U-M LDAP LDVERSION"
+.TH LDAPMODIFY 1 "20 August 2001" "OpenLDAP LDVERSION"
+.\" $OpenLDAP$
+.\" Copyright 1998-2002 The OpenLDAP Foundation All Rights Reserved.
+.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
 .SH NAME
-ldapmodify, ldapadd \- ldap modify entry and ldap add entry tools
+ldapmodify, ldapadd \- LDAP modify entry and LDAP add entry tools
 .SH SYNOPSIS
 .B ldapmodify
-.B [\-a]
-.B [\-b]
-.B [\-c]
-.B [\-r]
-.B [\-n]
-.B [\-v]
-.B [\-k]
-.B [\-d debuglevel]
-.B [\-D binddn]
-.B [\-w passwd]
-.B [\-h ldaphost]
-.B [\-p ldapport]
-.B [\-f file]
+[\c
+.BR \-a ]
+[\c
+.BR \-c ]
+[\c
+.BI \-S \ file\fR]
+.[\c
+.BR \-C ]
+[\c
+.BR \-n ]
+[\c
+.BR \-v ]
+[\c
+.BR \-k ]
+[\c
+.BR \-K ]
+[\c
+.BR \-M[M] ]
+[\c
+.BI \-d \ debuglevel\fR]
+[\c
+.BI \-D \ binddn\fR]
+[\c
+.BR \-W ]
+[\c
+.BI \-w \ passwd\fR]
+[\c
+.BI \-H \ ldapuri\fR]
+[\c
+.BI \-h \ ldaphost\fR]
+[\c
+.BI \-p \ ldapport\fR]
+[\c
+.BI \-P \ 2\fR\||\|\fI3\fR]
+[\c
+.BR \-O \ security-properties ]
+[\c
+.BR \-I ]
+[\c
+.BR \-Q ]
+[\c
+.BI \-U \ authcid\fR]
+[\c
+.BR \-x ]
+[\c
+.BI \-X \ authzid\fR]
+[\c
+.BI \-Y \ mech\fR]
+[\c
+.BR \-Z[Z] ]
+[\c
+.BI \-f \ file\fR]
 .LP
 .B ldapadd
-.B [\-b]
-.B [\-c]
-.B [\-r]
-.B [\-n]
-.B [\-v]
-.B [\-k]
-.B [\-K]
-.B [\-d debuglevel]
-.B [\-D binddn]
-.B [\-w passwd]
-.B [\-h ldaphost]
-.B [\-p ldapport]
-.B [\-f file]
+[\c
+.BR \-c ]
+[\c
+.BI \-S \ file\fR]
+[\c
+.BR \-C ]
+[\c
+.BR \-n ]
+[\c
+.BR \-v ]
+[\c
+.BR \-k ]
+[\c
+.BR \-K ]
+[\c
+.BR \-M[M] ]
+[\c
+.BI \-d \ debuglevel\fR]
+[\c
+.BI \-D \ binddn\fR]
+[\c
+.BR \-W ]
+[\c
+.BI \-w \ passwd\fR]
+[\c
+.BI \-h \ ldaphost\fR]
+[\c
+.BI \-p \ ldapport\fR]
+[\c
+.BI \-P \ 2\fR\||\|\fI3\fR]
+[\c
+.BR \-O \ security-properties ]
+[\c
+.BR \-I ]
+[\c
+.BR \-Q ]
+[\c
+.BI \-U \ authcid\fR]
+[\c
+.BR \-x ]
+[\c
+.BI \-X \ authzid\fR]
+[\c
+.BI \-Y \ mech\fR]
+[\c
+.BR \-Z[Z] ]
+[\c
+.BI \-f \ file\fR]
 .SH DESCRIPTION
 .B ldapmodify
 is a shell-accessible interface to the
@@ -56,10 +133,8 @@ is to modify existing entries.  If invoked as
 .BR ldapadd ,
 this flag is always set.
 .TP
-.B \-b
-Assume that any values that start with a `/' are binary values and that
-the actual value is in a file whose path is specified in the place where
-values normally appear.
+.B \-C
+Automatically chase referrals.
 .TP
 .B \-c
 Continuous operation mode.  Errors are reported, but
@@ -67,8 +142,10 @@ Continuous operation mode.  Errors are reported, but
 will continue with modifications.  The default is to exit after
 reporting an error.
 .TP
-.B \-r
-Replace existing values by default.
+.BI \-S \ file
+Add or change records which where skipped due to an error are written to \fIfile\fP 
+and the error message returned by the server is added as a comment. Most useful in 
+conjunction with -c.
 .TP
 .B \-n
 Show what would be done, but don't actually modify entries.  Useful for
@@ -78,14 +155,14 @@ debugging in conjunction with -v.
 Use verbose mode, with many diagnostics written to standard output.
 .TP
 .B \-k
-Use Kerberos authentication instead of simple authentication.  It is
+Use Kerberos IV authentication instead of simple authentication.  It is
 assumed that you already have a valid ticket granting ticket.  You must
-compile with KERBEROS defined for this option to have any effect.
+compile with Kerberos support for this option to have any effect.
 .TP
 .B \-K
-Same as \-k, but only does step 1 of the kerberos bind.  This is useful
+Same as \-k, but only does step 1 of the Kerberos IV bind.  This is useful
 when connecting to a slapd and there is no x500dsa.hostname principal
-registered with your kerberos servers.
+registered with your Kerberos Domain Controller(s).
 .TP
 .B \-F
 Force application of all changes regardless of the contents of input
@@ -94,36 +171,85 @@ lines that begin with
 (by default, replica: lines are compared against the LDAP server host
 and port in use to decide if a replog record should actually be applied).
 .TP
-.B \-d debuglevel
+.B \-M[M]
+Enable manage DSA IT control.
+.B \-MM
+makes control critical.
+.TP
+.BI \-d \ debuglevel
 Set the LDAP debugging level to \fIdebuglevel\fP.
 .B ldapmodify
 must be compiled with LDAP_DEBUG defined for this option to have any effect.
 .TP
-.B \-f file
+.BI \-f \ file
 Read the entry modification information from \fIfile\fP instead of from
 standard input.
 .TP
-.B \-D binddn
-Use \fIbinddn\fP to bind to the X.500 directory. \fIbinddn\fP should be
-a string-represented DN as defined in RFC 1779.
+.B \-x 
+Use simple authentication instead of SASL.
+.TP
+.BI \-D \ binddn
+Use the Distinguished Name \fIbinddn\fP to bind to the LDAP directory.
 .TP
-.B \-w passwd
+.B \-W
+Prompt for simple authentication.
+This is used instead of specifying the password on the command line.
+.TP
+.BI \-w \ passwd
 Use \fIpasswd\fP as the password for simple authentication.
 .TP
-.B \-h ldaphost
+.BI \-H \ ldapuri
+Specify URI(s) referring to the ldap server(s).
+.TP
+.BI \-h \ ldaphost
 Specify an alternate host on which the ldap server is running.
+Deprecated in favor of -H.
 .TP
-.B \-p ldapport
+.BI \-p \ ldapport
 Specify an alternate TCP port where the ldap server is listening.
+Deprecated in favor of -H.
+.TP
+.BI \-P \ 2\fR\||\|\fI3
+Specify the LDAP protocol version to use.
+.TP
+.BI \-O \ security-properties
+Specify SASL security properties.
+.TP
+.B \-I
+Enable SASL Interactive mode.  Always prompt.  Default is to prompt
+only as needed.
+.TP
+.B \-Q
+Enable SASL Quiet mode.  Never prompt.
+.TP
+.BI \-U \ authcid
+Specify the authentication ID for SASL bind. The form of the ID
+depends on the actual SASL mechanism used.
+.TP
+.BI \-X \ authzid
+Specify the requested authorization ID for SASL bind.
+.I authzid
+must be one of the following formats:
+.B dn:\c
+.I <distinguished name>
+or
+.B u:\c
+.I <username>
+.TP
+.BI \-Y \ mech
+Specify the SASL mechanism to be used for authentication. If it's not
+specified, the program will choose the best mechanism the server knows.
+.TP
+.B \-Z[Z]
+Issue StartTLS (Transport Layer Security) extended operation. If you use
+.B \-ZZ\c
+, the command will require the operation to be successful.
 .SH INPUT FORMAT
 The contents of \fIfile\fP (or standard input if no \-f flag is given on
 the command line) should conform to the format defined in
 .BR slapd.replog (5),
 with the exceptions noted below.
 .LP
-If the first line of a record consists of a decimal number (entry id),
-it is ignored.
-.LP
 Lines that begin with "replica:" are matched against the LDAP server host
 and port in use to decide if a particular replog record should be applied.
 Any other lines that precede the "dn:" line are ignored.
@@ -138,8 +264,10 @@ flag is set (or if the program was invoked as
 and "modify" otherwise.
 .LP
 If changetype is "modify" and no "add:", "replace:", or "delete:" lines
-appear, the default is "replace" if the -r flag is set and "add"
-otherwise.
+appear, the default is "replace" for and "add"
+.BR ldapmodify (1)
+for
+.BR ldapadd (1).
 .LP
 Note that the above exceptions to the
 .BR slapd.replog (5)
@@ -149,56 +277,22 @@ entries to be used as input to
 .I ldapmodify
 or
 .I ldapadd.
-.SH ALTERNATIVE INPUT FORMAT
-An alternative input format is supported for compatibility with older
-versions of
-.I ldapmodify.
-This format consists of one or more entries separated by blank lines,
-where each entry looks like:
-.LP
-.nf
-    Distinguished Name (DN)
-    attr=value
-    [attr=value ...]
-.fi
-.LP
-where \fIattr\fP is the name of the attribute and \fIvalue\fP is the
-value.
-.LP
-By default, values are added.  If the
-.RI \- r
-command line flag is
-given, the default is to replace existing values with the new one.
-Note that it is permissible for a given attribute to appear more than
-once (for example, to add more than one value for an attribute).  Also
-note that you can use a trailing `\\' to continue values across lines and
-preserve newlines in the value itself (this is useful for modifying
-QUIPU iattr attributes among others).
-.LP
-.I attr
-should be preceded by a \fB-\fP to remove a value.  The `=' and
-value should be omitted to remove an entire attribute.
-.LP
-.I attr
-should be preceded by a \fB+\fP to add a value in the presence of the
-\-r flag.
-.LP
 .SH EXAMPLES
 Assuming that the file
 .B /tmp/entrymods
 exists and has the contents:
 .LP
 .nf
-    dn: cn=Modify Me, o=University of Michigan, c=US
+    dn: cn=Modify Me,dc=example,dc=com
     changetype: modify
     replace: mail
-    mail: modme@terminator.rs.itd.umich.edu
+    mail: modme@OpenLDAP.org
     -
     add: title
     title: Grand Poobah
     -
     add: jpegPhoto
-    jpegPhoto: /tmp/modme.jpeg
+    jpegPhoto:< file://tmp/modme.jpeg
     -
     delete: description
     -
@@ -207,12 +301,12 @@ exists and has the contents:
 the command:
 .LP
 .nf
-    ldapmodify -b -r -f /tmp/entrymods
+    ldapmodify -f /tmp/entrymods
 .fi
 .LP
 will replace the contents of the "Modify Me" entry's
 .I mail
-attribute with the value "modme@terminator.rs.itd.umich.edu", add a
+attribute with the value "modme@example.com", add a
 .I title
 of "Grand Poobah", and the contents of the file "/tmp/modme.jpeg"
 as a
@@ -220,36 +314,19 @@ as a
 and completely remove the
 .I description
 attribute.
-The same modifications as above can be performed using the older
-.I ldapmodify
-inout format:
-.LP
-.nf
-    cn=Modify Me, o=University of Michigan, c=US
-    mail=modme@terminator.rs.itd.umich.edu
-    +title=Grand Poobah
-    +jpegPhoto=/tmp/modme.jpeg
-    -description
-.fi
-.LP
-and the command:
-.LP
-.nf
-    ldapmodify -b -r -f /tmp/entrymods
-.fi
 .LP
 Assuming that the file
 .B /tmp/newentry
 exists and has the contents:
 .LP
 .nf
-    dn: cn=Barbara Jensen, o=University of Michigan, c=US
+    dn: cn=Barbara Jensen,dc=example,dc=com
     objectClass: person
     cn: Barbara Jensen
     cn: Babs Jensen
     sn: Jensen
     title: the world's most famous mythical manager
-    mail: bjensen@terminator.rs.itd.umich.edu
+    mail: bjensen@example.com
     uid: bjensen
 .LP
 the command:
@@ -267,7 +344,7 @@ Assuming that the file
 exists and has the contents:
 .LP
 .nf
-    dn: cn=Barbara Jensen, o=University of Michigan, c=US
+    dn: cn=Barbara Jensen,dc=example,dc=com
     changetype: delete
 .LP
 the command:
@@ -278,24 +355,24 @@ the command:
 .LP
 will remove Babs Jensen's entry.
 .SH DIAGNOSTICS
-Exit status is 0 if no errors occur.  Errors result in a non-zero exit
-status and a diagnostic message being written to standard error.
+Exit status is zero if no errors occur.  Errors result in a non-zero
+exit status and a diagnostic message being written to standard error.
 .SH "SEE ALSO"
 .BR ldapadd (1),
 .BR ldapdelete (1),
 .BR ldapmodrdn (1),
 .BR ldapsearch (1),
+.BR ldap.conf (5),
 .BR ldap (3),
 .BR ldap_add (3),
 .BR ldap_delete (3),
 .BR ldap_modify (3),
 .BR ldap_modrdn (3),
 .BR slapd.replog (5)
-.LP
-Kille, S.,
-.IR "A String Representation of Distinguished Names",
-.SM RFC
-1779,
-ISODE Consortium, March 1995.
-.SH BUGS
-There is no interactive mode, but there probably should be.
+.SH AUTHOR
+The OpenLDAP Project <http://www.openldap.org/>
+.SH ACKNOWLEDGEMENTS
+.B	OpenLDAP
+is developed and maintained by The OpenLDAP Project (http://www.openldap.org/).
+.B	OpenLDAP
+is derived from University of Michigan LDAP 3.3 Release.  
diff --git a/libraries/libldap/cache.c b/libraries/libldap/cache.c
index ccfc763092d3973aac0e8100edb35cceeb2ccba9..83e6e7953cbe9b0ff8da07f23f52149eb1999bf9 100644
--- a/libraries/libldap/cache.c
+++ b/libraries/libldap/cache.c
@@ -37,6 +37,9 @@ static void		uncache_entry_or_req LDAP_P(( LDAP *ld, LDAP_CONST char *dn, ber_in
 int
 ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifndef LDAP_NOCACHE
 	if ( ld->ld_cache == NULL ) {
 		if (( ld->ld_cache = (LDAPCache *)LDAP_MALLOC( sizeof( LDAPCache )))
@@ -62,6 +65,9 @@ ldap_enable_cache( LDAP *ld, long timeout, ber_len_t maxmem )
 void
 ldap_disable_cache( LDAP *ld )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifndef LDAP_NOCACHE
 	if ( ld->ld_cache != NULL ) {
 		ld->ld_cache->lc_enabled = 0;
@@ -74,6 +80,9 @@ ldap_disable_cache( LDAP *ld )
 void
 ldap_set_cache_options( LDAP *ld, unsigned long opts )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifndef LDAP_NOCACHE
 	if ( ld->ld_cache != NULL ) {
 		ld->ld_cache->lc_options = opts;
@@ -85,6 +94,9 @@ ldap_set_cache_options( LDAP *ld, unsigned long opts )
 void
 ldap_destroy_cache( LDAP *ld )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifndef LDAP_NOCACHE
 	if ( ld->ld_cache != NULL ) {
 		ldap_flush_cache( ld );
@@ -102,6 +114,9 @@ ldap_flush_cache( LDAP *ld )
 	int		i;
 	LDAPMessage	*m, *next;
 
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_flush_cache\n" ));
 #else
@@ -134,6 +149,9 @@ ldap_flush_cache( LDAP *ld )
 void
 ldap_uncache_request( LDAP *ld, int msgid )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifndef LDAP_NOCACHE
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, 
@@ -152,6 +170,10 @@ ldap_uncache_request( LDAP *ld, int msgid )
 void
 ldap_uncache_entry( LDAP *ld, LDAP_CONST char *dn )
 {
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+	assert( dn != NULL );
+
 #ifndef LDAP_NOCACHE
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, 
@@ -240,6 +262,9 @@ ldap_add_request_to_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request )
 	LDAPMessage	*new;
 	ber_len_t	len;
 
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_add_request_to_cache\n" ));
 #else
@@ -288,6 +313,10 @@ ldap_add_result_to_cache( LDAP *ld, LDAPMessage *result )
 	LDAPMessage	*m, **mp, *req, *new, *prev;
 	int		err, keep;
 
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+	assert( result != NULL );
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ARGS, 
 		"ldap_add_result_to_cache: id %ld, type %ld\n",
@@ -447,6 +476,10 @@ ldap_check_cache( LDAP *ld, ber_tag_t msgtype, BerElement *request )
 	int		first, hash;
 	time_t	c_time;
 
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+	assert( request != NULL );
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "cache", LDAP_LEVEL_ENTRY, "ldap_check_cache\n" ));
 #else
diff --git a/libraries/libldap/compare.c b/libraries/libldap/compare.c
index 83d7ec125e934325daa614f8e27b0f6f3b25576c..4af59d01b8d15842a6a5f44db0244028d1a04c66 100644
--- a/libraries/libldap/compare.c
+++ b/libraries/libldap/compare.c
@@ -131,6 +131,8 @@ ldap_compare(
 	int msgid;
 	struct berval bvalue;
 
+	assert( value != NULL );
+
 	bvalue.bv_val = (char *) value;
 	bvalue.bv_len = (value == NULL) ? 0 : strlen( value );
 
@@ -171,6 +173,8 @@ ldap_compare_s(
 {
 	struct berval bvalue;
 
+	assert( value != NULL );
+
 	bvalue.bv_val = (char *) value;
 	bvalue.bv_len = (value == NULL) ? 0 : strlen( value );
 
diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c
index 76c2799236133b46dc3e2dcc760936d29b8e37cf..12f455be9863cc1e9fc97ef205d6a2b14abc3bd5 100644
--- a/libraries/libldap/controls.c
+++ b/libraries/libldap/controls.c
@@ -38,6 +38,7 @@ ldap_int_put_controls(
 	LDAPControl *const *c;
 
 	assert( ld != NULL );
+	assert( LDAP_VALID(ld) );
 	assert( ber != NULL );
 
 	if( ctrls == NULL ) {
@@ -414,6 +415,7 @@ ldap_create_control(
 	struct berval *bvalp;
 
 	assert( requestOID != NULL );
+	assert( ber != NULL );
 	assert( ctrlp != NULL );
 
 	ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
@@ -452,6 +454,7 @@ int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
 	LDAPControl *const *c;
 
 	assert( ld != NULL );
+	assert( LDAP_VALID(ld) );
 
 	if( ctrls == NULL ) {
 		/* use default server controls */
diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c
index c35eb0d5a996c2a90d84c205bc67f2973f1dc02b..b2707577dfa0e6c6f7dccd4c462a9e5de2cef1d4 100644
--- a/libraries/libldap/cyrus.c
+++ b/libraries/libldap/cyrus.c
@@ -434,19 +434,6 @@ ldap_int_sasl_open(
 	int rc;
 	sasl_conn_t *ctx;
 
-	sasl_callback_t *session_callbacks =
-		LDAP_CALLOC( 2, sizeof( sasl_callback_t ) );
-
-	if( session_callbacks == NULL ) return LDAP_NO_MEMORY;
-
-	session_callbacks[0].id = SASL_CB_USER;
-	session_callbacks[0].proc = NULL;
-	session_callbacks[0].context = ld;
-
-	session_callbacks[1].id = SASL_CB_LIST_END;
-	session_callbacks[1].proc = NULL;
-	session_callbacks[1].context = NULL;
-
 	assert( lc->lconn_sasl_ctx == NULL );
 
 	if ( host == NULL ) {
@@ -456,14 +443,13 @@ ldap_int_sasl_open(
 
 #if SASL_VERSION_MAJOR >= 2
 	rc = sasl_client_new( "ldap", host, NULL, NULL,
-		session_callbacks, 0, &ctx );
+		NULL, 0, &ctx );
 #else
-	rc = sasl_client_new( "ldap", host, session_callbacks,
+	rc = sasl_client_new( "ldap", host, NULL,
 		SASL_SECURITY_LAYER, &ctx );
 #endif
 
 	if ( rc != SASL_OK ) {
-		LDAP_FREE( session_callbacks );
 		ld->ld_errno = sasl_err2ldap( rc );
 		return ld->ld_errno;
 	}
@@ -477,7 +463,6 @@ ldap_int_sasl_open(
 #endif
 
 	lc->lconn_sasl_ctx = ctx;
-	lc->lconn_sasl_cbs = session_callbacks;
 
 	if( ssf ) {
 #if SASL_VERSION_MAJOR >= 2
@@ -510,8 +495,6 @@ int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
 	if( ctx != NULL ) {
 		sasl_dispose( &ctx );
 		lc->lconn_sasl_ctx = NULL;
-		LDAP_FREE( lc->lconn_sasl_cbs );
-		lc->lconn_sasl_cbs = NULL;
 	}
 
 	return LDAP_SUCCESS;
diff --git a/libraries/libldap/dnssrv.c b/libraries/libldap/dnssrv.c
index 1a763c9b6efc3b419206f83e464d11cab6988cb7..cc193e93582bef587dcfb15c511b60feaf00d18d 100644
--- a/libraries/libldap/dnssrv.c
+++ b/libraries/libldap/dnssrv.c
@@ -41,9 +41,8 @@ int ldap_dn2domain(
 	char *domain = NULL;
 	char **dn;
 
-	if( dn_in == NULL || domainp == NULL ) {
-		return -1;
-	}
+	assert( dn_in != NULL );
+	assert( domainp != NULL );
 
 	dn = ldap_explode_dn( dn_in, 0 );
 
@@ -147,12 +146,12 @@ int ldap_domain2dn(
     char *domain, *s, *tok_r, *dn;
     size_t loc;
 
-    if (domain_in == NULL || dnp == NULL) {
-	return LDAP_NO_MEMORY;
-    }
+	assert( domain_in != NULL );
+	assert( dnp != NULL );
+
     domain = LDAP_STRDUP(domain_in);
     if (domain == NULL) {
-	return LDAP_NO_MEMORY;
+		return LDAP_NO_MEMORY;
     }
     dn = NULL;
     loc = 0;
diff --git a/libraries/libldap/getentry.c b/libraries/libldap/getentry.c
index b75a4403f4e787efcffc57c15f2665bcaca5dd88..4fb23eff6cb69bc0993f0daec9c65963daf39231 100644
--- a/libraries/libldap/getentry.c
+++ b/libraries/libldap/getentry.c
@@ -29,10 +29,6 @@ ldap_first_entry( LDAP *ld, LDAPMessage *chain )
 	assert( LDAP_VALID( ld ) );
 	assert( chain != NULL );
 
-	if( ld == NULL || chain == NULL ) {
-		return NULL;
-	}
-
 	return chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY
 		? chain
 		: ldap_next_entry( ld, chain );
@@ -45,11 +41,7 @@ ldap_next_entry( LDAP *ld, LDAPMessage *entry )
 	assert( LDAP_VALID( ld ) );
 	assert( entry != NULL );
 
-	if ( ld == NULL || entry == NULL ) {
-		return NULL;
-	}
-
-	for (
+	for(
 		entry = entry->lm_chain;
 		entry != NULL;
 		entry = entry->lm_chain )
@@ -70,10 +62,6 @@ ldap_count_entries( LDAP *ld, LDAPMessage *chain )
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
 
-	if ( ld == NULL ) {
-		return -1;
-	}
-
 	for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
 		if( chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY ) {
 			i++;
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
index cd10cde790ab87aaf485cf9b3ddcde46f3469ca7..4ad20dd9f4c813a6172fbc9e940e42b441803d9d 100644
--- a/libraries/libldap/ldap-int.h
+++ b/libraries/libldap/ldap-int.h
@@ -189,7 +189,6 @@ typedef struct ldap_conn {
 #endif
 #ifdef HAVE_CYRUS_SASL
 	void		*lconn_sasl_ctx;
-	void		*lconn_sasl_cbs;
 #endif
 	int			lconn_refcnt;
 	time_t		lconn_lastused;	/* time */
diff --git a/libraries/libldap/messages.c b/libraries/libldap/messages.c
new file mode 100644
index 0000000000000000000000000000000000000000..bcb13a7f1461d4697705cdfe67387a07c183eec0
--- /dev/null
+++ b/libraries/libldap/messages.c
@@ -0,0 +1,55 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/*
+ *  messages.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"
+
+LDAPMessage *
+ldap_first_message( LDAP *ld, LDAPMessage *chain )
+{
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+	assert( chain != NULL );
+
+  	return chain;
+}
+
+LDAPMessage *
+ldap_next_message( LDAP *ld, LDAPMessage *msg )
+{
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+	assert( msg != NULL );
+
+	return msg->lm_chain;
+}
+
+int
+ldap_count_messages( LDAP *ld, LDAPMessage *chain )
+{
+	int	i;
+
+	assert( ld != NULL );
+	assert( LDAP_VALID( ld ) );
+
+	for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
+		i++;
+	}
+
+	return( i );
+}
diff --git a/libraries/libldap/references.c b/libraries/libldap/references.c
index 2aae3f469c5a0bcce38000b0685e601c19cb4a6f..ff9b63fc0c7902403a6716bee1cf279004311cd6 100644
--- a/libraries/libldap/references.c
+++ b/libraries/libldap/references.c
@@ -24,7 +24,7 @@ ldap_first_reference( LDAP *ld, LDAPMessage *chain )
 {
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
-	assert( chain !=  NULL );
+	assert( chain != NULL );
 
 	return chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE
 		? chain
@@ -36,7 +36,7 @@ ldap_next_reference( LDAP *ld, LDAPMessage *ref )
 {
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
-	assert( ref !=  NULL );
+	assert( ref != NULL );
 
 	for (
 		ref = ref->lm_chain;
@@ -58,13 +58,7 @@ ldap_count_references( LDAP *ld, LDAPMessage *chain )
 
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
-	assert( chain !=  NULL );
-
-	if ( ld == NULL ) {
-		return -1;
-	}
 
-	
 	for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
 		if( chain->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
 			i++;
diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c
index b7cc3e70ef661f6a08cb1c6d0550da567177b2fc..98fa9b85665a0c0e60fbc89325a5879ce13856ac 100644
--- a/servers/slapd/back-bdb/add.c
+++ b/servers/slapd/back-bdb/add.c
@@ -23,7 +23,7 @@ bdb_add(
 	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
 	struct berval	pdn;
 	Entry		*p = NULL;
-	int			rc; 
+	int		rc, ret; 
 	const char	*text;
 	char textbuf[SLAP_TEXT_BUFLEN];
 	size_t textlen = sizeof textbuf;
@@ -33,6 +33,8 @@ bdb_add(
 #ifdef BDB_SUBENTRIES
 	int subentry;
 #endif
+	u_int32_t	locker;
+	DB_LOCK		lock;
 #if 0
 	u_int32_t	lockid;
 	DB_LOCK		lock;
@@ -108,6 +110,8 @@ retry:	/* transaction retry */
 		text = "internal error";
 		goto return_results;
 	}
+
+	locker = TXN_ID ( ltid );
 #if 0
 	lockid = TXN_ID( ltid );
 #endif
@@ -142,7 +146,7 @@ retry:	/* transaction retry */
 #endif
 
 		/* get parent */
-		rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 );
+		rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0, locker, &lock );
 
 		switch( rc ) {
 		case 0:
@@ -169,7 +173,7 @@ retry:	/* transaction retry */
 				refs = is_entry_referral( matched )
 					? get_entry_referrals( be, conn, op, matched )
 					: NULL;
-				bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+				bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched );
 				matched = NULL;
 
 			} else {
@@ -200,7 +204,7 @@ retry:	/* transaction retry */
 		case DB_LOCK_DEADLOCK:
 		case DB_LOCK_NOTGRANTED:
 			/* free parent and reader lock */
-			bdb_cache_return_entry_r( &bdb->bi_cache, p );
+			bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
 			p = NULL;
 			goto retry;
 		}
@@ -262,7 +266,7 @@ retry:	/* transaction retry */
 				matched_dn, NULL, refs, NULL );
 
 			ber_bvarray_free( refs );
-			bdb_cache_return_entry_r( &bdb->bi_cache, p );
+			bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
 			p = NULL;
 			goto done;
 		}
@@ -275,7 +279,7 @@ retry:	/* transaction retry */
 #endif
 
 		/* free parent and reader lock */
-		bdb_cache_return_entry_r( &bdb->bi_cache, p );
+		bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
 		p = NULL;
 
 	} else {
@@ -430,9 +434,22 @@ retry:	/* transaction retry */
 			text = "txn_prepare failed";
 
 		} else {
+			ret = bdb_cache_add_entry_rw(bdb->bi_dbenv, &bdb->bi_cache, e, CACHE_WRITE_LOCK, locker, &lock);
+#if 0
 			if ( bdb_cache_add_entry_rw(&bdb->bi_cache,
 				e, CACHE_WRITE_LOCK) != 0 )
-			{
+#endif
+			switch ( ret ) {
+			case 0:
+				break;
+			case DB_LOCK_DEADLOCK:
+			case DB_LOCK_NOTGRANTED:
+				goto retry;
+			default:
+				ret = LDAP_OTHER;
+			}
+
+			if ( ret ) {
 				if(( rc=TXN_ABORT( ltid )) != 0 ) {
 					text = "cache add & txn_abort failed";
 				} else {
diff --git a/servers/slapd/back-bdb/attribute.c b/servers/slapd/back-bdb/attribute.c
index 38203b994d3e245290427b0d29eb1e30a4962c8e..1277f0256104f9addae957f37ed24829b19ed65a 100644
--- a/servers/slapd/back-bdb/attribute.c
+++ b/servers/slapd/back-bdb/attribute.c
@@ -39,6 +39,9 @@ bdb_attribute(
 	const char *entry_at_name = entry_at->ad_cname.bv_val;
 	AccessControlState acl_state = ACL_STATE_INIT;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 #ifdef NEW_LOGGING
 	LDAP_LOG(( "backend", LDAP_LEVEL_ARGS,
 		"bdb_attribute: gr dn: \"%s\"\n", entry_ndn->bv_val ));
@@ -65,6 +68,11 @@ bdb_attribute(
 		txn = boi->boi_txn;
 	}
 
+	if ( txn != NULL )
+		locker = TXN_ID ( txn );
+	else
+		LOCK_ID ( bdb->bi_dbenv, &locker );
+
 	if (target != NULL && dn_match(&target->e_nname, entry_ndn)) {
 		/* we already have a LOCKED copy of the entry */
 		e = target;
@@ -80,16 +88,23 @@ bdb_attribute(
 
 
 	} else {
+dn2entry_retry:
 		/* can we find entry */
-		rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0 );
+		rc = bdb_dn2entry_r( be, NULL, entry_ndn, &e, NULL, 0, locker, &lock );
 		switch( rc ) {
 		case DB_NOTFOUND:
 		case 0:
 			break;
+		case DB_LOCK_DEADLOCK:
+		case DB_LOCK_NOTGRANTED:
+			goto dn2entry_retry;
 		default:
 			if( txn != NULL ) {
 				boi->boi_err = rc;
 			}
+			else {
+				LOCK_ID_FREE( bdb->bi_dbenv, locker );
+			}
 			return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
 		}
 		if (e == NULL) {
@@ -102,6 +117,9 @@ bdb_attribute(
 				"=> bdb_attribute: cannot find entry: \"%s\"\n",
 					entry_ndn->bv_val, 0, 0 ); 
 #endif
+			if ( txn == NULL ) {
+				LOCK_ID_FREE( bdb->bi_dbenv, locker );
+			}
 			return LDAP_NO_SUCH_OBJECT; 
 		}
 		
@@ -205,7 +223,11 @@ bdb_attribute(
 return_results:
 	if( target != e ) {
 		/* free entry */
-		bdb_cache_return_entry_r(&bdb->bi_cache, e);
+		bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
+	}
+
+	if ( txn == NULL ) {
+		LOCK_ID_FREE( bdb->bi_dbenv, locker );
 	}
 
 #ifdef NEW_LOGGING
diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h
index be89b98bf30361f5165387cc92175719c878f71b..784bbc89aaa40eeffa247c368991d747d9db1dc7 100644
--- a/servers/slapd/back-bdb/back-bdb.h
+++ b/servers/slapd/back-bdb/back-bdb.h
@@ -146,21 +146,27 @@ struct bdb_op_info {
 #if DB_VERSION_MAJOR < 4
 #define LOCK_DETECT(env,f,t,a)		lock_detect(env, f, t, a)
 #define LOCK_GET(env,i,f,o,m,l)		lock_get(env, i, f, o, m, l)
+#define LOCK_PUT(env,l)			lock_put(env, l)
 #define TXN_CHECKPOINT(env,k,m,f)	txn_checkpoint(env, k, m, f)
 #define TXN_BEGIN(env,p,t,f)		txn_begin((env), p, t, f)
 #define TXN_PREPARE(txn,gid)		txn_prepare((txn), (gid))
 #define TXN_COMMIT(txn,f)			txn_commit((txn), (f))
 #define	TXN_ABORT(txn)				txn_abort((txn))
 #define TXN_ID(txn)					txn_id(txn)
+#define LOCK_ID(env, locker)		lock_id(env, locker)
+#define LOCK_ID_FREE(env, locker)	lock_id_free(env, locker)
 #else
 #define LOCK_DETECT(env,f,t,a)		(env)->lock_detect(env, f, t, a)
 #define LOCK_GET(env,i,f,o,m,l)		(env)->lock_get(env, i, f, o, m, l)
+#define LOCK_PUT(env,l)			(env)->lock_put(env, l)
 #define TXN_CHECKPOINT(env,k,m,f)	(env)->txn_checkpoint(env, k, m, f)
 #define TXN_BEGIN(env,p,t,f)		(env)->txn_begin((env), p, t, f)
 #define TXN_PREPARE(txn,g)			(txn)->prepare((txn), (g))
 #define TXN_COMMIT(txn,f)			(txn)->commit((txn), (f))
 #define TXN_ABORT(txn)				(txn)->abort((txn))
 #define TXN_ID(txn)					(txn)->id(txn)
+#define LOCK_ID(env, locker)		(env)->lock_id(env, locker)
+#define LOCK_ID_FREE(env, locker)	(env)->lock_id_free(env, locker)
 #endif
 
 LDAP_END_DECL
diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c
index ad1bcfe3bb8315648d2da15b9a6ec51412cce818..be64c5b6a8c90ca587a63b51cbf81943868bf619 100644
--- a/servers/slapd/back-bdb/bind.c
+++ b/servers/slapd/back-bdb/bind.c
@@ -40,14 +40,20 @@ bdb_bind(
 
 	AttributeDescription *password = slap_schema.si_ad_userPassword;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "bind", LDAP_LEVEL_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val ));
 #else
 	Debug( LDAP_DEBUG_ARGS, "==> bdb_bind: dn: %s\n", dn->bv_val, 0, 0);
 #endif
 
+	LOCK_ID(bdb->bi_dbenv, &locker);
+
+dn2entry_retry:
 	/* get entry */
-	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
+	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock );
 
 	switch(rc) {
 	case DB_NOTFOUND:
@@ -56,10 +62,15 @@ bdb_bind(
 	case LDAP_BUSY:
 		send_ldap_result( conn, op, LDAP_BUSY,
 			NULL, "ldap server busy", NULL, NULL );
+		LOCK_ID_FREE(bdb->bi_dbenv, locker);
 		return LDAP_BUSY;
+	case DB_LOCK_DEADLOCK:
+	case DB_LOCK_NOTGRANTED:
+		goto dn2entry_retry;
 	default:
 		send_ldap_result( conn, op, rc=LDAP_OTHER,
 			NULL, "internal error", NULL, NULL );
+		LOCK_ID_FREE(bdb->bi_dbenv, locker);
 		return rc;
 	}
 
@@ -75,7 +86,7 @@ bdb_bind(
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
 
-			bdb_cache_return_entry_r( &bdb->bi_cache, matched );
+			bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock );
 			matched = NULL;
 
 		} else {
@@ -108,6 +119,8 @@ bdb_bind(
 				NULL, NULL, NULL, NULL );
 		}
 
+		LOCK_ID_FREE(bdb->bi_dbenv, locker);
+
 		ber_bvarray_free( refs );
 		free( matched_dn );
 
@@ -274,9 +287,11 @@ bdb_bind(
 done:
 	/* free entry and reader lock */
 	if( e != NULL ) {
-		bdb_cache_return_entry_r( &bdb->bi_cache, e );
+		bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
 	}
 
+	LOCK_ID_FREE(bdb->bi_dbenv, locker);
+
 	/* front end with send result on success (rc==0) */
 	return rc;
 }
diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c
index 5038db4bc799bacf7dbe6f7982e621f379a1a0db..18854548fed61a6764105066e3f1d7348f53a697 100644
--- a/servers/slapd/back-bdb/cache.c
+++ b/servers/slapd/back-bdb/cache.c
@@ -132,6 +132,36 @@ bdb_cache_entry_private_init( Entry *e )
 	return 0;
 }
 
+int
+bdb_cache_entry_db_lock
+( DB_ENV *env, u_int32_t locker, Entry *e, int rw, u_int32_t flags, DB_LOCK *lock )
+{
+	int       rc;
+	DBT       lockobj;
+	int       db_rw;
+
+	if (rw)
+		db_rw = DB_LOCK_WRITE;
+	else
+		db_rw = DB_LOCK_READ;
+
+	lockobj.data = e->e_nname.bv_val;
+	lockobj.size = e->e_nname.bv_len;
+	rc = LOCK_GET(env, locker, flags | DB_LOCK_NOWAIT,
+					&lockobj, db_rw, lock);
+	return rc;
+}
+
+int
+bdb_cache_entry_db_unlock
+( DB_ENV *env, DB_LOCK *lock )
+{
+	int rc;
+
+	rc = LOCK_PUT ( env, lock );
+	return rc;
+}
+
 /*
  * marks an entry in CREATING state as committed, so it is really returned
  * to the cache. Otherwise an entry in CREATING state is removed.
@@ -162,8 +192,9 @@ bdb_cache_entry_private_destroy( Entry *e )
 }
 
 void
-bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
+bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
 {
+
 	ID id;
 	int refcnt, freeit = 1;
 
@@ -172,7 +203,112 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
 
 	assert( e->e_private );
 
+#if 0
 	bdb_cache_entry_rdwr_unlock(e, rw);
+#endif
+
+	id = e->e_id;
+	refcnt = --BEI(e)->bei_refcnt;
+
+	/*
+	 * if the entry is returned when in CREATING state, it is deleted
+	 * but not freed because it may belong to someone else (do_add,
+	 * for instance)
+	 */
+	if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
+		/* set lru mutex */
+		ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
+		bdb_cache_delete_entry_internal( cache, e );
+		/* free lru mutex */
+		ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
+		freeit = 0;
+		/* now the entry is in DELETED state */
+	}
+
+	if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
+		BEI(e)->bei_state = CACHE_ENTRY_READY;
+
+		/* free cache write lock */
+		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
+
+#ifdef NEW_LOGGING
+		LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+			   "bdb_unlocked_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
+			   id, rw ? "w" : "r", refcnt ));
+#else
+		Debug( LDAP_DEBUG_TRACE,
+			"====> bdb_unlocked_cache_return_entry_%s( %ld ): created (%d)\n",
+			rw ? "w" : "r", id, refcnt );
+#endif
+
+
+	} else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
+		if( refcnt > 0 ) {
+			/* free cache write lock */
+			ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
+
+#ifdef NEW_LOGGING
+			LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+				   "bdb_unlocked_cache_return_entry_rw: %ld, delete pending (%d).\n",
+				   id, refcnt ));
+#else
+			Debug( LDAP_DEBUG_TRACE,
+				"====> bdb_unlocked_cache_return_entry_%s( %ld ): delete pending (%d)\n",
+				rw ? "w" : "r", id, refcnt );
+#endif
+
+		} else {
+			bdb_cache_entry_private_destroy( e );
+			if ( freeit ) {
+				bdb_entry_return( e );
+			}
+
+			/* free cache write lock */
+			ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
+
+#ifdef NEW_LOGGING
+			LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+				   "bdb_unlocked_cache_return_entry_rw: (%ld): deleted (%d)\n",
+				   id, refcnt ));
+#else
+			Debug( LDAP_DEBUG_TRACE,
+				"====> bdb_unlocked_cache_return_entry_%s( %ld ): deleted (%d)\n",
+				rw ? "w" : "r", id, refcnt );
+#endif
+		}
+
+	} else {
+		/* free cache write lock */
+		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
+
+#ifdef NEW_LOGGING
+		LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+			   "bdb_unlocked_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
+			   id, rw ? "w": "r", refcnt ));
+#else
+		Debug( LDAP_DEBUG_TRACE,
+			"====> bdb_unlocked_cache_return_entry_%s( %ld ): returned (%d)\n",
+			rw ? "w" : "r", id, refcnt);
+#endif
+	}
+}
+
+void
+bdb_cache_return_entry_rw
+( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock )
+{
+	ID id;
+	int refcnt, freeit = 1;
+
+	/* set cache write lock */
+	ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );
+
+	assert( e->e_private );
+
+	bdb_cache_entry_db_unlock( env, lock );
+#if 0
+	bdb_cache_entry_rdwr_unlock(e, rw);
+#endif
 
 	id = e->e_id;
 	refcnt = --BEI(e)->bei_refcnt;
@@ -290,12 +426,16 @@ bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw )
  * returns:	0	entry has been created and locked
  *		1	entry already existed
  *		-1	something bad happened
+ *             other    Berkeley DB locking error code
  */
 int
 bdb_cache_add_entry_rw(
+    DB_ENV	*env,
     Cache	*cache,
     Entry	*e,
-    int		rw
+    int		rw,
+    u_int32_t	locker,
+    DB_LOCK	*lock
 )
 {
 	int	i, rc;
@@ -385,7 +525,37 @@ bdb_cache_add_entry_rw(
 		return( -1 );
 	}
 
-	bdb_cache_entry_rdwr_lock( e, rw );
+	rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock );
+	switch ( rc ) {
+	case 0 :
+		break;
+	case DB_LOCK_DEADLOCK :
+	case DB_LOCK_NOTGRANTED :
+		/* undo avl changes immediately */
+		if ( avl_delete( &cache->c_idtree, (caddr_t) e,
+			(AVL_CMP) entry_id_cmp ) == NULL ) {
+#ifdef NEW_LOGGING
+			LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+				"bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn ));
+#else
+			Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 );
+#endif
+		}
+		if ( avl_delete( &cache->c_dntree, (caddr_t) e,
+				(AVL_CMP) entry_dn_cmp ) == NULL ) {
+#ifdef NEW_LOGGING
+			LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+					"bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn ));
+#else
+			Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 );
+#endif
+		}
+		/* fall through */
+	default :
+		bdb_cache_entry_private_destroy(e);
+		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
+		return rc;
+	}
 
 	/* put the entry into 'CREATING' state */
 	/* will be marked after when entry is returned */
@@ -661,14 +831,18 @@ try_again:
 
 Entry *
 bdb_cache_find_entry_id(
+	DB_ENV	*env,
 	Cache	*cache,
 	ID				id,
-	int				rw
+	int				rw,
+	u_int32_t	locker,
+	DB_LOCK		*lock
 )
 {
 	Entry	e;
 	Entry	*ep;
 	int	count = 0;
+	int	rc;
 
 	e.e_id = id;
 
@@ -715,7 +889,13 @@ try_again:
 		}
 
 		/* acquire reader lock */
+		rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock );
+
+#if 0
 		if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
+#endif
+
+		if ( rc ) { /* will be changed to retry beyond threshold */
 			/* could not acquire entry lock...
 			 * owner cannot free as we have the cache locked.
 			 * so, unlock the cache, yield, and try again.
@@ -732,6 +912,9 @@ try_again:
 			Debug(LDAP_DEBUG_TRACE,
 				"====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n",
 				id, ep_id, state);
+			Debug(LDAP_DEBUG_TRACE,
+				"locker = %d\n",
+				locker, 0, 0);
 #endif
 
 			ldap_pvt_thread_yield();
diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c
index e9c40dcbbc4bb5b721b096f200b0a188869b359c..ac799bb62777791701da86b2cd90c090a076f781 100644
--- a/servers/slapd/back-bdb/compare.c
+++ b/servers/slapd/back-bdb/compare.c
@@ -31,8 +31,14 @@ bdb_compare(
 	const char	*text = NULL;
 	int		manageDSAit = get_manageDSAit( op );
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
+	LOCK_ID ( bdb->bi_dbenv, &locker );
+
+dn2entry_retry:
 	/* get entry */
-	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
+	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock );
 
 	switch( rc ) {
 	case DB_NOTFOUND:
@@ -41,6 +47,9 @@ bdb_compare(
 	case LDAP_BUSY:
 		text = "ldap server busy";
 		goto return_results;
+	case DB_LOCK_DEADLOCK:
+	case DB_LOCK_NOTGRANTED:
+		goto dn2entry_retry;
 	default:
 		rc = LDAP_OTHER;
 		text = "internal error";
@@ -56,7 +65,7 @@ bdb_compare(
 			refs = is_entry_referral( matched )
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
-			bdb_cache_return_entry_r( &bdb->bi_cache, matched );
+			bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lock );
 			matched = NULL;
 
 		} else {
@@ -125,8 +134,10 @@ return_results:
 done:
 	/* free entry */
 	if( e != NULL ) {
-		bdb_cache_return_entry_r( &bdb->bi_cache, e );
+		bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
 	}
 
+	LOCK_ID_FREE ( bdb->bi_dbenv, locker );
+
 	return rc;
 }
diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c
index dcaf399fafd07c9abb777f2abc130bf84a00a992..a348631cc73205f4f1564e750ddaf69f75e85d53 100644
--- a/servers/slapd/back-bdb/delete.c
+++ b/servers/slapd/back-bdb/delete.c
@@ -33,6 +33,9 @@ bdb_delete(
 	AttributeDescription *children = slap_schema.si_ad_children;
 	DB_TXN		*ltid = NULL;
 	struct bdb_op_info opinfo;
+
+	u_int32_t	locker;
+	DB_LOCK		lock;
 #if 0
 	u_int32_t	lockid;
 	DB_LOCK		lock;
@@ -49,7 +52,7 @@ bdb_delete(
 	if( 0 ) {
 retry:	/* transaction retry */
 		if( e != NULL ) {
-			bdb_cache_return_entry_w(&bdb->bi_cache, e);
+			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 		}
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "delete", LDAP_LEVEL_DETAIL1, 
@@ -87,6 +90,8 @@ retry:	/* transaction retry */
 		text = "internal error";
 		goto return_results;
 	}
+
+	locker = TXN_ID ( ltid );
 #if 0
 	lockid = TXN_ID( ltid );
 #endif
@@ -111,7 +116,7 @@ retry:	/* transaction retry */
 		}
 #endif
 		/* get parent */
-		rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0 );
+		rc = bdb_dn2entry_r( be, ltid, &pdn, &p, NULL, 0, locker, &lock );
 
 		switch( rc ) {
 		case 0:
@@ -147,7 +152,7 @@ retry:	/* transaction retry */
 		rc = access_allowed( be, conn, op, p,
 			children, NULL, ACL_WRITE, NULL );
 
-		bdb_cache_return_entry_r(&bdb->bi_cache, p);
+		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
 		p = NULL;
 
 		switch( opinfo.boi_err ) {
@@ -226,7 +231,7 @@ retry:	/* transaction retry */
 	}
 
 	/* get entry for read/modify/write */
-	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW );
+	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW, locker, &lock );
 
 	switch( rc ) {
 	case 0:
@@ -263,7 +268,7 @@ retry:	/* transaction retry */
 			refs = is_entry_referral( matched )
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
-			bdb_cache_return_entry_r(&bdb->bi_cache, matched );
+			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched);
 			matched = NULL;
 
 		} else {
@@ -465,7 +470,7 @@ return_results:
 done:
 	/* free entry */
 	if( e != NULL ) {
-		bdb_cache_return_entry_w(&bdb->bi_cache, e);
+		bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 	}
 
 	if( ltid != NULL ) {
diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c
index 00cd9efed7cea38446f909fe4af43ce29d6312a1..a6440536f7ebb662761bab2260d71ab522273371 100644
--- a/servers/slapd/back-bdb/dn2entry.c
+++ b/servers/slapd/back-bdb/dn2entry.c
@@ -25,7 +25,9 @@ bdb_dn2entry_rw(
 	Entry **e,
 	Entry **matched,
 	int flags,
-	int rw )
+	int rw,
+	u_int32_t locker,
+	DB_LOCK *lock )
 {
 	int rc;
 	ID		id, id2 = 0;
@@ -52,9 +54,9 @@ bdb_dn2entry_rw(
 	}
 
 	if( id2 == 0 ) {
-		rc = bdb_id2entry_rw( be, tid, id, e, rw );
+		rc = bdb_id2entry_rw( be, tid, id, e, rw, locker, lock );
 	} else {
-		rc = bdb_id2entry_r( be, tid, id2, matched);
+		rc = bdb_id2entry_r( be, tid, id2, matched, locker, lock );
 	}
 
 	return rc;
diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c
index bd8adc0bdc8c2deb688b4adf0a0c59f0ee3757c5..a09bc1e3f4b578dcec590e8befcd484512c263a7 100644
--- a/servers/slapd/back-bdb/filterindex.c
+++ b/servers/slapd/back-bdb/filterindex.c
@@ -65,6 +65,10 @@ bdb_filter_candidates(
 		Debug( LDAP_DEBUG_FILTER, "\tDN ONE\n", 0, 0, 0 );
 #endif
 		rc = bdb_dn2idl( be, f->f_dn, DN_ONE_PREFIX, ids );
+		if( rc == DB_NOTFOUND ) {
+			BDB_IDL_ZERO( ids );
+			rc = 0;
+		}
 		break;
 
 	case SLAPD_FILTER_DN_SUBTREE:
diff --git a/servers/slapd/back-bdb/group.c b/servers/slapd/back-bdb/group.c
index 2000de520996c7f849c70efc136ce9ac9bd2c2b1..6c2cdf11330a3c7f9035248c16555a65ffa41101 100644
--- a/servers/slapd/back-bdb/group.c
+++ b/servers/slapd/back-bdb/group.c
@@ -44,6 +44,9 @@ bdb_group(
 	const char *group_oc_name = NULL;
 	const char *group_at_name = group_at->ad_cname.bv_val;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 	if( group_oc->soc_names && group_oc->soc_names[0] ) {
 		group_oc_name = group_oc->soc_names[0];
 	} else {
@@ -76,6 +79,11 @@ bdb_group(
 		txn = boi->boi_txn;
 	}
 
+	if ( txn )
+		locker = TXN_ID( txn );
+	else
+		LOCK_ID ( bdb->bi_dbenv, &locker );
+
 	if (dn_match(&target->e_name, gr_ndn)) {
 		/* we already have a LOCKED copy of the entry */
 		e = target;
@@ -88,12 +96,18 @@ bdb_group(
 			gr_ndn->bv_val, 0, 0 );
 #endif
 	} else {
+dn2entry_retry:
 		/* can we find group entry */
-		rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0 ); 
+		rc = bdb_dn2entry_r( be, NULL, gr_ndn, &e, NULL, 0, locker, &lock ); 
 		if( rc ) {
+			if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED )
+				goto dn2entry_retry;
 			if( txn ) {
 				boi->boi_err = rc;
 			}
+			else {
+				LOCK_ID_FREE ( bdb->bi_dbenv, locker );
+			}
 			return( 1 );
 		}
 		if (e == NULL) {
@@ -106,6 +120,9 @@ bdb_group(
 				"=> bdb_group: cannot find group: \"%s\"\n",
 					gr_ndn->bv_val, 0, 0 ); 
 #endif
+			if ( txn == NULL ) {
+				LOCK_ID_FREE ( bdb->bi_dbenv, locker );
+			}
 			return( 1 );
 		}
 #ifdef NEW_LOGGING
@@ -211,7 +228,11 @@ bdb_group(
 return_results:
 	if( target != e ) {
 		/* free entry */
-		bdb_cache_return_entry_r( &bdb->bi_cache, e );
+		bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
+	}
+
+	if ( txn == NULL ) {
+		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
 	}
 
 #ifdef NEW_LOGGING
diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c
index 10ec1637a58aacd6baff8e40cd27354fbedacbc0..0a841cab21e1c7099e740d2ef8e7886d067e8133 100644
--- a/servers/slapd/back-bdb/id2entry.c
+++ b/servers/slapd/back-bdb/id2entry.c
@@ -80,13 +80,15 @@ int bdb_id2entry_rw(
 	DB_TXN *tid,
 	ID id,
 	Entry **e,
-	int rw )
+	int rw,
+	u_int32_t locker,
+	DB_LOCK *lock )
 {
 	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
 	DB *db = bdb->bi_id2entry->bdi_db;
 	DBT key, data;
 	struct berval bv;
-	int rc = 0;
+	int rc = 0, ret = 0;
 
 	*e = NULL;
 
@@ -97,7 +99,7 @@ int bdb_id2entry_rw(
 	DBTzero( &data );
 	data.flags = DB_DBT_MALLOC;
 
-	if ((*e = bdb_cache_find_entry_id(&bdb->bi_cache, id, rw)) != NULL) {
+	if ((*e = bdb_cache_find_entry_id(bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock)) != NULL) {
 		return 0;
 	}
 
@@ -121,24 +123,36 @@ int bdb_id2entry_rw(
 		ch_free( data.data );
 	}
 
-	while (rc == 0 && bdb_cache_add_entry_rw(&bdb->bi_cache, *e, rw) != 0) {
-		Entry *ee;
-		int add_loop_cnt = 0;
-		if ( (*e)->e_private != NULL ) {
-			free ((*e)->e_private);
-		}
-		(*e)->e_private = NULL;
-		if ( (ee = bdb_cache_find_entry_id
-				(&bdb->bi_cache, id, rw) ) != NULL) {
-			bdb_entry_return ( *e );
-			*e = ee;
-			return 0;
+	if ( rc == 0 ) {
+		ret = bdb_cache_add_entry_rw( bdb->bi_dbenv,
+				&bdb->bi_cache, *e, rw, locker, lock);
+		while ( ret == 1 || ret == -1 ) {
+			Entry *ee;
+			int add_loop_cnt = 0;
+			if ( (*e)->e_private != NULL ) {
+				free ((*e)->e_private);
+			}
+			(*e)->e_private = NULL;
+			if ( (ee = bdb_cache_find_entry_id
+					(bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock) ) != NULL) {
+				bdb_entry_return ( *e );
+				*e = ee;
+				return 0;
+			}
+			if ( ++add_loop_cnt == BDB_MAX_ADD_LOOP ) {
+				bdb_entry_return ( *e );
+				*e = NULL;
+				return LDAP_BUSY;
+			}
 		}
-		if ( ++add_loop_cnt == BDB_MAX_ADD_LOOP ) {
-			bdb_entry_return ( *e );
+		if ( ret != 0 ) {
+			if ( (*e)->e_private != NULL )
+				free ( (*e)->e_private );
+			bdb_entry_return( *e );
 			*e = NULL;
-			return LDAP_BUSY;
+			ch_free( data.data );
 		}
+		rc = ret;
 	}
 
 #ifdef BDB_HIER
@@ -232,7 +246,7 @@ int bdb_entry_release(
  
 	if ( slapMode == SLAP_SERVER_MODE ) {
 		/* free entry and reader or writer lock */
-		bdb_cache_return_entry_rw( &bdb->bi_cache, e, rw );
+		bdb_unlocked_cache_return_entry_rw( &bdb->bi_cache, e, rw );
 	} else {
 		if (e->e_private != NULL)
 			free (e->e_private);
diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c
index 9fece09c88f86b7b916666f4f517ae71bebcb31e..d205b60060b3b925e34da6ed69b678309afb62be 100644
--- a/servers/slapd/back-bdb/modify.c
+++ b/servers/slapd/back-bdb/modify.c
@@ -91,7 +91,6 @@ int bdb_modify_internal(
 			Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0);
 #endif
 			err = modify_replace_values( e, mod, text, textbuf, textlen );
-			assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
 			if( err != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
 				LDAP_LOG (( "modify", LDAP_LEVEL_ERR, "bdb_modify_internal: %d %s\n", err, *text ));
@@ -250,6 +249,9 @@ bdb_modify(
 	DB_TXN	*ltid = NULL;
 	struct bdb_op_info opinfo;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "modify", LDAP_LEVEL_ENTRY, "bdb_modify: %s\n", dn->bv_val ));
 #else
@@ -260,7 +262,7 @@ bdb_modify(
 retry:	/* transaction retry */
 		if( e != NULL ) {
 			bdb_cache_delete_entry(&bdb->bi_cache, e);
-			bdb_cache_return_entry_w(&bdb->bi_cache, e);
+			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 		}
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "modify", LDAP_LEVEL_DETAIL1, "bdb_modify: retrying...\n" ));
@@ -296,13 +298,15 @@ retry:	/* transaction retry */
 		goto return_results;
 	}
 
+	locker = TXN_ID ( ltid );
+
 	opinfo.boi_bdb = be;
 	opinfo.boi_txn = ltid;
 	opinfo.boi_err = 0;
 	op->o_private = &opinfo;
 
 	/* get entry */
-	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 );
+	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0, locker, &lock );
 
 	if ( rc != 0 ) {
 #ifdef NEW_LOGGING
@@ -338,7 +342,7 @@ retry:	/* transaction retry */
 			refs = is_entry_referral( matched )
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
-			bdb_cache_return_entry_r (&bdb->bi_cache, matched);
+			bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, matched);
 			matched = NULL;
 
 		} else {
@@ -464,7 +468,7 @@ done:
 	}
 
 	if( e != NULL ) {
-		bdb_cache_return_entry_w (&bdb->bi_cache, e);
+		bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e);
 	}
 	return rc;
 }
diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c
index cb1e1517ebb81f3f5bc9377d26152d5af4a8dd69..30f345c7f072ed1193e2aaef51b0eb7c6f647a2c 100644
--- a/servers/slapd/back-bdb/modrdn.c
+++ b/servers/slapd/back-bdb/modrdn.c
@@ -56,6 +56,9 @@ bdb_modrdn(
 
 	int		manageDSAit = get_manageDSAit( op );
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "modrdn", LDAP_LEVEL_ENTRY, "==>bdb_modrdn(%s,%s,%s)\n",
 		dn->bv_val,newrdn->bv_val,
@@ -78,13 +81,13 @@ bdb_modrdn(
 retry:	/* transaction retry */
 		if (e != NULL) {
 			bdb_cache_delete_entry(&bdb->bi_cache, e);
-			bdb_cache_return_entry_w(&bdb->bi_cache, e);
+			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 		}
 		if (p != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, p);
+			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
 		}
 		if (np != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, np);
+			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
 		}
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "modrdn", LDAP_LEVEL_DETAIL1, "==>bdb_modrdn: retrying...\n"));
@@ -119,13 +122,15 @@ retry:	/* transaction retry */
 		goto return_results;
 	}
 
+	locker = TXN_ID ( ltid );
+
 	opinfo.boi_bdb = be;
 	opinfo.boi_txn = ltid;
 	opinfo.boi_err = 0;
 	op->o_private = &opinfo;
 
 	/* get entry */
-	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0 );
+	rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, 0, locker, &lock );
 
 	switch( rc ) {
 	case 0:
@@ -152,7 +157,7 @@ retry:	/* transaction retry */
 			refs = is_entry_referral( matched )
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
-			bdb_cache_return_entry_r( &bdb->bi_cache, matched );
+			bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched);
 			matched = NULL;
 
 		} else {
@@ -199,7 +204,7 @@ retry:	/* transaction retry */
 		/* Make sure parent entry exist and we can write its 
 		 * children.
 		 */
-		rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0 );
+		rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0, locker, &lock );
 
 		switch( rc ) {
 		case 0:
@@ -348,7 +353,7 @@ retry:	/* transaction retry */
 			/* newSuperior == entry being moved?, if so ==> ERROR */
 			/* Get Entry with dn=newSuperior. Does newSuperior exist? */
 
-			rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0 );
+			rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0, locker, &lock );
 
 			switch( rc ) {
 			case 0:
@@ -855,17 +860,17 @@ done:
 	/* LDAP v3 Support */
 	if( np != NULL ) {
 		/* free new parent and reader lock */
-		bdb_cache_return_entry_r(&bdb->bi_cache, np);
+		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
 	}
 
 	if( p != NULL ) {
 		/* free parent and reader lock */
-		bdb_cache_return_entry_r(&bdb->bi_cache, p);
+		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
 	}
 
 	/* free entry */
 	if( e != NULL ) {
-		bdb_cache_return_entry_w( &bdb->bi_cache, e );
+		bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
 	}
 
 	if( ltid != NULL ) {
diff --git a/servers/slapd/back-bdb/operational.c b/servers/slapd/back-bdb/operational.c
index 08172b8c2d173278de42aa9669ca1114285caf58..5278c23ba3baa83ca6ed59a29f9a81223b903eab 100644
--- a/servers/slapd/back-bdb/operational.c
+++ b/servers/slapd/back-bdb/operational.c
@@ -44,9 +44,11 @@ bdb_operational(
 
 	if( 0 ) {
 retry:	/* transaction retry */
+#if 0
 		if( e != NULL ) {
-			bdb_cache_return_entry_w(&bdb->bi_cache, e);
+			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 		}
+#endif
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "operational", LDAP_LEVEL_DETAIL1,
 			"=> bdb_operational: retrying...\n" ));
diff --git a/servers/slapd/back-bdb/passwd.c b/servers/slapd/back-bdb/passwd.c
index 0e05443926b91970ecebf9e9b951c6c76ed4cb32..25f0c654ed7513a2184c6684b29b49dc0af7abc9 100644
--- a/servers/slapd/back-bdb/passwd.c
+++ b/servers/slapd/back-bdb/passwd.c
@@ -41,6 +41,9 @@ bdb_exop_passwd(
 	struct berval dn;
 	struct berval ndn;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 	assert( reqoid != NULL );
 	assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 );
 
@@ -109,7 +112,7 @@ bdb_exop_passwd(
 retry:	/* transaction retry */
 		if ( e != NULL ) {
 			bdb_cache_delete_entry(&bdb->bi_cache, e);
-			bdb_cache_return_entry_w(&bdb->bi_cache, e);
+			bdb_cache_return_entry_w(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 		}
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "passwd", LDAP_LEVEL_DETAIL1, "bdb_exop_passwd: retrying...\n" ));
@@ -144,13 +147,15 @@ retry:	/* transaction retry */
 		goto done;
 	}
 
+	locker = TXN_ID ( ltid );
+
 	opinfo.boi_bdb = be;
 	opinfo.boi_txn = ltid;
 	opinfo.boi_err = 0;
 	op->o_private = &opinfo;
 
 	/* get entry */
-	rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 );
+	rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 , locker, &lock);
 
 	switch(rc) {
 	case DB_LOCK_DEADLOCK:
@@ -256,7 +261,7 @@ retry:	/* transaction retry */
 
 done:
 	if( e != NULL ) {
-		bdb_cache_return_entry_w( &bdb->bi_cache, e );
+		bdb_cache_return_entry_w( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
 	}
 		
 	if( hash.bv_val != NULL ) {
diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h
index cdea9803e190411fc29f2d066bf0051eca884bc4..f5c7af92fd366317f5c380ea9e4a9ece9c14d031 100644
--- a/servers/slapd/back-bdb/proto-bdb.h
+++ b/servers/slapd/back-bdb/proto-bdb.h
@@ -58,9 +58,9 @@ bdb_db_cache(
  * dn2entry.c
  */
 int bdb_dn2entry_rw LDAP_P(( BackendDB *be, DB_TXN *tid,
-       struct berval *dn, Entry **e, Entry **matched, int flags, int rw ));
-#define bdb_dn2entry_r(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0)
-#define bdb_dn2entry_w(be, tid, dn, e, m, f) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1)
+       struct berval *dn, Entry **e, Entry **matched, int flags, int rw , u_int32_t locker, DB_LOCK *lock));
+#define bdb_dn2entry_r(be, tid, dn, e, m, f, locker, lock) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 0, locker, lock)
+#define bdb_dn2entry_w(be, tid, dn, e, m, f, locker, lock) bdb_dn2entry_rw((be), (tid), (dn), (e), (m), (f), 1, locker, lock)
 
 /*
  * dn2id.c
@@ -152,9 +152,11 @@ int bdb_id2entry_rw(
 	DB_TXN *tid,
 	ID id,
 	Entry **e,
-	int rw );
-#define bdb_id2entry_r(be, tid, id, e)      bdb_id2entry_rw((be), (tid), (id), (e), 0)
-#define bdb_id2entry_w(be, tid, id, e)      bdb_id2entry_rw((be), (tid), (id), (e), 1)
+	int rw,
+	u_int32_t locker,
+	DB_LOCK *lock );
+#define bdb_id2entry_r(be, tid, id, e, locker, lock)      bdb_id2entry_rw((be), (tid), (id), (e), 0, locker, lock)
+#define bdb_id2entry_w(be, tid, id, e, locker, lock)      bdb_id2entry_rw((be), (tid), (id), (e), 1, locker, lock)
 
 void bdb_entry_free ( Entry *e );
 
@@ -301,13 +303,19 @@ BI_op_extended bdb_exop_passwd;
  */
 
 void bdb_cache_entry_commit( Entry *e );
-void bdb_cache_return_entry_rw( Cache *cache, Entry *e, int rw );
-#define bdb_cache_return_entry_r(c, e) bdb_cache_return_entry_rw((c), (e), 0)
-#define bdb_cache_return_entry_w(c, e) bdb_cache_return_entry_rw((c), (e), 1)
+void bdb_cache_return_entry_rw( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock );
+#define bdb_cache_return_entry_r(env, c, e, l) bdb_cache_return_entry_rw((env), (c), (e), 0, (l))
+#define bdb_cache_return_entry_w(env, c, e, l) bdb_cache_return_entry_rw((env), (c), (e), 1, (l))
+void bdb_unlocked_cache_return_entry_rw( Cache *cache, Entry *e, int rw );
+#define bdb_unlocked_cache_return_entry_r( c, e ) bdb_unlocked_cache_return_entry_rw((c), (e), 0)
+#define bdb_unlocked_cache_return_entry_w( c, e ) bdb_unlocked_cache_return_entry_rw((c), (e), 1)
 int bdb_cache_add_entry_rw(
-       Cache   *cache,
-       Entry   *e,
-       int     rw
+	DB_ENV	*env,
+	Cache   *cache,
+	Entry   *e,
+	int     rw,
+	u_int32_t locker,
+	DB_LOCK	*lock
 );
 int bdb_cache_update_entry(
        Cache   *cache,
@@ -319,9 +327,12 @@ ID bdb_cache_find_entry_ndn2id(
        struct berval   *ndn
 );
 Entry* bdb_cache_find_entry_id(
-       Cache   *cache,
-       ID      id,
-       int     rw
+	DB_ENV		*env,
+	Cache		*cache,
+	ID		id,
+	int		rw,
+	u_int32_t	locker,
+	DB_LOCK		*lock
 );
 int bdb_cache_delete_entry(
        Cache   *cache,
diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c
index 3517492c7945b8c24374ec5a254258689bab207d..4d60f68d0e83030029b78329c7c41b3424ea4b3f 100644
--- a/servers/slapd/back-bdb/referral.c
+++ b/servers/slapd/back-bdb/referral.c
@@ -26,6 +26,9 @@ bdb_referrals(
 	Entry *e = NULL;
 	Entry *matched = NULL;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 	if( op->o_tag == LDAP_REQ_SEARCH ) {
 		/* let search take care of itself */
 		return rc;
@@ -36,8 +39,11 @@ bdb_referrals(
 		return rc;
 	} 
 
+	LOCK_ID ( bdb->bi_dbenv, &locker );
+
+dn2entry_retry:
 	/* get entry */
-	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0 );
+	rc = bdb_dn2entry_r( be, NULL, ndn, &e, &matched, 0, locker, &lock );
 
 	switch(rc) {
 	case DB_NOTFOUND:
@@ -46,14 +52,18 @@ bdb_referrals(
 		break;
 	case LDAP_BUSY:
 		if (e != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, e);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 		}
 		if (matched != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 		}
 		send_ldap_result( conn, op, LDAP_BUSY,
 			NULL, "ldap server busy", NULL, NULL );
+		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
 		return LDAP_BUSY;
+	case DB_LOCK_DEADLOCK:
+	case DB_LOCK_NOTGRANTED:
+		goto dn2entry_retry;
 	default:
 #ifdef NEW_LOGGING
 		LDAP_LOG (( "referral", LDAP_LEVEL_ERR,
@@ -65,13 +75,14 @@ bdb_referrals(
 			db_strerror(rc), rc, 0 ); 
 #endif
 		if (e != NULL) {
-                        bdb_cache_return_entry_r(&bdb->bi_cache, e);
+                        bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 		}
                 if (matched != NULL) {
-                        bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+                        bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 		}
 		send_ldap_result( conn, op, rc=LDAP_OTHER,
 			NULL, "internal error", NULL, NULL );
+		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
 		return rc;
 	}
 
@@ -97,7 +108,7 @@ bdb_referrals(
 				refs = get_entry_referrals( be, conn, op, matched );
 			}
 
-			bdb_cache_return_entry_r (&bdb->bi_cache, matched);
+			bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 			matched = NULL;
 		} else if ( default_referral != NULL ) {
 			rc = LDAP_OTHER;
@@ -116,6 +127,7 @@ bdb_referrals(
 				NULL, NULL );
 		}
 
+		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
 		free( matched_dn );
 		return rc;
 	}
@@ -148,6 +160,7 @@ bdb_referrals(
 		ber_bvarray_free( refs );
 	}
 
-	bdb_cache_return_entry_r(&bdb->bi_cache, e);
+	bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
+	LOCK_ID_FREE ( bdb->bi_dbenv, locker );
 	return rc;
 }
diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c
index 9887feb342c6515c777c11af87c1e1cb0a8d31c0..a68e17fb646e90400b4058bb1f660c30aea5f04b 100644
--- a/servers/slapd/back-bdb/search.c
+++ b/servers/slapd/back-bdb/search.c
@@ -59,6 +59,9 @@ bdb_search(
 	struct slap_limits_set *limit = NULL;
 	int isroot = 0;
 
+	u_int32_t	locker;
+	DB_LOCK		lock;
+
 #ifdef NEW_LOGGING
 	LDAP_LOG (( "search", LDAP_LEVEL_ENTRY,"bdb_back_search\n"));
 #else
@@ -68,6 +71,8 @@ bdb_search(
 
 	manageDSAit = get_manageDSAit( op );
 
+	LOCK_ID (bdb->bi_dbenv, &locker );
+
 	if ( nbase->bv_len == 0 ) {
 		/* DIT root special case */
 		e = (Entry *) &slap_entry_root;
@@ -81,7 +86,8 @@ bdb_search(
 	} else
 #endif
 	{
-		rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0 );
+dn2entry_retry:
+		rc = bdb_dn2entry_r( be, NULL, nbase, &e, &matched, 0, locker, &lock );
 	}
 
 	switch(rc) {
@@ -90,23 +96,28 @@ bdb_search(
 		break;
 	case LDAP_BUSY:
 		if (e != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, e);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 		}
 		if (matched != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 		}
 		send_ldap_result( conn, op, LDAP_BUSY,
 			NULL, "ldap server busy", NULL, NULL );
+		LOCK_ID_FREE (bdb->bi_dbenv, locker );
 		return LDAP_BUSY;
+	case DB_LOCK_DEADLOCK:
+	case DB_LOCK_NOTGRANTED:
+		goto dn2entry_retry;
 	default:
 		if (e != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, e);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 		}
 		if (matched != NULL) {
-			bdb_cache_return_entry_r(&bdb->bi_cache, matched);
+			bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 		}
 		send_ldap_result( conn, op, rc=LDAP_OTHER,
 			NULL, "internal error", NULL, NULL );
+		LOCK_ID_FREE (bdb->bi_dbenv, locker );
 		return rc;
 	}
 
@@ -116,14 +127,13 @@ bdb_search(
 
 		if ( matched != NULL ) {
 			BerVarray erefs;
-
 			ber_dupbv( &matched_dn, &matched->e_name );
 
 			erefs = is_entry_referral( matched )
 				? get_entry_referrals( be, conn, op, matched )
 				: NULL;
 
-			bdb_cache_return_entry_r (&bdb->bi_cache, matched);
+			bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, matched, &lock);
 			matched = NULL;
 
 			if( erefs ) {
@@ -140,6 +150,7 @@ bdb_search(
 		send_ldap_result( conn, op,	rc=LDAP_REFERRAL ,
 			matched_dn.bv_val, text, refs, NULL );
 
+		LOCK_ID_FREE (bdb->bi_dbenv, locker );
 		if ( refs ) ber_bvarray_free( refs );
 		if ( matched_dn.bv_val ) ber_memfree( matched_dn.bv_val );
 		return rc;
@@ -154,7 +165,7 @@ bdb_search(
 		erefs = get_entry_referrals( be, conn, op, e );
 		refs = NULL;
 
-		bdb_cache_return_entry_r( &bdb->bi_cache, e );
+		bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
 		e = NULL;
 
 		if( erefs ) {
@@ -175,6 +186,7 @@ bdb_search(
 			refs ? NULL : "bad referral object",
 			refs, NULL );
 
+		LOCK_ID_FREE (bdb->bi_dbenv, locker );
 		ber_bvarray_free( refs );
 		ber_memfree( matched_dn.bv_val );
 		return 1;
@@ -270,7 +282,7 @@ bdb_search(
 	cursor = e->e_id == NOID ? 1 : e->e_id;
 
 	if ( e != &slap_entry_root ) {
-		bdb_cache_return_entry_r(&bdb->bi_cache, e);
+		bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 	}
 	e = NULL;
 
@@ -320,13 +332,17 @@ bdb_search(
 			goto done;
 		}
 
+id2entry_retry:
 		/* get the entry with reader lock */
-		rc = bdb_id2entry_r( be, NULL, id, &e );
+		rc = bdb_id2entry_r( be, NULL, id, &e, locker, &lock );
 
 		if (rc == LDAP_BUSY) {
 			send_ldap_result( conn, op, rc=LDAP_BUSY,
 				NULL, "ldap server busy", NULL, NULL );
 			goto done;
+
+		} else if ( rc == DB_LOCK_DEADLOCK || rc == DB_LOCK_NOTGRANTED ) {
+			goto id2entry_retry;	
 		}
 
 		if ( e == NULL ) {
@@ -416,18 +432,49 @@ bdb_search(
 		if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
 			is_entry_referral( e ) )
 		{
-			BerVarray erefs = get_entry_referrals(
-				be, conn, op, e );
-			BerVarray refs = referral_rewrite( erefs,
-				&e->e_name, NULL,
-				scope == LDAP_SCOPE_SUBTREE 
-					? LDAP_SCOPE_SUBTREE
-					: LDAP_SCOPE_BASE );
+			struct berval	dn;
 
-			send_search_reference( be, conn, op,
-				e, refs, NULL, &v2refs );
+			/* check scope */
+			if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
+				if ( !be_issuffix( be, &e->e_nname ) ) {
+					dnParent( &e->e_nname, &dn );
+					scopeok = dn_match( &dn, &realbase );
+				} else {
+					scopeok = (realbase.bv_len == 0);
+				}
 
-			ber_bvarray_free( refs );
+			} else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
+				scopeok = dnIsSuffix( &e->e_nname, &realbase );
+
+			} else {
+				scopeok = 1;
+			}
+
+			if( scopeok ) {
+				BerVarray erefs = get_entry_referrals(
+					be, conn, op, e );
+				BerVarray refs = referral_rewrite( erefs,
+					&e->e_name, NULL,
+					scope == LDAP_SCOPE_SUBTREE
+						? LDAP_SCOPE_SUBTREE
+						: LDAP_SCOPE_BASE );
+
+				send_search_reference( be, conn, op,
+					e, refs, NULL, &v2refs );
+
+				ber_bvarray_free( refs );
+
+			} else {
+#ifdef NEW_LOGGING
+				LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2,
+					"bdb_search: candidate referral %ld scope not okay\n",
+					id ));
+#else
+				Debug( LDAP_DEBUG_TRACE,
+					"bdb_search: candidate referral %ld scope not okay\n",
+					id, 0, 0 );
+#endif
+			}
 
 			goto loop_continue;
 		}
@@ -456,7 +503,7 @@ bdb_search(
 			if ( scopeok ) {
 				/* check size limit */
 				if ( --slimit == -1 ) {
-					bdb_cache_return_entry_r (&bdb->bi_cache, e);
+					bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 					e = NULL;
 					send_search_result( conn, op,
 						rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
@@ -481,7 +528,7 @@ bdb_search(
 					case 1:		/* entry not sent */
 						break;
 					case -1:	/* connection closed */
-						bdb_cache_return_entry_r(&bdb->bi_cache, e);
+						bdb_cache_return_entry_r(bdb->bi_dbenv, &bdb->bi_cache, e, &lock);
 						e = NULL;
 						rc = LDAP_OTHER;
 						goto done;
@@ -509,7 +556,7 @@ bdb_search(
 loop_continue:
 		if( e != NULL ) {
 			/* free reader lock */
-                        bdb_cache_return_entry_r ( &bdb->bi_cache, e );
+                        bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e , &lock);
                         e = NULL;
 		}
 
@@ -524,9 +571,11 @@ loop_continue:
 done:
 	if( e != NULL ) {
 		/* free reader lock */
-		bdb_cache_return_entry_r ( &bdb->bi_cache, e );
+		bdb_cache_return_entry_r ( bdb->bi_dbenv, &bdb->bi_cache, e, &lock );
 	}
 
+	LOCK_ID_FREE (bdb->bi_dbenv, locker );
+
 	if( v2refs ) ber_bvarray_free( v2refs );
 	if( realbase.bv_val ) ch_free( realbase.bv_val );
 
diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c
index 3dc4cdbcf1baff1e096801430229fbf0868d2233..137734c104b8d3a3d2fb8557cd4d137c911d21e1 100644
--- a/servers/slapd/daemon.c
+++ b/servers/slapd/daemon.c
@@ -490,13 +490,15 @@ static int slap_get_listener_addresses(
 
 		freeaddrinfo(res);
 #else
+		int i, n = 1;
 		struct in_addr in;
+		struct hostent *he = NULL;
 
 		if ( host == NULL ) {
 			in.s_addr = htonl(INADDR_ANY);
 
 		} else if ( !inet_aton( host, &in ) ) {
-			struct hostent *he = gethostbyname( host );
+			he = gethostbyname( host );
 			if( he == NULL ) {
 #ifdef NEW_LOGGING
 				LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
@@ -508,25 +510,30 @@ static int slap_get_listener_addresses(
 #endif
 				return -1;
 			}
-			AC_MEMCPY( &in, he->h_addr, sizeof( in ) );
+			for (n = 0; he->h_addr_list[n]; n++) ;
 		}
 
-		*sal = ch_malloc(2 * sizeof(void *));
+		*sal = ch_malloc((n+1) * sizeof(void *));
 		if (*sal == NULL) {
 			return -1;
 		}
 
 		sap = *sal;
-		*sap = ch_malloc(sizeof(struct sockaddr_in));
-		if (*sap == NULL) {
-			goto errexit;
+		for ( i = 0; i<n; i++ ) {
+			sap[i] = ch_malloc(sizeof(struct sockaddr_in));
+			if (*sap == NULL) {
+				goto errexit;
+			}
+			(void)memset( (void *)sap[i], '\0', sizeof(struct sockaddr_in) );
+			sap[i]->sa_family = AF_INET;
+			((struct sockaddr_in *)sap[i])->sin_port = htons(port);
+			if (he) {
+				AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, he->h_addr_list[i], sizeof(struct in_addr) );
+			} else {
+				AC_MEMCPY( &((struct sockaddr_in *)sap[i])->sin_addr, &in, sizeof(struct in_addr) );
+			}
 		}
-		sap[1] = NULL;
-
-		(void)memset( (void *)*sap, '\0', sizeof(struct sockaddr_in) );
-		(*sap)->sa_family = AF_INET;
-		((struct sockaddr_in *)*sap)->sin_port = htons(port);
-		((struct sockaddr_in *)*sap)->sin_addr = in;
+		sap[i] = NULL;
 #endif
 	}
 
@@ -537,10 +544,13 @@ errexit:
 	return -1;
 }
 
-static Listener * slap_open_listener(
-	const char* url )
+static int slap_open_listener(
+	const char* url,
+	int *listeners,
+	int *cur
+	)
 {
-	int	tmp, rc;
+	int	num, tmp, rc;
 	Listener l;
 	Listener *li;
 	LDAPURLDesc *lud;
@@ -565,7 +575,7 @@ static Listener * slap_open_listener(
 			"daemon: listen URL \"%s\" parse error=%d\n",
 			url, rc, 0 );
 #endif
-		return NULL;
+		return rc;
 	}
 
 #ifndef HAVE_TLS
@@ -580,7 +590,7 @@ static Listener * slap_open_listener(
 			url, 0, 0 );
 #endif
 		ldap_free_urldesc( lud );
-		return NULL;
+		return -1;
 	}
 
 	if(! lud->lud_port ) {
@@ -620,7 +630,7 @@ static Listener * slap_open_listener(
 			url, 0, 0);
 #endif
 		ldap_free_urldesc( lud );
-		return NULL;
+		return -1;
 #endif
 	} else {
 #ifdef LDAP_CONNECTIONLESS
@@ -637,7 +647,16 @@ static Listener * slap_open_listener(
 
 	ldap_free_urldesc( lud );
 	if ( err ) {
-		return NULL;
+		return -1;
+	}
+
+	/* If we got more than one address returned, we need to make space
+	 * for it in the slap_listeners array.
+	 */
+	for ( num=0; sal[num]; num++ );
+	if ( num > 1 ) {
+		*listeners += num-1;
+		slap_listeners = ch_realloc( slap_listeners, (*listeners + 1) * sizeof(Listener *) );
 	}
 
 	psal = sal;
@@ -732,9 +751,8 @@ static Listener * slap_open_listener(
 #endif
 		}
 
-		if (!bind(l.sl_sd, *sal, addrlen))
-			break;
-		err = sock_errno();
+		if (bind(l.sl_sd, *sal, addrlen)) {
+			err = sock_errno();
 #ifdef NEW_LOGGING
 		LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
 			   "slap_open_listener: bind(%ld) failed errno=%d (%s)\n",
@@ -743,21 +761,10 @@ static Listener * slap_open_listener(
 		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n",
 		       (long) l.sl_sd, err, sock_errstr(err) );
 #endif
-		tcp_close( l.sl_sd );
-		sal++;
-	} /* while ( *sal != NULL ) */
-
-	if ( *sal == NULL ) {
-#ifdef NEW_LOGGING
-		LDAP_LOG(( "connection", LDAP_LEVEL_INFO,
-			   "slap_open_listener: bind(%ld) failed.\n", (long)l.sl_sd ));
-#else
-		Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed\n",
-			(long) l.sl_sd, 0, 0 );
-#endif
-		slap_free_listener_addresses(psal);
-		return NULL;
-	}
+			tcp_close( l.sl_sd );
+			sal++;
+			continue;
+		}
 
 	switch ( (*sal)->sa_family ) {
 #ifdef LDAP_PF_LOCAL
@@ -775,7 +782,7 @@ static Listener * slap_open_listener(
 #endif
 			tcp_close( l.sl_sd );
 			slap_free_listener_addresses(psal);
-			return NULL;
+			return -1;
 		}
 		l.sl_name = ch_malloc( strlen(addr) + sizeof("PATH=") );
 		sprintf( l.sl_name, "PATH=%s", addr );
@@ -821,20 +828,27 @@ static Listener * slap_open_listener(
 		break;
 	}
 
-	slap_free_listener_addresses(psal);
-
+	AC_MEMCPY(&l.sl_sa, *sal, addrlen);
 	l.sl_url = ch_strdup( url );
 	li = ch_malloc( sizeof( Listener ) );
 	*li = l;
+	slap_listeners[*cur] = li;
+	(*cur)++;
+	sal++;
+
+	} /* while ( *sal != NULL ) */
+
+	slap_free_listener_addresses(psal);
+
 
 #ifdef NEW_LOGGING
 	LDAP_LOG(( "connection", LDAP_LEVEL_RESULTS,
-		   "slap_open_listener: daemon initialzed %s\n", l.sl_url ));
+		   "slap_open_listener: daemon initialized %s\n", l.sl_url ));
 #else
 	Debug( LDAP_DEBUG_TRACE, "daemon: initialized %s\n",
 		l.sl_url, 0, 0 );
 #endif
-	return li;
+	return 0;
 }
 
 static int sockinit(void);
@@ -842,7 +856,7 @@ static int sockdestroy(void);
 
 int slapd_daemon_init( const char *urls )
 {
-	int i, rc;
+	int i, j, n, rc;
 	char **u;
 
 #ifdef NEW_LOGGING
@@ -938,15 +952,13 @@ int slapd_daemon_init( const char *urls )
 #endif
 	slap_listeners = ch_malloc( (i+1)*sizeof(Listener *) );
 
-	for(i = 0; u[i] != NULL; i++ ) {
-		slap_listeners[i] = slap_open_listener( u[i] );
-
-		if( slap_listeners[i] == NULL ) {
+	for(n = 0, j = 0; u[n]; n++ ) {
+		if ( slap_open_listener( u[n], &i, &j ) ) {
 			charray_free( u );
 			return -1;
 		}
 	}
-	slap_listeners[i] = NULL;
+	slap_listeners[j] = NULL;
 
 #ifdef NEW_LOGGING
 	LDAP_LOG(( "connection", LDAP_LEVEL_DETAIL1,
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 1437f35cc4279e7dcde36f81f143bb0a8752305b..a4b02c75bd730eb2011c75cc7dca46db56a35fdf 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -579,6 +579,8 @@ struct slap_internal_schema {
 	AttributeDescription *si_ad_modifyTimestamp;
 	AttributeDescription *si_ad_hasSubordinates;
 	AttributeDescription *si_ad_subschemaSubentry;
+	AttributeDescription *si_ad_entryUUID;
+	AttributeDescription *si_ad_entryCSN;
 
 	/* root DSE attribute descriptions */
 	AttributeDescription *si_ad_altServer;