[Pkg-openldap-devel] r1243 - in openldap/trunk: . build clients/tools contrib contrib/ldapc++/src contrib/slapd-modules contrib/slapd-modules/acl contrib/slapd-modules/addpartial contrib/slapd-modules/allop contrib/slapd-modules/autogroup contrib/slapd-modules/cloak contrib/slapd-modules/dsaschema contrib/slapd-modules/nops contrib/slapd-modules/nssov contrib/slapd-modules/passwd contrib/slapd-modules/passwd/sha2 contrib/slapd-modules/proxyOld contrib/slapd-modules/smbk5pwd contrib/slapd-tools contrib/slapi-plugins/addrdnvalues debian doc/guide/admin doc/man/man1 doc/man/man3 doc/man/man5 include include/ac libraries/liblber libraries/libldap libraries/libldap_r libraries/liblutil servers/slapd servers/slapd/back-bdb servers/slapd/back-ldap servers/slapd/back-meta servers/slapd/back-monitor servers/slapd/back-ndb servers/slapd/back-relay servers/slapd/back-sql servers/slapd/overlays servers/slapd/slapi tests tests/data tests/scripts

vorlon at alioth.debian.org vorlon at alioth.debian.org
Wed Sep 23 17:57:38 UTC 2009


Author: vorlon
Date: 2009-09-23 17:57:37 +0000 (Wed, 23 Sep 2009)
New Revision: 1243

Added:
   openldap/trunk/contrib/slapd-modules/allowed/
   openldap/trunk/doc/man/man5/slapo-sssvlv.5
   openldap/trunk/servers/slapd/overlays/sssvlv.c
Removed:
   openldap/trunk/contrib/slapd-modules/addpartial/COPYRIGHT
   openldap/trunk/contrib/slapd-modules/addpartial/LICENSE
   openldap/trunk/contrib/slapd-modules/autogroup/COPYRIGHT
Modified:
   openldap/trunk/CHANGES
   openldap/trunk/build/version.var
   openldap/trunk/clients/tools/common.c
   openldap/trunk/clients/tools/common.h
   openldap/trunk/clients/tools/ldapcompare.c
   openldap/trunk/clients/tools/ldapdelete.c
   openldap/trunk/clients/tools/ldapexop.c
   openldap/trunk/clients/tools/ldapmodify.c
   openldap/trunk/clients/tools/ldapmodrdn.c
   openldap/trunk/clients/tools/ldapsearch.c
   openldap/trunk/configure
   openldap/trunk/configure.in
   openldap/trunk/contrib/README
   openldap/trunk/contrib/ldapc++/src/SaslInteractionHandler.cpp
   openldap/trunk/contrib/slapd-modules/acl/README
   openldap/trunk/contrib/slapd-modules/acl/posixgroup.c
   openldap/trunk/contrib/slapd-modules/addpartial/README
   openldap/trunk/contrib/slapd-modules/addpartial/addpartial-overlay.c
   openldap/trunk/contrib/slapd-modules/allop/README
   openldap/trunk/contrib/slapd-modules/autogroup/README
   openldap/trunk/contrib/slapd-modules/autogroup/autogroup.c
   openldap/trunk/contrib/slapd-modules/cloak/cloak.c
   openldap/trunk/contrib/slapd-modules/cloak/slapo-cloak.5
   openldap/trunk/contrib/slapd-modules/dsaschema/dsaschema.c
   openldap/trunk/contrib/slapd-modules/nops/nops.c
   openldap/trunk/contrib/slapd-modules/nssov/Makefile
   openldap/trunk/contrib/slapd-modules/nssov/README
   openldap/trunk/contrib/slapd-modules/nssov/alias.c
   openldap/trunk/contrib/slapd-modules/nssov/ether.c
   openldap/trunk/contrib/slapd-modules/nssov/group.c
   openldap/trunk/contrib/slapd-modules/nssov/host.c
   openldap/trunk/contrib/slapd-modules/nssov/ldapns.schema
   openldap/trunk/contrib/slapd-modules/nssov/netgroup.c
   openldap/trunk/contrib/slapd-modules/nssov/network.c
   openldap/trunk/contrib/slapd-modules/nssov/nssov.c
   openldap/trunk/contrib/slapd-modules/nssov/nssov.h
   openldap/trunk/contrib/slapd-modules/nssov/pam.c
   openldap/trunk/contrib/slapd-modules/nssov/passwd.c
   openldap/trunk/contrib/slapd-modules/nssov/protocol.c
   openldap/trunk/contrib/slapd-modules/nssov/rpc.c
   openldap/trunk/contrib/slapd-modules/nssov/service.c
   openldap/trunk/contrib/slapd-modules/nssov/shadow.c
   openldap/trunk/contrib/slapd-modules/passwd/README
   openldap/trunk/contrib/slapd-modules/passwd/kerberos.c
   openldap/trunk/contrib/slapd-modules/passwd/netscape.c
   openldap/trunk/contrib/slapd-modules/passwd/radius.c
   openldap/trunk/contrib/slapd-modules/passwd/sha2/README
   openldap/trunk/contrib/slapd-modules/passwd/sha2/slapd-sha2.c
   openldap/trunk/contrib/slapd-modules/proxyOld/Makefile
   openldap/trunk/contrib/slapd-modules/proxyOld/README
   openldap/trunk/contrib/slapd-modules/proxyOld/proxyOld.c
   openldap/trunk/contrib/slapd-modules/smbk5pwd/Makefile
   openldap/trunk/contrib/slapd-modules/smbk5pwd/README
   openldap/trunk/contrib/slapd-modules/smbk5pwd/smbk5pwd.c
   openldap/trunk/contrib/slapd-tools/README
   openldap/trunk/contrib/slapd-tools/statslog
   openldap/trunk/contrib/slapi-plugins/addrdnvalues/README
   openldap/trunk/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c
   openldap/trunk/debian/changelog
   openldap/trunk/debian/rules
   openldap/trunk/doc/guide/admin/guide.html
   openldap/trunk/doc/guide/admin/overlays.sdf
   openldap/trunk/doc/man/man1/ldapsearch.1
   openldap/trunk/doc/man/man3/ldap_get_option.3
   openldap/trunk/doc/man/man3/ldap_open.3
   openldap/trunk/doc/man/man5/slapd-bdb.5
   openldap/trunk/doc/man/man5/slapd-config.5
   openldap/trunk/doc/man/man5/slapd.conf.5
   openldap/trunk/doc/man/man5/slapo-pcache.5
   openldap/trunk/include/ac/unistd.h
   openldap/trunk/include/lber.h
   openldap/trunk/include/ldap.h
   openldap/trunk/include/portable.hin
   openldap/trunk/libraries/liblber/bprint.c
   openldap/trunk/libraries/liblber/decode.c
   openldap/trunk/libraries/liblber/encode.c
   openldap/trunk/libraries/liblber/io.c
   openldap/trunk/libraries/liblber/lber-int.h
   openldap/trunk/libraries/libldap/cyrus.c
   openldap/trunk/libraries/libldap/error.c
   openldap/trunk/libraries/libldap/init.c
   openldap/trunk/libraries/libldap/ldap-int.h
   openldap/trunk/libraries/libldap/options.c
   openldap/trunk/libraries/libldap/os-ip.c
   openldap/trunk/libraries/libldap/os-local.c
   openldap/trunk/libraries/libldap/tls_g.c
   openldap/trunk/libraries/libldap/tls_m.c
   openldap/trunk/libraries/libldap/tls_o.c
   openldap/trunk/libraries/libldap/utf-8-conv.c
   openldap/trunk/libraries/libldap_r/thr_debug.c
   openldap/trunk/libraries/liblutil/getpass.c
   openldap/trunk/libraries/liblutil/passwd.c
   openldap/trunk/servers/slapd/aclparse.c
   openldap/trunk/servers/slapd/ad.c
   openldap/trunk/servers/slapd/back-bdb/back-bdb.h
   openldap/trunk/servers/slapd/back-bdb/cache.c
   openldap/trunk/servers/slapd/back-bdb/config.c
   openldap/trunk/servers/slapd/back-bdb/idl.c
   openldap/trunk/servers/slapd/back-bdb/init.c
   openldap/trunk/servers/slapd/back-bdb/monitor.c
   openldap/trunk/servers/slapd/back-bdb/search.c
   openldap/trunk/servers/slapd/back-ldap/back-ldap.h
   openldap/trunk/servers/slapd/back-ldap/bind.c
   openldap/trunk/servers/slapd/back-ldap/chain.c
   openldap/trunk/servers/slapd/back-ldap/init.c
   openldap/trunk/servers/slapd/back-ldap/proto-ldap.h
   openldap/trunk/servers/slapd/back-ldap/search.c
   openldap/trunk/servers/slapd/back-ldap/unbind.c
   openldap/trunk/servers/slapd/back-meta/back-meta.h
   openldap/trunk/servers/slapd/back-meta/bind.c
   openldap/trunk/servers/slapd/back-meta/config.c
   openldap/trunk/servers/slapd/back-meta/conn.c
   openldap/trunk/servers/slapd/back-meta/search.c
   openldap/trunk/servers/slapd/back-meta/unbind.c
   openldap/trunk/servers/slapd/back-monitor/back-monitor.h
   openldap/trunk/servers/slapd/back-monitor/database.c
   openldap/trunk/servers/slapd/back-monitor/init.c
   openldap/trunk/servers/slapd/back-monitor/proto-back-monitor.h
   openldap/trunk/servers/slapd/back-ndb/init.cpp
   openldap/trunk/servers/slapd/back-ndb/search.cpp
   openldap/trunk/servers/slapd/back-relay/back-relay.h
   openldap/trunk/servers/slapd/back-relay/init.c
   openldap/trunk/servers/slapd/back-relay/op.c
   openldap/trunk/servers/slapd/back-sql/entry-id.c
   openldap/trunk/servers/slapd/back-sql/search.c
   openldap/trunk/servers/slapd/backend.c
   openldap/trunk/servers/slapd/backover.c
   openldap/trunk/servers/slapd/bconfig.c
   openldap/trunk/servers/slapd/config.c
   openldap/trunk/servers/slapd/config.h
   openldap/trunk/servers/slapd/connection.c
   openldap/trunk/servers/slapd/controls.c
   openldap/trunk/servers/slapd/daemon.c
   openldap/trunk/servers/slapd/dn.c
   openldap/trunk/servers/slapd/entry.c
   openldap/trunk/servers/slapd/filter.c
   openldap/trunk/servers/slapd/modify.c
   openldap/trunk/servers/slapd/overlays/Makefile.in
   openldap/trunk/servers/slapd/overlays/dds.c
   openldap/trunk/servers/slapd/overlays/dynlist.c
   openldap/trunk/servers/slapd/overlays/pcache.c
   openldap/trunk/servers/slapd/overlays/ppolicy.c
   openldap/trunk/servers/slapd/overlays/translucent.c
   openldap/trunk/servers/slapd/overlays/unique.c
   openldap/trunk/servers/slapd/passwd.c
   openldap/trunk/servers/slapd/proto-slap.h
   openldap/trunk/servers/slapd/result.c
   openldap/trunk/servers/slapd/sasl.c
   openldap/trunk/servers/slapd/schema_init.c
   openldap/trunk/servers/slapd/search.c
   openldap/trunk/servers/slapd/slap.h
   openldap/trunk/servers/slapd/slapacl.c
   openldap/trunk/servers/slapd/slapauth.c
   openldap/trunk/servers/slapd/slapi/slapi_ops.c
   openldap/trunk/servers/slapd/slapi/slapi_pblock.c
   openldap/trunk/servers/slapd/slapschema.c
   openldap/trunk/servers/slapd/syncrepl.c
   openldap/trunk/tests/data/monitor1.out
   openldap/trunk/tests/data/slapd-proxycache.conf
   openldap/trunk/tests/run.in
   openldap/trunk/tests/scripts/all
   openldap/trunk/tests/scripts/conf.sh
   openldap/trunk/tests/scripts/test020-proxycache
   openldap/trunk/tests/scripts/test024-unique
   openldap/trunk/tests/scripts/test046-dds
   openldap/trunk/tests/scripts/test056-monitor
   openldap/trunk/tests/scripts/test058-syncrepl-asymmetric
Log:
New upstream version

Modified: openldap/trunk/CHANGES
===================================================================
--- openldap/trunk/CHANGES	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/CHANGES	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,8 +1,54 @@
 OpenLDAP 2.4 Change Log
 
+OpenLDAP 2.4.18 Release (2009/09/06)
+	Fixed client tools common options (ITS#6049)
+	Fixed liblber speed and other problems (ITS#6215)
+	Added libldap MozNSS PEM support (ITS#6278)
+	Added libldap option for SASL_USERNAME (ITS#6257)
+	Fixed libldap error parsing (ITS#6197)
+	Fixed libldap native getpass usage (ITS#4643)
+	Fixed libldap tls_check_hostname for OpenSSL and MozNSS (ITS#6239)
+	Added slapd tcp buffers support (ITS#6234)
+	Fixed slapd allow mirrormode to be set to FALSE (ITS#5946)
+	Fixed slapd certificate list parsing (ITS#6241)
+	Fixed slapd writers blocking (ITS#6276)
+	Fixed slapd dncachesize behavior to unlimited by default (ITS#6222)
+	Fixed slapd incorrectly applying writetimeout when not set (ITS#6220)
+	Fixed slapd with duplicate empty lines for olcDbConfig (ITS#6240)
+	Fixed slapd server URL matching (ITS#5942)
+	Fixed slapd subordinate needs a suffix (ITS#6216)
+	Fixed slapd syncrepl decrement on possible NULL value (ITS#6256)
+	Fixed slapd tools to properly close database (ITS#6214)
+	Fixed slapd uninitialized SlapReply components (ITS#6101)
+	Fixed slapd-meta starttls with targets (ITS#6190)
+	Fixed slapd-monitor stats with glued subordinates (ITS#6243)
+	Fixed slapd-ndb startup (ITS#6203)
+	Fixed slapd-relay various issues (ITS#6133)
+	Fixed slapd-relay response/cleanup callback mismatch (ITS#6154)
+	Fixed slapd-sql with baseObject query (ITS#6172)
+	Fixed slapd-sql with empty attribute (ITS#6163)
+	Fixed slapo-dynlist uninitialized var (ITS#6266)
+	Fixed slapo-pcache multiple enhancements (ITS#6152,ITS#5178)
+	Fixed slapo-ppolicy updating operational attributes (ITS#6265)
+	Fixed slapo-translucent attribute return (ITS#6254)
+	Fixed slapo-translucent filter matching (ITS#6255)
+	Fixed slapo-translucent to honor sizelimit (ITS#6253)
+	Fixed slapo-unique filter matching (ITS#6077)
+	Fixed tools off by one error (ITS#6233)
+	Fixed tools resource leaks (ITS#6145)
+	Added contrib/allowed (ITS#4730)
+	Fixed contrib/autogroup with RE24 (ITS#6227)
+	Fixed contrib/nss symbols (ITS#6273)
+	Build Environment
+		Tests note which backend is being tested (ITS#5810)
+		Fixed test056-monitor with custom ports (ITS#6213)
+	Documentation
+		admin24 fix broken link (ITS#6264)
+		ldap_open(3) document URI (ITS#6261)
+
 OpenLDAP 2.4.17 Release (2009/07/13)
 	Fixed liblber to use ber_strnlen (ITS#6080)
-	Fixed libldap gnutls private key init (ITS#6053)
+	Fixed libldap GnuTLS private key init (ITS#6053)
 	Fixed libldap openssl digest initialization (ITS#6192)
 	Fixed libldap tls NULL error messages (ITS#6079)
 	Fixed liblutil opendir/closedir on windows (ITS#6041)

Modified: openldap/trunk/build/version.var
===================================================================
--- openldap/trunk/build/version.var	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/build/version.var	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/build/version.var,v 1.9.2.56 2009/07/13 17:30:01 kurt Exp $
+# $OpenLDAP: pkg/ldap/build/version.var,v 1.9.2.59 2009/09/06 13:22:28 kurt Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -15,9 +15,9 @@
 ol_package=OpenLDAP
 ol_major=2
 ol_minor=4
-ol_patch=17
-ol_api_inc=20417
+ol_patch=18
+ol_api_inc=20418
 ol_api_current=7
-ol_api_revision=0
+ol_api_revision=1
 ol_api_age=5
-ol_release_date="2009/07/13"
+ol_release_date="2009/09/06"

Modified: openldap/trunk/clients/tools/common.c
===================================================================
--- openldap/trunk/clients/tools/common.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/common.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* common.c - common routines for the ldap client tools */
-/* $OpenLDAP: pkg/ldap/clients/tools/common.c,v 1.78.2.22 2009/05/01 20:00:34 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/common.c,v 1.78.2.27 2009/08/25 22:58:08 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -120,6 +120,9 @@
 static int	sessionTracking = 0;
 struct berval	stValue;
 #endif /* LDAP_CONTROL_X_SESSION_TRACKING */
+ber_int_t vlvPos;
+ber_int_t vlvCount;
+struct berval *vlvContext;
 
 LDAPControl	*unknown_ctrls = NULL;
 int		unknown_ctrls_num = 0;
@@ -136,6 +139,7 @@
 static int print_ppolicy( LDAP *ld, LDAPControl *ctrl );
 #endif
 static int print_sss( LDAP *ld, LDAPControl *ctrl );
+static int print_vlv( LDAP *ld, LDAPControl *ctrl );
 #ifdef LDAP_CONTROL_X_DEREF
 static int print_deref( LDAP *ld, LDAPControl *ctrl );
 #endif
@@ -155,6 +159,7 @@
 	{ LDAP_CONTROL_PASSWORDPOLICYRESPONSE,		TOOL_ALL,	print_ppolicy },
 #endif
 	{ LDAP_CONTROL_SORTRESPONSE,	TOOL_SEARCH,	print_sss },
+	{ LDAP_CONTROL_VLVRESPONSE,		TOOL_SEARCH,	print_vlv },
 #ifdef LDAP_CONTROL_X_DEREF
 	{ LDAP_CONTROL_X_DEREF,				TOOL_SEARCH,	print_deref },
 #endif
@@ -266,7 +271,6 @@
 tool_common_usage( void )
 {
 	static const char *const descriptions[] = {
-N_("  -c         continuous operation mode (do not stop on errors)\n"),
 N_("  -d level   set LDAP debugging level to `level'\n"),
 N_("  -D binddn  bind DN\n"),
 N_("  -e [!]<ext>[=<extparam>] general extensions (! indicates criticality)\n")
@@ -297,18 +301,15 @@
 N_("             abandon, cancel, ignore (SIGINT sends abandon/cancel,\n"
    "             or ignores response; if critical, doesn't wait for SIGINT.\n"
    "             not really controls)\n")
-N_("  -f file    read operations from `file'\n"),
 N_("  -h host    LDAP server\n"),
 N_("  -H URI     LDAP Uniform Resource Identifier(s)\n"),
 N_("  -I         use SASL Interactive mode\n"),
-N_("  -M         enable Manage DSA IT control (-MM to make critical)\n"),
 N_("  -n         show what would be done but don't actually do it\n"),
 N_("  -N         do not use reverse DNS to canonicalize SASL host name\n"),
 N_("  -O props   SASL security properties\n"),
 N_("  -o <opt>[=<optparam] general options\n"),
 N_("             nettimeout=<timeout> (in seconds, or \"none\" or \"max\")\n"),
 N_("  -p port    port on LDAP server\n"),
-N_("  -P version protocol version (default: 3)\n"),
 N_("  -Q         use SASL Quiet mode\n"),
 N_("  -R realm   SASL realm\n"),
 N_("  -U authcid SASL authentication identity\n"),
@@ -1917,8 +1918,8 @@
 	rc = ldap_parse_sortresponse_control( ld, ctrl, &err, &attr );
 	if ( rc == LDAP_SUCCESS ) {
 		char buf[ BUFSIZ ];
-		rc = snprintf( buf, sizeof(buf), "(%d) %s %s",
-			err, ldap_err2string(err), attr ? attr : "" );
+		rc = snprintf( buf, sizeof(buf), "(%d) %s%s%s",
+			err, ldap_err2string(err), attr ? " " : "", attr ? attr : "" );
 
 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
 			"sortResult", buf, rc );
@@ -1927,6 +1928,46 @@
 	return rc;
 }
 
+static int
+print_vlv( LDAP *ld, LDAPControl *ctrl )
+{
+	int rc;
+	ber_int_t err;
+	struct berval bv;
+
+	rc = ldap_parse_vlvresponse_control( ld, ctrl, &vlvPos, &vlvCount,
+		&vlvContext, &err );
+	if ( rc == LDAP_SUCCESS ) {
+		char buf[ BUFSIZ ];
+
+		if ( vlvContext && vlvContext->bv_len > 0 ) {
+			bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
+				vlvContext->bv_len ) + 1;
+			bv.bv_val = ber_memalloc( bv.bv_len + 1 );
+
+			bv.bv_len = lutil_b64_ntop(
+				(unsigned char *) vlvContext->bv_val,
+				vlvContext->bv_len,
+				bv.bv_val, bv.bv_len );
+		} else {
+			bv.bv_val = "";
+			bv.bv_len = 0;
+		}
+
+		rc = snprintf( buf, sizeof(buf), "pos=%d count=%d context=%s (%d) %s",
+			vlvPos, vlvCount, bv.bv_val,
+			err, ldap_err2string(err));
+
+		if ( bv.bv_len )
+			ber_memfree( bv.bv_val );
+
+		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
+			"vlvResult", buf, rc );
+	}
+
+	return rc;
+}
+
 #ifdef LDAP_CONTROL_X_DEREF
 static int
 print_deref( LDAP *ld, LDAPControl *ctrl )
@@ -1971,22 +2012,15 @@
 			if ( dv->vals != NULL ) {
 				int j;
 				for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
-					int k;
+					int k = ldif_is_not_printable( dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
 
-					for ( k = 0; k < dv->vals[ j ].bv_len; k++ ) {
-						if ( !isprint( dv->vals[ j ].bv_val[k] ) ) {
-							k = -1;
-							break;
-						}
-					}
-
 					*ptr++ = '<';
 					ptr = lutil_strcopy( ptr, dv->type );
-					if ( k == -1 ) {
+					if ( k ) {
 						*ptr++ = ':';
 					}
 					*ptr++ = '=';
-					if ( k == -1 ) {
+					if ( k ) {
 						k = lutil_b64_ntop(
 							(unsigned char *) dv->vals[ j ].bv_val,
 							dv->vals[ j ].bv_len,
@@ -2004,7 +2038,7 @@
 		}
 		ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
 		*ptr++ = '\n';
-		*ptr++ = '\0';
+		*ptr = '\0';
 		assert( ptr <= buf + len );
 
 		tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, ptr - buf);

Modified: openldap/trunk/clients/tools/common.h
===================================================================
--- openldap/trunk/clients/tools/common.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/common.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* common.h - common definitions for the ldap client tools */
-/* $OpenLDAP: pkg/ldap/clients/tools/common.h,v 1.24.2.4 2009/01/22 00:00:42 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/common.h,v 1.24.2.5 2009/07/22 20:02:20 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -93,6 +93,9 @@
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 extern int		chaining;
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+extern ber_int_t	vlvPos;
+extern ber_int_t	vlvCount;
+extern struct berval	*vlvContext;
 
 /* options */
 extern struct timeval	nettimeout;

Modified: openldap/trunk/clients/tools/ldapcompare.c
===================================================================
--- openldap/trunk/clients/tools/ldapcompare.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapcompare.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapcompare.c -- LDAP compare tool */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapcompare.c,v 1.43.2.6 2009/01/22 00:00:42 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapcompare.c,v 1.43.2.7 2009/08/13 00:55:06 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -85,6 +85,8 @@
 	fprintf( stderr, _("Compare options:\n"));
 	fprintf( stderr, _("  -E [!]<ext>[=<extparam>] compare extensions (! indicates criticality)\n"));
 	fprintf( stderr, _("             !dontUseCopy                (Don't Use Copy)\n"));
+	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
+	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
 	fprintf( stderr, _("  -z         Quiet mode,"
 		" don't print anything, use return values\n"));
 	tool_common_usage();

Modified: openldap/trunk/clients/tools/ldapdelete.c
===================================================================
--- openldap/trunk/clients/tools/ldapdelete.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapdelete.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapdelete.c - simple program to delete an entry using LDAP */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapdelete.c,v 1.118.2.9 2009/01/22 00:00:42 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapdelete.c,v 1.118.2.11 2009/08/13 00:55:06 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -71,6 +71,10 @@
 	fprintf( stderr, _("	dn: list of DNs to delete. If not given, it will be readed from stdin\n"));
 	fprintf( stderr, _("	    or from the file specified with \"-f file\".\n"));
 	fprintf( stderr, _("Delete Options:\n"));
+	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
+	fprintf( stderr, _("  -f file    read operations from `file'\n"));
+	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
+	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
 	fprintf( stderr, _("  -r         delete recursively\n"));
 	tool_common_usage();
 	exit( EXIT_FAILURE );
@@ -162,12 +166,10 @@
 main( int argc, char **argv )
 {
 	char		buf[ 4096 ];
-	FILE		*fp;
+	FILE		*fp = NULL;
 	LDAP		*ld;
 	int		rc, retval;
 
-    fp = NULL;
-
 	tool_init( TOOL_DELETE );
     prog = lutil_progname( "ldapdelete", argc, argv );
 
@@ -179,9 +181,9 @@
 			exit( EXIT_FAILURE );
 	    }
 	} else {
-	if ( optind >= argc ) {
-	    fp = stdin;
-	}
+		if ( optind >= argc ) {
+			fp = stdin;
+		}
     }
 
 	ld = tool_conn_setup( 0, &private_conn_setup );
@@ -189,7 +191,11 @@
 	if ( pw_file || want_bindpw ) {
 		if ( pw_file ) {
 			rc = lutil_get_filed_password( pw_file, &passwd );
-			if( rc ) return EXIT_FAILURE;
+			if( rc ) {
+				if ( fp && fp != stdin )
+					fclose( fp );
+				return EXIT_FAILURE;
+			}
 		} else {
 			passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
 			passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
@@ -222,6 +228,8 @@
 					retval = rc;
 			}
 		}
+		if ( fp != stdin )
+			fclose( fp );
 	}
 
 	tool_unbind( ld );

Modified: openldap/trunk/clients/tools/ldapexop.c
===================================================================
--- openldap/trunk/clients/tools/ldapexop.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapexop.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapexop.c -- a tool for performing well-known extended operations */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapexop.c,v 1.9.2.5 2009/01/22 00:00:42 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapexop.c,v 1.9.2.6 2009/08/14 20:51:14 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2005-2009 The OpenLDAP Foundation.
@@ -43,6 +43,9 @@
 {
 	fprintf( stderr, _("Issue LDAP extended operations\n\n"));
 	fprintf( stderr, _("usage: %s [options] <oid|oid:data|oid::b64data>\n"), prog);
+	fprintf( stderr, _("       %s [options] whoami\n"), prog);
+	fprintf( stderr, _("       %s [options] cancel <id>\n"), prog);
+	fprintf( stderr, _("       %s [options] refresh <DN> [<ttl>]\n"), prog);
 	tool_common_usage();
 	exit( EXIT_FAILURE );
 }
@@ -152,8 +155,6 @@
 		case 2:
 			dn.bv_val = argv[ 1 ];
 			dn.bv_len = strlen( dn.bv_val );
-
-		case 1:
 			break;
 
 		default:

Modified: openldap/trunk/clients/tools/ldapmodify.c
===================================================================
--- openldap/trunk/clients/tools/ldapmodify.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapmodify.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapmodify.c - generic program to modify or add entries using LDAP */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.11 2009/07/08 00:28:21 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.12 2009/08/13 00:55:07 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -137,8 +137,12 @@
 	fprintf( stderr, _("Add or modify options:\n"));
 	fprintf( stderr, _("  -a         add values (%s)\n"),
 		(ldapadd ? _("default") : _("default is to replace")));
+	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
 	fprintf( stderr, _("  -E [!]ext=extparam	modify extensions"
 		" (! indicate s criticality)\n"));
+	fprintf( stderr, _("  -f file    read operations from `file'\n"));
+	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
+	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
 #ifdef LDAP_X_TXN
  	fprintf( stderr,
 		_("             [!]txn=<commit|abort>         (transaction)\n"));

Modified: openldap/trunk/clients/tools/ldapmodrdn.c
===================================================================
--- openldap/trunk/clients/tools/ldapmodrdn.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapmodrdn.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapmodrdn.c - generic program to modify an entry's RDN using LDAP */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapmodrdn.c,v 1.116.2.6 2009/01/22 00:00:42 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapmodrdn.c,v 1.116.2.8 2009/08/13 00:55:07 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -38,8 +38,8 @@
  * This work was originally developed by the University of Michigan
  * (as part of U-MICH LDAP).  Additional significant contributors
  * include:
- *    Kurt D. Zeilenga
- *    Juan C Gomez
+ *	Kurt D. Zeilenga
+ *	Juan C Gomez
  */
 
 
@@ -68,11 +68,11 @@
 
 
 static int domodrdn(
-    LDAP	*ld,
-    char	*dn,
-    char	*rdn,
-    char	*newSuperior,
-    int		remove );	/* flag: remove old RDN */
+	LDAP	*ld,
+	char	*dn,
+	char	*rdn,
+	char	*newSuperior,
+	int		remove );	/* flag: remove old RDN */
 
 void
 usage( void )
@@ -83,7 +83,11 @@
 	fprintf( stderr, _("		If not given, the list of modifications is read from stdin or\n"));
 	fprintf( stderr, _("		from the file specified by \"-f file\" (see man page).\n"));
 	fprintf( stderr, _("Rename options:\n"));
-	fprintf( stderr, _("  -r         remove old RDN\n"));
+ 	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
+ 	fprintf( stderr, _("  -f file    read operations from `file'\n"));
+ 	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
+ 	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
+	fprintf( stderr, _("  -r		 remove old RDN\n"));
 	fprintf( stderr, _("  -s newsup  new superior entry\n"));
 	tool_common_usage();
 	exit( EXIT_FAILURE );
@@ -127,8 +131,8 @@
 #endif
 
 	case 'r':	/* remove old RDN */
-	    remove_old_RDN++;
-	    break;
+		remove_old_RDN++;
+		break;
 
 	case 's':	/* newSuperior */
 		if( protocol == LDAP_VERSION2 ) {
@@ -136,9 +140,9 @@
 				prog, protocol );
 			exit( EXIT_FAILURE );
 		}
-	    newSuperior = strdup( optarg );
-	    protocol = LDAP_VERSION3;
-	    break;
+		newSuperior = strdup( optarg );
+		protocol = LDAP_VERSION3;
+		break;
 
 	default:
 		return 0;
@@ -150,47 +154,53 @@
 int
 main(int argc, char **argv)
 {
-    char		*entrydn = NULL, *rdn = NULL, buf[ 4096 ];
-    FILE		*fp;
-    LDAP		*ld;
+	char		*entrydn = NULL, *rdn = NULL, buf[ 4096 ];
+	FILE		*fp = NULL;
+	LDAP		*ld;
 	int		rc, retval, havedn;
 
-    tool_init( TOOL_MODRDN );
-    prog = lutil_progname( "ldapmodrdn", argc, argv );
+	tool_init( TOOL_MODRDN );
+	prog = lutil_progname( "ldapmodrdn", argc, argv );
 
 	tool_args( argc, argv );
 
-    havedn = 0;
-    if (argc - optind == 2) {
-	if (( rdn = strdup( argv[argc - 1] )) == NULL ) {
-	    perror( "strdup" );
-	    return( EXIT_FAILURE );
+	havedn = 0;
+	if (argc - optind == 2) {
+		if (( rdn = strdup( argv[argc - 1] )) == NULL ) {
+			perror( "strdup" );
+			retval = EXIT_FAILURE;
+			goto fail;
+		}
+		if (( entrydn = strdup( argv[argc - 2] )) == NULL ) {
+			perror( "strdup" );
+			retval = EXIT_FAILURE;
+			goto fail;
+		}
+		++havedn;
+	} else if ( argc - optind != 0 ) {
+		fprintf( stderr, _("%s: invalid number of arguments (%d), only two allowed\n"), prog, argc-optind );
+		usage();
 	}
-        if (( entrydn = strdup( argv[argc - 2] )) == NULL ) {
-	    perror( "strdup" );
-	    return( EXIT_FAILURE );
-        }
-	++havedn;
-    } else if ( argc - optind != 0 ) {
-	fprintf( stderr, _("%s: invalid number of arguments (%d), only two allowed\n"), prog, argc-optind );
-	usage();
-    }
 
-    if ( infile != NULL ) {
-	if (( fp = fopen( infile, "r" )) == NULL ) {
-	    perror( infile );
-	    return( EXIT_FAILURE );
+	if ( infile != NULL ) {
+		if (( fp = fopen( infile, "r" )) == NULL ) {
+			perror( infile );
+			retval = EXIT_FAILURE;
+			goto fail;
+		}
+	} else {
+		fp = stdin;
 	}
-    } else {
-	fp = stdin;
-    }
 
 	ld = tool_conn_setup( 0, 0 );
 
 	if ( pw_file || want_bindpw ) {
 		if ( pw_file ) {
 			rc = lutil_get_filed_password( pw_file, &passwd );
-			if( rc ) return EXIT_FAILURE;
+			if( rc ) {
+				retval = EXIT_FAILURE;
+				goto fail;
+			}
 		} else {
 			passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
 			passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
@@ -201,50 +211,57 @@
 
 	tool_server_controls( ld, NULL, 0 );
 
-    retval = rc = 0;
-    if (havedn)
-	retval = domodrdn( ld, entrydn, rdn, newSuperior, remove_old_RDN );
-    else while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
-	if ( *buf != '\n' ) {	/* blank lines optional, skip */
-	    buf[ strlen( buf ) - 1 ] = '\0';	/* remove nl */
+	retval = rc = 0;
+	if (havedn)
+		retval = domodrdn( ld, entrydn, rdn, newSuperior, remove_old_RDN );
+	else while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
+		if ( *buf != '\n' ) {	/* blank lines optional, skip */
+			buf[ strlen( buf ) - 1 ] = '\0';	/* remove nl */
 
-	    if ( havedn ) {	/* have DN, get RDN */
-		if (( rdn = strdup( buf )) == NULL ) {
-                    perror( "strdup" );
-                    return( EXIT_FAILURE );
+			if ( havedn ) {	/* have DN, get RDN */
+				if (( rdn = strdup( buf )) == NULL ) {
+					perror( "strdup" );
+					retval = EXIT_FAILURE;
+					goto fail;
+				}
+				rc = domodrdn(ld, entrydn, rdn, newSuperior, remove_old_RDN );
+				if ( rc != 0 )
+					retval = rc;
+				havedn = 0;
+				free( rdn ); rdn = NULL;
+				free( entrydn ); entrydn = NULL;
+			} else if ( !havedn ) {	/* don't have DN yet */
+				if (( entrydn = strdup( buf )) == NULL ) {
+					retval = EXIT_FAILURE;
+					goto fail;
+				}
+				++havedn;
+			}
 		}
-		rc = domodrdn(ld, entrydn, rdn, newSuperior, remove_old_RDN );
-		if ( rc != 0 )
-			retval = rc;
-		havedn = 0;
-	    } else if ( !havedn ) {	/* don't have DN yet */
-	        if (( entrydn = strdup( buf )) == NULL ) {
-		    perror( "strdup" );
-		    return( EXIT_FAILURE );
-	        }
-		++havedn;
-	    }
 	}
-    }
 
 	tool_unbind( ld );
 	tool_destroy();
-    return( retval );
+fail:
+	if ( fp && fp != stdin ) fclose( fp );
+	if ( entrydn ) free( entrydn );
+	if ( rdn ) free( rdn );
+	return( retval );
 }
 
 static int domodrdn(
-    LDAP	*ld,
-    char	*dn,
-    char	*rdn,
-    char	*newSuperior,
-    int		remove ) /* flag: remove old RDN */
+	LDAP	*ld,
+	char	*dn,
+	char	*rdn,
+	char	*newSuperior,
+	int		remove ) /* flag: remove old RDN */
 {
 	int rc, code, id;
 	char *matcheddn=NULL, *text=NULL, **refs=NULL;
 	LDAPControl **ctrls = NULL;
 	LDAPMessage *res;
 
-    if ( verbose ) {
+	if ( verbose ) {
 		printf( _("Renaming \"%s\"\n"), dn );
 		printf( _("\tnew rdn=\"%s\" (%s old rdn)\n"),
 			rdn, remove ? _("delete") : _("keep") );
@@ -318,7 +335,7 @@
 	if (ctrls) {
 		tool_print_ctrls( ld, ctrls );
 		ldap_controls_free( ctrls );
-    }
+	}
 
 	ber_memfree( text );
 	ber_memfree( matcheddn );

Modified: openldap/trunk/clients/tools/ldapsearch.c
===================================================================
--- openldap/trunk/clients/tools/ldapsearch.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/clients/tools/ldapsearch.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ldapsearch -- a tool for searching LDAP directories */
-/* $OpenLDAP: pkg/ldap/clients/tools/ldapsearch.c,v 1.234.2.19 2009/03/09 23:16:48 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/clients/tools/ldapsearch.c,v 1.234.2.23 2009/08/25 22:58:08 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -123,6 +123,7 @@
 	fprintf( stderr, _("  -a deref   one of never (default), always, search, or find\n"));
 	fprintf( stderr, _("  -A         retrieve attribute names only (no values)\n"));
 	fprintf( stderr, _("  -b basedn  base dn for search\n"));
+	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
 	fprintf( stderr, _("  -E [!]<ext>[=<extparam>] search extensions (! indicates criticality)\n"));
 	fprintf( stderr, _("             [!]domainScope              (domain scope)\n"));
 	fprintf( stderr, _("             !dontUseCopy                (Don't Use Copy)\n"));
@@ -133,16 +134,21 @@
 	fprintf( stderr, _("             [!]subentries[=true|false]  (RFC 3672 subentries)\n"));
 	fprintf( stderr, _("             [!]sync=ro[/<cookie>]       (RFC 4533 LDAP Sync refreshOnly)\n"));
 	fprintf( stderr, _("                     rp[/<cookie>][/<slimit>] (refreshAndPersist)\n"));
+	fprintf( stderr, _("             [!]vlv=<before>/<after>(/<offset>/<count>|:<value>)\n"));
+	fprintf( stderr, _("                                         (ldapv3-vlv-09 virtual list views)\n"));
 #ifdef LDAP_CONTROL_X_DEREF
 	fprintf( stderr, _("             [!]deref=derefAttr:attr[,...][;derefAttr:attr[,...][;...]]\n"));
 #endif
 	fprintf( stderr, _("             [!]<oid>=:<value>           (generic control; no response handling)\n"));
+	fprintf( stderr, _("  -f file    read operations from `file'\n"));
 	fprintf( stderr, _("  -F prefix  URL prefix for files (default: %s)\n"), def_urlpre);
 	fprintf( stderr, _("  -l limit   time limit (in seconds, or \"none\" or \"max\") for search\n"));
 	fprintf( stderr, _("  -L         print responses in LDIFv1 format\n"));
 	fprintf( stderr, _("  -LL        print responses in LDIF format without comments\n"));
 	fprintf( stderr, _("  -LLL       print responses in LDIF format without comments\n"));
 	fprintf( stderr, _("             and version\n"));
+	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
+	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
 	fprintf( stderr, _("  -s scope   one of base, one, sub or children (search scope)\n"));
 	fprintf( stderr, _("  -S attr    sort the results by attribute `attr'\n"));
 	fprintf( stderr, _("  -t         write binary values to files in temporary directory\n"));
@@ -207,6 +213,10 @@
 static int sss = 0;
 static LDAPSortKey **sss_keys = NULL;
 
+static int vlv = 0;
+static LDAPVLVInfo vlvInfo;
+static struct berval vlvValue;
+
 static int ldapsync = 0;
 static struct berval sync_cookie = { 0, NULL };
 static int sync_slimit = -1;
@@ -263,7 +273,48 @@
 	}
 }
 
+static int
+parse_vlv(char *cvalue)
+{
+	char *keyp, *key2;
+	int num1, num2;
 
+	keyp = cvalue;
+	if ( sscanf( keyp, "%d/%d", &num1, &num2 ) != 2 ) {
+		fprintf( stderr,
+			_("VLV control value \"%s\" invalid\n"),
+			cvalue );
+		return -1;
+	}
+	vlvInfo.ldvlv_before_count = num1;
+	vlvInfo.ldvlv_after_count = num2;
+	keyp = strchr( keyp, '/' ) + 1;
+	key2 = strchr( keyp, '/' );
+	if ( key2 ) {
+		keyp = key2 + 1;
+		if ( sscanf( keyp, "%d/%d", &num1, &num2 ) != 2 ) {
+			fprintf( stderr,
+				_("VLV control value \"%s\" invalid\n"),
+				cvalue );
+			return -1;
+		}
+		vlvInfo.ldvlv_offset = num1;
+		vlvInfo.ldvlv_count = num2;
+		vlvInfo.ldvlv_attrvalue = NULL;
+	} else {
+		key2 = strchr( keyp, ':' );
+		if ( !key2 ) {
+			fprintf( stderr,
+				_("VLV control value \"%s\" invalid\n"),
+				cvalue );
+			return -1;
+		}
+		ber_str2bv( key2+1, 0, 0, &vlvValue );
+		vlvInfo.ldvlv_attrvalue = &vlvValue;
+	}
+	return 0;
+}
+
 const char options[] = "a:Ab:cE:F:l:Ls:S:tT:uz:"
 	"Cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
 
@@ -343,6 +394,11 @@
 					_("PagedResultsControl previously specified\n") );
 				exit( EXIT_FAILURE );
 			}
+			if ( vlv != 0 ) {
+				fprintf( stderr,
+					_("PagedResultsControl incompatible with VLV\n") );
+				exit( EXIT_FAILURE );
+			}
 
 			if( cvalue != NULL ) {
 				char *promptp;
@@ -500,6 +556,27 @@
 			}
 			if ( crit ) ldapsync *= -1;
 
+		} else if ( strcasecmp( control, "vlv" ) == 0 ) {
+			if( vlv ) {
+				fprintf( stderr,
+					_("virtual list view control previously specified\n"));
+				exit( EXIT_FAILURE );
+			}
+			if ( pagedResults != 0 ) {
+				fprintf( stderr,
+					_("PagedResultsControl incompatible with VLV\n") );
+				exit( EXIT_FAILURE );
+			}
+			if( cvalue == NULL ) {
+				fprintf( stderr,
+			         _("missing specification of vlv control\n") );
+				exit( EXIT_FAILURE );
+			}
+			if ( parse_vlv( cvalue ))
+				exit( EXIT_FAILURE );
+
+			vlv = 1 + crit;
+
 #ifdef LDAP_CONTROL_X_DEREF
 		} else if ( strcasecmp( control, "deref" ) == 0 ) {
 			int ispecs;
@@ -748,6 +825,12 @@
 
 	tool_args( argc, argv );
 
+	if ( vlv && !sss ) {
+		fprintf( stderr,
+			_("VLV control requires server side sort control\n" ));
+		return EXIT_FAILURE;
+	}
+
 	if (( argc - optind < 1 ) ||
 		( *argv[optind] != '(' /*')'*/ &&
 		( strchr( argv[optind], '=' ) == NULL ) ) )
@@ -843,7 +926,8 @@
 		|| ldapsync
 		|| sss
 		|| subentries
-		|| valuesReturnFilter )
+		|| valuesReturnFilter
+		|| vlv )
 	{
 
 #ifdef LDAP_CONTROL_DONTUSECOPY
@@ -991,6 +1075,21 @@
 			i++;
 		}
 
+		if ( vlv ) {
+			if ( ctrl_add() ) {
+				return EXIT_FAILURE;
+			}
+
+			if ( ldap_create_vlv_control_value( ld,
+				&vlvInfo, &c[i].ldctl_value ) )
+			{
+				return EXIT_FAILURE;
+			}
+
+			c[i].ldctl_oid = LDAP_CONTROL_VLVREQUEST;
+			c[i].ldctl_iscritical = sss > 1;
+			i++;
+		}
 #ifdef LDAP_CONTROL_X_DEREF
 		if ( derefcrit ) {
 			if ( derefval.bv_val == NULL ) {
@@ -1106,10 +1205,19 @@
 			printf(_("\n# with server side sorting %scontrol"),
 				sss > 1 ? _("critical ") : "" );
 		}
+		if ( vlv ) {
+			printf(_("\n# with virtual list view %scontrol: %d/%d"),
+				vlv > 1 ? _("critical ") : "",
+				vlvInfo.ldvlv_before_count, vlvInfo.ldvlv_after_count);
+			if ( vlvInfo.ldvlv_attrvalue )
+				printf(":%s", vlvInfo.ldvlv_attrvalue->bv_val );
+			else
+				printf("/%d/%d", vlvInfo.ldvlv_offset, vlvInfo.ldvlv_count );
+		}
 #ifdef LDAP_CONTROL_X_DEREF
-		if ( sss ) {
+		if ( derefcrit ) {
 			printf(_("\n# with dereference %scontrol"),
-				sss > 1 ? _("critical ") : "" );
+				derefcrit > 1 ? _("critical ") : "" );
 		}
 #endif
 
@@ -1149,7 +1257,7 @@
 	}
 
 	if (( rc == LDAP_SUCCESS ) && pageSize && pr_morePagedResults ) {
-		char	buf[6];
+		char	buf[12];
 		int	i, moreEntries, tmpSize;
 
 		/* Loop to get the next pages when 
@@ -1187,6 +1295,41 @@
 		goto getNextPage;
 	}
 
+	if (( rc == LDAP_SUCCESS ) && vlv ) {
+		char	buf[BUFSIZ];
+		int	i, moreEntries;
+
+		/* Loop to get the next window when 
+		 * enter is pressed on the terminal.
+		 */
+		printf( _("Press [before/after(/offset/count|:value)] Enter for the next window.\n"));
+		i = 0;
+		moreEntries = getchar();
+		while ( moreEntries != EOF && moreEntries != '\n' ) { 
+			if ( i < (int)sizeof(buf) - 1 ) {
+				buf[i] = moreEntries;
+				i++;
+			}
+			moreEntries = getchar();
+		}
+		buf[i] = '\0';
+		if ( buf[0] ) {
+			i = parse_vlv( strdup( buf ));
+			if ( i )
+				return EXIT_FAILURE;
+		} else {
+			vlvInfo.ldvlv_attrvalue = NULL;
+			vlvInfo.ldvlv_count = vlvCount;
+			vlvInfo.ldvlv_offset += vlvInfo.ldvlv_after_count;
+		}
+
+		if ( vlvInfo.ldvlv_context )
+			ber_bvfree( vlvInfo.ldvlv_context );
+		vlvInfo.ldvlv_context = vlvContext;
+
+		goto getNextPage;
+	}
+
 	tool_unbind( ld );
 	tool_destroy();
 	if ( base != NULL ) {

Modified: openldap/trunk/configure
===================================================================
--- openldap/trunk/configure	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/configure	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.631.2.24 2009/07/06 19:22:51 quanah Exp .
+# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.631.2.26 2009/08/13 00:11:16 quanah Exp .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61.
 #
@@ -918,6 +918,7 @@
 BUILD_RETCODE
 BUILD_RWM
 BUILD_SEQMOD
+BUILD_SSSVLV
 BUILD_SYNCPROV
 BUILD_TRANSLUCENT
 BUILD_UNIQUE
@@ -1599,7 +1600,8 @@
     --enable-refint	  Referential Integrity overlay no|yes|mod [no]
     --enable-retcode	  Return Code testing overlay no|yes|mod [no]
     --enable-rwm       	  Rewrite/Remap overlay no|yes|mod [no]
-    --enable-seqmod	  Sequential Modify overlay no|yes|mod [yes]
+    --enable-seqmod	  Sequential Modify overlay no|yes|mod [no]
+    --enable-sssvlv	  ServerSideSort/VLV overlay no|yes|mod [no]
     --enable-syncprov	  Syncrepl Provider overlay no|yes|mod [yes]
     --enable-translucent  Translucent Proxy overlay no|yes|mod [no]
     --enable-unique       Attribute Uniqueness overlay no|yes|mod [no]
@@ -3753,6 +3755,7 @@
 	retcode \
 	rwm \
 	seqmod \
+	sssvlv \
 	syncprov \
 	translucent \
 	unique \
@@ -4140,11 +4143,35 @@
 	ol_enable_seqmod="$ol_arg"
 
 else
-  	ol_enable_seqmod=${ol_enable_overlays:-yes}
+  	ol_enable_seqmod=${ol_enable_overlays:-no}
 fi
 
 # end --enable-seqmod
 
+# OpenLDAP --enable-sssvlv
+
+	# Check whether --enable-sssvlv was given.
+if test "${enable_sssvlv+set}" = set; then
+  enableval=$enable_sssvlv;
+	ol_arg=invalid
+	for ol_val in no yes mod ; do
+		if test "$enableval" = "$ol_val" ; then
+			ol_arg="$ol_val"
+		fi
+	done
+	if test "$ol_arg" = "invalid" ; then
+		{ { echo "$as_me:$LINENO: error: bad value $enableval for --enable-sssvlv" >&5
+echo "$as_me: error: bad value $enableval for --enable-sssvlv" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	ol_enable_sssvlv="$ol_arg"
+
+else
+  	ol_enable_sssvlv=${ol_enable_overlays:-no}
+fi
+
+# end --enable-sssvlv
+
 # OpenLDAP --enable-syncprov
 
 	# Check whether --enable-syncprov was given.
@@ -4464,6 +4491,7 @@
 BUILD_RETCODE=no
 BUILD_RWM=no
 BUILD_SEQMOD=no
+BUILD_SSSVLV=no
 BUILD_SYNCPROV=no
 BUILD_TRANSLUCENT=no
 BUILD_UNIQUE=no
@@ -6436,7 +6464,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6439 "configure"' > conftest.$ac_ext
+  echo '#line 6467 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -8505,11 +8533,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8508: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8536: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8512: \$? = $ac_status" >&5
+   echo "$as_me:8540: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8767,11 +8795,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8770: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8798: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8774: \$? = $ac_status" >&5
+   echo "$as_me:8802: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8829,11 +8857,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8832: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8860: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8836: \$? = $ac_status" >&5
+   echo "$as_me:8864: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11040,7 +11068,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11043 "configure"
+#line 11071 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11138,7 +11166,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11141 "configure"
+#line 11169 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -36768,7 +36796,6 @@
 
 
 
-
 for ac_func in \
 	bcopy			\
 	closesocket		\
@@ -36782,7 +36809,6 @@
 	geteuid			\
 	getgrgid		\
 	gethostname		\
-	getpass			\
 	getpassphrase		\
 	getpwuid		\
 	getpwnam		\
@@ -38462,6 +38488,22 @@
 
 fi
 
+if test "$ol_enable_sssvlv" != no ; then
+	BUILD_SSSVLV=$ol_enable_sssvlv
+	if test "$ol_enable_sssvlv" = mod ; then
+		MFLAG=SLAPD_MOD_DYNAMIC
+		SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS sssvlv.la"
+	else
+		MFLAG=SLAPD_MOD_STATIC
+		SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS sssvlv.o"
+	fi
+
+cat >>confdefs.h <<_ACEOF
+#define SLAPD_OVER_SSSVLV $MFLAG
+_ACEOF
+
+fi
+
 if test "$ol_enable_syncprov" != no ; then
 	BUILD_SYNCPROV=$ol_enable_syncprov
 	if test "$ol_enable_syncprov" = mod ; then
@@ -38642,6 +38684,7 @@
 
 
 
+
 # Check whether --with-xxinstall was given.
 if test "${with_xxinstall+set}" = set; then
   withval=$with_xxinstall;
@@ -39466,6 +39509,7 @@
 BUILD_RETCODE!$BUILD_RETCODE$ac_delim
 BUILD_RWM!$BUILD_RWM$ac_delim
 BUILD_SEQMOD!$BUILD_SEQMOD$ac_delim
+BUILD_SSSVLV!$BUILD_SSSVLV$ac_delim
 BUILD_SYNCPROV!$BUILD_SYNCPROV$ac_delim
 BUILD_TRANSLUCENT!$BUILD_TRANSLUCENT$ac_delim
 BUILD_UNIQUE!$BUILD_UNIQUE$ac_delim
@@ -39506,7 +39550,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 91; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5

Modified: openldap/trunk/configure.in
===================================================================
--- openldap/trunk/configure.in	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/configure.in	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-dnl $OpenLDAP: pkg/ldap/configure.in,v 1.631.2.24 2009/07/06 19:22:51 quanah Exp $
+dnl $OpenLDAP: pkg/ldap/configure.in,v 1.631.2.26 2009/08/13 00:11:16 quanah Exp $
 dnl This work is part of OpenLDAP Software <http://www.openldap.org/>.
 dnl
 dnl Copyright 1998-2009 The OpenLDAP Foundation.
@@ -25,7 +25,7 @@
 dnl Configure.in for OpenLDAP
 AC_COPYRIGHT([[Copyright 1998-2009 The OpenLDAP Foundation. All rights reserved.
 Restrictions apply, see COPYRIGHT and LICENSE files.]])
-AC_REVISION([$OpenLDAP: pkg/ldap/configure.in,v 1.631.2.24 2009/07/06 19:22:51 quanah Exp $])
+AC_REVISION([$OpenLDAP: pkg/ldap/configure.in,v 1.631.2.26 2009/08/13 00:11:16 quanah Exp $])
 AC_INIT([OpenLDAP],,[http://www.openldap.org/its/])
 m4_define([AC_PACKAGE_BUGREPORT],[<http://www.openldap.org/its/>])
 AC_CONFIG_SRCDIR(build/version.sh)dnl
@@ -346,6 +346,7 @@
 	retcode \
 	rwm \
 	seqmod \
+	sssvlv \
 	syncprov \
 	translucent \
 	unique \
@@ -385,7 +386,9 @@
 OL_ARG_ENABLE(rwm,[    --enable-rwm       	  Rewrite/Remap overlay],
 	no, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(seqmod,[    --enable-seqmod	  Sequential Modify overlay],
-	yes, [no yes mod], ol_enable_overlays)
+	no, [no yes mod], ol_enable_overlays)
+OL_ARG_ENABLE(sssvlv,[    --enable-sssvlv	  ServerSideSort/VLV overlay],
+	no, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(syncprov,[    --enable-syncprov	  Syncrepl Provider overlay],
 	yes, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(translucent,[    --enable-translucent  Translucent Proxy overlay],
@@ -554,6 +557,7 @@
 BUILD_RETCODE=no
 BUILD_RWM=no
 BUILD_SEQMOD=no
+BUILD_SSSVLV=no
 BUILD_SYNCPROV=no
 BUILD_TRANSLUCENT=no
 BUILD_UNIQUE=no
@@ -2393,7 +2397,6 @@
 	geteuid			\
 	getgrgid		\
 	gethostname		\
-	getpass			\
 	getpassphrase		\
 	getpwuid		\
 	getpwnam		\
@@ -2938,6 +2941,18 @@
 	AC_DEFINE_UNQUOTED(SLAPD_OVER_SEQMOD,$MFLAG,[define for Sequential Modify overlay])
 fi
 
+if test "$ol_enable_sssvlv" != no ; then
+	BUILD_SSSVLV=$ol_enable_sssvlv
+	if test "$ol_enable_sssvlv" = mod ; then
+		MFLAG=SLAPD_MOD_DYNAMIC
+		SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS sssvlv.la"
+	else
+		MFLAG=SLAPD_MOD_STATIC
+		SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS sssvlv.o"
+	fi
+	AC_DEFINE_UNQUOTED(SLAPD_OVER_SSSVLV,$MFLAG,[define for ServerSideSort/VLV overlay])
+fi
+
 if test "$ol_enable_syncprov" != no ; then
 	BUILD_SYNCPROV=$ol_enable_syncprov
 	if test "$ol_enable_syncprov" = mod ; then
@@ -3056,6 +3071,7 @@
   AC_SUBST(BUILD_RETCODE)
   AC_SUBST(BUILD_RWM)
   AC_SUBST(BUILD_SEQMOD)
+  AC_SUBST(BUILD_SSSVLV)
   AC_SUBST(BUILD_SYNCPROV)
   AC_SUBST(BUILD_TRANSLUCENT)
   AC_SUBST(BUILD_UNIQUE)

Modified: openldap/trunk/contrib/README
===================================================================
--- openldap/trunk/contrib/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,10 +1,11 @@
 OpenLDAP Contributed Software README
 
 OpenLDAP Project provides a number of freely-distributable LDAP
-software packages.  Though distributed with OpenLDAP Software, they
-are not part of OpenLDAP Software.  Some packages may be out of
-date.  Each package in this directory has it's own use and
-redistribution restrictions as documented within the package.
+software packages.  While distributed as part of OpenLDAP Software,
+they are not necessarily supported by the OpenLDAP Project.  Some
+packages may be out of date.  Each package in this directory has its
+own use and may have different redistribution restrictions than typical
+for OpenLDAP Software.
 
 Current contributions:
 	ldapc++
@@ -28,4 +29,4 @@
 OpenLDAP Contributing Guidelines are available at:
   <http://www.openldap.org/devel/contributing.html>.
 
-$OpenLDAP: pkg/ldap/contrib/README,v 1.19 2006/01/25 21:13:14 kurt Exp $
+$OpenLDAP: pkg/ldap/contrib/README,v 1.19.2.1 2009/08/17 21:48:55 quanah Exp $

Modified: openldap/trunk/contrib/ldapc++/src/SaslInteractionHandler.cpp
===================================================================
--- openldap/trunk/contrib/ldapc++/src/SaslInteractionHandler.cpp	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/ldapc++/src/SaslInteractionHandler.cpp	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-// $OpenLDAP: pkg/ldap/contrib/ldapc++/src/SaslInteractionHandler.cpp,v 1.3.2.2 2008/04/14 23:09:26 quanah Exp $
+// $OpenLDAP: pkg/ldap/contrib/ldapc++/src/SaslInteractionHandler.cpp,v 1.3.2.3 2009/07/22 19:50:57 quanah Exp $
 /*
  * Copyright 2007, OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
@@ -11,6 +11,7 @@
 
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
+#include <cstdio>
 #endif
 
 #include <string.h>

Modified: openldap/trunk/contrib/slapd-modules/acl/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/acl/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/acl/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,3 @@
-Copyright 2005-2009 The OpenLDAP Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
 This directory contains native slapd plugins that implement access rules.
 
 posixgroup.c contains a simple example that implements access control
@@ -34,3 +28,10 @@
 
 to compile the posixGroup ACL plugin.
 
+---
+Copyright 2005-2009 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+

Modified: openldap/trunk/contrib/slapd-modules/acl/posixgroup.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/acl/posixgroup.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/acl/posixgroup.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,7 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/acl/posixgroup.c,v 1.3.2.5 2009/01/22 00:00:45 kurt Exp $ */
-/*
+/* posixgroup.c */
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/acl/posixgroup.c,v 1.3.2.6 2009/08/17 21:48:55 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
  * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *

Deleted: openldap/trunk/contrib/slapd-modules/addpartial/COPYRIGHT
===================================================================
--- openldap/trunk/contrib/slapd-modules/addpartial/COPYRIGHT	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/addpartial/COPYRIGHT	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,10 +0,0 @@
-Copyright (C) Virginia Tech, David Hawes.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-http://www.OpenLDAP.org/license.html.

Deleted: openldap/trunk/contrib/slapd-modules/addpartial/LICENSE
===================================================================
--- openldap/trunk/contrib/slapd-modules/addpartial/LICENSE	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/addpartial/LICENSE	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,47 +0,0 @@
-The OpenLDAP Public License
-  Version 2.8, 17 August 2003
-
-  Redistribution and use of this software and associated documentation
-  ("Software"), with or without modification, are permitted provided
-  that the following conditions are met:
-
-  1. Redistributions in source form must retain copyright statements
-     and notices,
-
-  2. Redistributions in binary form must reproduce applicable copyright
-     statements and notices, this list of conditions, and the following
-     disclaimer in the documentation and/or other materials provided
-     with the distribution, and
-
-  3. Redistributions must contain a verbatim copy of this document.
-
-The OpenLDAP Foundation may revise this license from time to time.
-Each revision is distinguished by a version number.  You may use
-this Software under terms of this license revision or under the
-terms of any subsequent revision of the license.
-
-THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
-CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT
-SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
-OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-The names of the authors and copyright holders must not be used in
-advertising or otherwise to promote the sale, use or other dealing
-in this Software without specific, written prior permission.  Title
-to copyright in this Software shall at all times remain with copyright
-holders.
-
-OpenLDAP is a registered trademark of the OpenLDAP Foundation.
-
-Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
-California, USA.  All Rights Reserved.  Permission to copy and
-distribute verbatim copies of this document is granted.

Modified: openldap/trunk/contrib/slapd-modules/addpartial/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/addpartial/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/addpartial/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -57,3 +57,16 @@
       This is especially important if you are using syncrepl, as the modify that
       addpartial does will muck with the locking that takes place in the
       syncprov overlay.
+
+---
+Copyright 2004-2009 The OpenLDAP Foundation.
+Portions Copyright (C) Virginia Tech, David Hawes.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+http://www.OpenLDAP.org/license.html.

Modified: openldap/trunk/contrib/slapd-modules/addpartial/addpartial-overlay.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/addpartial/addpartial-overlay.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/addpartial/addpartial-overlay.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
-/**
- * $Id: addpartial-overlay.c 6588 2007-11-07 18:29:25Z dhawes $
+/* addpartial-overlay.c */
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/addpartial/addpartial-overlay.c,v 1.1.2.5 2009/08/17 21:48:56 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright (C) 2004 Virginia Tech, David Hawes.
+ * Copyright 2004-2009 The OpenLDAP Foundation.
+ * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -11,16 +13,13 @@
  * A copy of this license is available in file LICENSE in the
  * top-level directory of the distribution or, alternatively, at
  * http://www.OpenLDAP.org/license.html.
+ */
+/* ACKNOLEDGEDMENTS:
+ * This work was initially developed by David Hawes of Virginia Tech
+ * for inclusion in OpenLDAP Software.
+ */
+/* addpartial-overlay
  *
- * SEE LICENSE FOR MORE INFORMATION
- *
- * Author:  David H. Hawes, Jr.
- * Email:   dhawes at vt.edu
- * Version: $Revision: 8385 $
- * Updated: $Date: 2008-11-04 12:19:52 -0500 (Tue, 04 Nov 2008) $
- * 
- * addpartial-overlay
- *
  * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
  * change has actually taken place for that record, and then performs a modify
  * request for those values that have changed (modified, added, deleted).  If

Modified: openldap/trunk/contrib/slapd-modules/allop/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/allop/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/allop/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,3 @@
-Copyright 2004-2009 The OpenLDAP Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
 This directory contains a slapd overlay, allop.
 The intended usage is as a global overlay for use with those clients
 that do not make use of the RFC3673 allOp ("+") in the requested 
@@ -25,3 +19,10 @@
 
 to compile this overlay.
 
+---
+Copyright 2004-2009 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+

Deleted: openldap/trunk/contrib/slapd-modules/autogroup/COPYRIGHT
===================================================================
--- openldap/trunk/contrib/slapd-modules/autogroup/COPYRIGHT	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/autogroup/COPYRIGHT	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,10 +0,0 @@
-Copyright (C) 2007 Michał Szulczyński.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-http://www.OpenLDAP.org/license.html.

Modified: openldap/trunk/contrib/slapd-modules/autogroup/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/autogroup/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/autogroup/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -69,4 +69,17 @@
     of members may be slow.
 
 ACKNOWLEDGEMENTS
-    This module was written in 2007 by Michał Szulczyński.
+    This module was originally written in 2007 by Michał Szulczyński.
+
+---
+Copyright 1998-2009 The OpenLDAP Foundation.
+Portions Copyright (C) 2007 Michał Szulczyński.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+http://www.OpenLDAP.org/license.html.

Modified: openldap/trunk/contrib/slapd-modules/autogroup/autogroup.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/autogroup/autogroup.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/autogroup/autogroup.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,10 @@
 /* autogroup.c - automatic group overlay */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/autogroup/autogroup.c,v 1.2.2.2 2008/11/10 19:57:30 quanah Exp $ */
-/*
- * Copyright 2007 Michał Szulczyński.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/autogroup/autogroup.c,v 1.2.2.4 2009/08/17 21:48:56 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2007-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2007 Michał Szulczyński.
+ * Portions Copyright 2009 Howard Chu.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,6 +15,11 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Michał Szulczyński for inclusion in
+ * OpenLDAP Software.  Additional significant contributors include:
+ *   Howard Chu
+ */
 
 #include "portable.h"
 
@@ -238,20 +246,13 @@
 static int
 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
 {
-	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
-
 	assert( op->o_tag == LDAP_REQ_SEARCH );
 
 	if ( rs->sr_type == REP_SEARCH ) {
 		autogroup_ga_t		*agg = (autogroup_ga_t *)op->o_callback->sc_private;
 		autogroup_entry_t	*age = agg->agg_group;
-		Operation		o = *op;
 		Modifications		*modlist;
-		SlapReply		sreply = {REP_RESULT};
-		const char		*text = NULL;
-		char			textbuf[1024];
 		struct berval		vals[ 2 ], nvals[ 2 ];
-		slap_callback		cb = { NULL, slap_null_cb, NULL, NULL };
 
 		Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
 			rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
@@ -508,11 +509,8 @@
 static int
 autogroup_group_add_cb( Operation *op, SlapReply *rs )
 {
-	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
-
 	assert( op->o_tag == LDAP_REQ_SEARCH );
 
-
 	if ( rs->sr_type == REP_SEARCH ) {
 		autogroup_sc_t		*ags = (autogroup_sc_t *)op->o_callback->sc_private;
 
@@ -538,7 +536,6 @@
 	autogroup_def_t		*agd = agi->agi_def;
 	autogroup_entry_t	*age = agi->agi_entry;
 	autogroup_filter_t	*agf;
-	Attribute		*a;
 	int			rc = 0;
 
 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n", 
@@ -652,7 +649,6 @@
 {
 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
 	autogroup_info_t		*agi = (autogroup_info_t *)on->on_bi.bi_private;
-	autogroup_def_t		*agd = agi->agi_def;
 	autogroup_entry_t	*age = agi->agi_entry,
 				*age_prev, *age_next;
 	autogroup_filter_t	*agf;
@@ -683,9 +679,6 @@
 			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
 
 			if ( match == 0 ) {
-				autogroup_filter_t	*agf = age->age_filter,
-							*agf_next;
-
 				autogroup_delete_group( agi, age );
 				break;
 			}
@@ -1266,7 +1259,6 @@
 			autogroup_entry_t	*age_next, *age_prev;
 			autogroup_filter_t	*agf,
 						*agf_next;
-			struct berval		*bv;
 
 			ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
 
@@ -1446,8 +1438,7 @@
 	BackendDB	*be,
 	ConfigReply	*cr )
 {
-	slap_overinst			*on = (slap_overinst *) be->bd_info,
-				*on_bd;
+	slap_overinst			*on = (slap_overinst *) be->bd_info;
 	autogroup_info_t		*agi = on->on_bi.bi_private;
 	autogroup_def_t		*agd;
 	autogroup_sc_t		ags;
@@ -1458,9 +1449,6 @@
 	void				*thrctx = ldap_pvt_thread_pool_context();
 	Connection			conn = { 0 };
 	OperationBuffer 	opbuf;
-	BerValue		bv;
-	char			*ptr;
-	int			rc = 0;
 
 	Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n", 0, 0, 0);
 
@@ -1482,31 +1470,28 @@
 	op->ors_slimit = SLAP_NO_LIMIT;
 	op->ors_attrs =  slap_anlist_no_attrs;
 
-	op->o_bd = select_backend(&op->o_req_ndn, 0);
+	op->o_bd = be;
+	op->o_bd->bd_info = (BackendInfo *)on->on_info;
 
-	ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
+	ags.ags_info = agi;
+	cb.sc_private = &ags;
+	cb.sc_response = autogroup_group_add_cb;
+	cb.sc_cleanup = NULL;
+	cb.sc_next = NULL;
+
+	op->o_callback = &cb;
+
 	for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
 
 		autogroup_build_def_filter(agd, op);
 
-
-		ags.ags_info = agi;
 		ags.ags_def = agd;
-		cb.sc_private = &ags;
-		cb.sc_response = autogroup_group_add_cb;
-		cb.sc_cleanup = NULL;
-		cb.sc_next = NULL;
 
-		op->o_callback = &cb;
-
-		op->o_bd->bd_info = (BackendInfo *)on->on_info;
 		op->o_bd->be_search( op, &rs );
-		op->o_bd->bd_info = (BackendInfo *)on;
 
 		filter_free_x( op, op->ors_filter, 1 );
 		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
 	}		
-	ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
 
 	return 0;
 }

Modified: openldap/trunk/contrib/slapd-modules/cloak/cloak.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/cloak/cloak.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/cloak/cloak.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/cloak/cloak.c,v 1.2.2.2 2009/03/17 16:42:59 quanah Exp $ */
 /* cloak.c - Overlay to hide some attribute except if explicitely requested */
-/* 
- * Copyright 2008 Emmanuel Dreyfus
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/cloak/cloak.c,v 1.2.2.3 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 Emmanuel Dreyfus
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,6 +14,11 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the Emmanuel Dreyfus for
+ * inclusion in OpenLDAP Software.
+ */
+
 #include "portable.h"
 
 #ifdef SLAPD_OVER_CLOAK

Modified: openldap/trunk/contrib/slapd-modules/cloak/slapo-cloak.5
===================================================================
--- openldap/trunk/contrib/slapd-modules/cloak/slapo-cloak.5	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/cloak/slapo-cloak.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,7 @@
 .TH SLAPO-CLOAK 5 "RELEASEDATE" "OpenLDAP LDVERSION"
 .\" Copyright 1998-2009 The OpenLDAP Foundation, All Rights Reserved.
 .\" Copying restrictions apply.  See the COPYRIGHT file.
-.\" $OpenLDAP: pkg/ldap/contrib/slapd-modules/cloak/slapo-cloak.5,v 1.1.2.2 2009/01/22 00:00:45 kurt Exp $
+.\" $OpenLDAP: pkg/ldap/contrib/slapd-modules/cloak/slapo-cloak.5,v 1.1.2.3 2009/08/17 21:48:57 quanah Exp $
 .SH NAME
 slapo-cloak \- Attribute cloak overlay to slapd
 .SH SYNOPSIS
@@ -79,4 +79,4 @@
 .BR back-config .
 .SH ACKNOWLEDGEMENTS
 .P
-This module was written in 2008 by Emmanuel Dreyfus.
+This module was originally written in 2008 by Emmanuel Dreyfus.

Modified: openldap/trunk/contrib/slapd-modules/dsaschema/dsaschema.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/dsaschema/dsaschema.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/dsaschema/dsaschema.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,7 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/dsaschema/dsaschema.c,v 1.5.2.4 2009/01/22 00:00:45 kurt Exp $ */
-/*
+/* dsaschema.c */
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/dsaschema/dsaschema.c,v 1.5.2.5 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
  * Copyright 2004-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *

Modified: openldap/trunk/contrib/slapd-modules/nops/nops.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nops/nops.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nops/nops.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nops/nops.c,v 1.1.2.3 2009/04/28 00:51:12 quanah Exp $ */
 /* nops.c - Overlay to filter idempotent operations */
-/* 
- * Copyright 2008 Emmanuel Dreyfus
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nops/nops.c,v 1.1.2.4 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Copyright 2008 Emmanuel Dreyfus.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,6 +14,10 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by the Emmanuel Dreyfus for
+ * inclusion in OpenLDAP Software.
+ */
 #include "portable.h"
 
 #ifdef SLAPD_OVER_NOPS

Modified: openldap/trunk/contrib/slapd-modules/nssov/Makefile
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/Makefile	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/Makefile	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,6 +1,9 @@
-# $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/Makefile,v 1.1.2.2 2009/06/03 20:46:54 quanah Exp $
-# Copyright 2008 Howard Chu, Symas Corp. All Rights Reserved.
+# $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/Makefile,v 1.1.2.5 2009/09/01 22:53:30 quanah Exp $
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
 #
+# Copyright 2008-2009 The OpenLDAP Foundation.
+# Portions Copyright 2008 Howard Chu, Symas Corp. All Rights Reserved.
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
 # Public License.
@@ -27,8 +30,18 @@
 LDAP_LIB=-lldap_r -llber
 LIBS=$(LDAP_LIB)
 
-all:	nssov.la
+prefix=/usr/local
+exec_prefix=$(prefix)
+ldap_subdir=/openldap
 
+libdir=$(exec_prefix)/lib
+libexecdir=$(exec_prefix)/libexec
+moduledir = $(libexecdir)$(ldap_subdir)
+sysconfdir = $(prefix)/etc$(ldap_subdir)
+schemadir = $(sysconfdir)/schema
+
+all:	install
+
 XOBJS = tio.lo
 
 OBJS = alias.lo ether.lo group.lo host.lo netgroup.lo network.lo \
@@ -37,7 +50,7 @@
 .SUFFIXES: .c .o .lo
 
 .c.lo:
-	$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $?
+	$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
 
 tio.lo:	nss-ldapd/common/tio.c
 	$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(NLDAPD_INC) -c $?
@@ -46,4 +59,12 @@
 
 nssov.la:	$(OBJS) $(XOBJS)
 	$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info 0:0:0 \
-	-rpath /usr/local/libexec/openldap -module -o $@ $(OBJS) $(XOBJS) $(LIBS)
+	-rpath $(libdir) -module -o $@ $(OBJS) $(XOBJS) $(LIBS)
+
+install: nssov.la
+	mkdir -p $(DESTDIR)$(moduledir)
+	$(LIBTOOL) --mode=install cp nssov.la $(DESTDIR)$(moduledir)
+	cp ldapns.schema $(DESTDIR)$(schemadir)
+
+clean:
+	rm -f *.*o *.la .libs/*

Modified: openldap/trunk/contrib/slapd-modules/nssov/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,13 +1,3 @@
-Copyright 2008-2009 Howard Chu, Symas Corp. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in the file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-<http://www.OpenLDAP.org/license.html>.
-
 This directory contains a slapd overlay, nssov, that handles
 NSS lookup requests through a local Unix Domain socket. It uses the
 same IPC protocol as Arthur de Jong's nss-ldapd, and a complete
@@ -124,3 +114,18 @@
 
 Password management: the overlay will perform a PasswordModify exop
 in the server for the given user.
+
+---
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
+
+Copyright 1998-2009 The OpenLDAP Foundation.
+Portions Copyright 2008-2009 Howard Chu, Symas Corp. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+

Modified: openldap/trunk/contrib/slapd-modules/nssov/alias.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/alias.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/alias.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* alias.c - mail alias lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/alias.c,v 1.1.2.2 2009/06/03 20:46:54 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/alias.c,v 1.1.2.3 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/ether.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/ether.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/ether.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,6 +1,8 @@
 /* ether.c - ethernet address lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/ether.c,v 1.1.2.2 2009/06/03 20:46:54 quanah Exp $ */
-/*
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/ether.c,v 1.1.2.3 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
  * Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/group.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/group.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/group.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* group.c - group lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/group.c,v 1.1.2.3 2009/06/03 20:46:54 quanah Exp $ */
-/*
- * Copyright 2008-2009 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/group.c,v 1.1.2.4 2009/08/17 21:48:57 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008-2009 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/host.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/host.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/host.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* host.c - host lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/host.c,v 1.1.2.2 2009/06/03 20:46:54 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/host.c,v 1.1.2.4 2009/08/24 17:35:29 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.
@@ -72,7 +74,7 @@
 	} else {
 		dupname = -1;
 		for (i=0; i<numname; i++) {
-			if ( ber_bvmatch(&name, &a->a_nvals[i])) {
+			if ( bvmatch(&name, &a->a_nvals[i])) {
 				dupname = i;
 				break;
 			}

Modified: openldap/trunk/contrib/slapd-modules/nssov/ldapns.schema
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/ldapns.schema	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/ldapns.schema	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,4 @@
-# $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/ldapns.schema,v 1.2.2.2 2009/06/03 20:46:55 quanah Exp $
-# $Id: ldapns.schema,v 1.3 2003/05/29 12:57:29 lukeh Exp $
+# $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/ldapns.schema,v 1.2.2.3 2009/08/17 21:48:58 quanah Exp $
 # LDAP Name Service Additional Schema
 # http://www.iana.org/assignments/gssapi-service-names
 

Modified: openldap/trunk/contrib/slapd-modules/nssov/netgroup.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/netgroup.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/netgroup.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* netgroup.c - netgroup lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/netgroup.c,v 1.1.2.2 2009/06/03 20:46:55 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/netgroup.c,v 1.1.2.3 2009/08/17 21:48:58 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/network.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/network.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/network.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* network.c - network address lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/network.c,v 1.1.2.2 2009/06/03 20:46:55 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/network.c,v 1.1.2.4 2009/08/24 17:35:29 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.
@@ -72,7 +74,7 @@
 	} else {
 		dupname = -1;
         for (i=0; i<numname; i++) {
-            if ( ber_bvmatch(&name, &a->a_nvals[i])) {
+            if ( bvmatch(&name, &a->a_nvals[i])) {
                 dupname = i;
                 break;
             }

Modified: openldap/trunk/contrib/slapd-modules/nssov/nssov.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/nssov.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/nssov.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* nssov.c - nss-ldap overlay for slapd */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/nssov.c,v 1.1.2.4 2009/06/04 18:15:49 quanah Exp $ */
-/*
- * Copyright 2008-2009 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/nssov.c,v 1.1.2.5 2009/08/17 21:48:58 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/nssov.h
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/nssov.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/nssov.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,18 @@
 /* nssov.h - NSS overlay header file */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/nssov.h,v 1.1.2.4 2009/06/03 20:46:55 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/nssov.h,v 1.1.2.5 2009/08/17 21:48:58 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
  * Portions Copyright 2008 Howard Chu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
  */
 
 #ifndef NSSOV_H

Modified: openldap/trunk/contrib/slapd-modules/nssov/pam.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/pam.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/pam.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* pam.c - pam processing routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/pam.c,v 1.13.2.2 2009/06/03 20:46:55 quanah Exp $ */
-/*
- * Copyright 2009 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/pam.c,v 1.13.2.3 2009/08/17 21:48:58 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without

Modified: openldap/trunk/contrib/slapd-modules/nssov/passwd.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/passwd.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/passwd.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* passwd.c - password lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/passwd.c,v 1.1.2.4 2009/06/03 20:46:55 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/passwd.c,v 1.1.2.5 2009/08/17 21:48:58 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/nssov/protocol.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/protocol.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/protocol.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* protocol.c - network protocol lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/protocol.c,v 1.1.2.2 2009/06/03 20:46:55 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/protocol.c,v 1.1.2.4 2009/08/24 17:35:29 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -13,6 +15,7 @@
  * <http://www.OpenLDAP.org/license.html>.
  */
 /*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.
@@ -72,7 +75,7 @@
 	} else {
 		dupname = -1;
 		for (i=0; i<numname; i++) {
-			if ( ber_bvmatch(&name, &a->a_nvals[i])) {
+			if ( bvmatch(&name, &a->a_nvals[i])) {
 				dupname = i;
 				break;
 			}

Modified: openldap/trunk/contrib/slapd-modules/nssov/rpc.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/rpc.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/rpc.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* rpc.c - rpc lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/rpc.c,v 1.1.2.2 2009/06/03 20:46:56 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/rpc.c,v 1.1.2.4 2009/08/24 17:35:29 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.
@@ -75,7 +77,7 @@
 	} else {
 		dupname = -1;
 		for (i=0; i<numname; i++) {
-			if ( ber_bvmatch(&name, &a->a_nvals[i])) {
+			if ( bvmatch(&name, &a->a_nvals[i])) {
 				dupname = i;
 				break;
 			}

Modified: openldap/trunk/contrib/slapd-modules/nssov/service.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/service.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/service.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* service.c - service lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/service.c,v 1.1.2.2 2009/06/03 20:46:56 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/service.c,v 1.1.2.4 2009/08/24 17:35:29 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.
@@ -137,7 +139,7 @@
 	} else {
 		dupname = -1;
 		for (i=0; i<numname; i++) {
-			if ( ber_bvmatch(&name, &a->a_nvals[i])) {
+			if ( bvmatch(&name, &a->a_nvals[i])) {
 				dupname = i;
 				break;
 			}

Modified: openldap/trunk/contrib/slapd-modules/nssov/shadow.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/nssov/shadow.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/nssov/shadow.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* shadow.c - shadow account lookup routines */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/shadow.c,v 1.1.2.2 2009/06/03 20:46:56 quanah Exp $ */
-/*
- * Copyright 2008 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/shadow.c,v 1.1.2.3 2009/08/17 21:48:59 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
+ *
+ * Copyright 2008-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2008 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,7 +14,7 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * This code references portions of the nss-ldapd package
  * written by Arthur de Jong. The nss-ldapd code was forked
  * from the nss-ldap library written by Luke Howard.

Modified: openldap/trunk/contrib/slapd-modules/passwd/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,3 @@
-Copyright 2004-2009 The OpenLDAP Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
 This directory contains native slapd plugins for password mechanisms that
 are not actively supported by the project. Currently this includes the
 Kerberos, Netscape MTA-MD5 and RADIUS password mechanisms.
@@ -48,3 +42,17 @@
 (Actually, you might want to statically link the RADIUS client library 
 libradius.a into the module).
 
+---
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
+
+Copyright 2004-2009 The OpenLDAP Foundation.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+

Modified: openldap/trunk/contrib/slapd-modules/passwd/kerberos.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/kerberos.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/kerberos.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,6 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/kerberos.c,v 1.5.2.4 2009/01/22 00:00:46 kurt Exp $ */
-/*
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/kerberos.c,v 1.5.2.5 2009/08/17 21:48:59 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
  * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *

Modified: openldap/trunk/contrib/slapd-modules/passwd/netscape.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/netscape.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/netscape.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,6 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/netscape.c,v 1.5.2.4 2009/01/22 00:00:46 kurt Exp $ */
-/*
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/netscape.c,v 1.5.2.5 2009/08/17 21:48:59 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
  * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *

Modified: openldap/trunk/contrib/slapd-modules/passwd/radius.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/radius.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/radius.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,6 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/radius.c,v 1.2.2.5 2009/01/22 00:00:46 kurt Exp $ */
-/*
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/radius.c,v 1.2.2.6 2009/08/17 21:48:59 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
  * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *

Modified: openldap/trunk/contrib/slapd-modules/passwd/sha2/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/sha2/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/sha2/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,11 +1,6 @@
 SHA-512 OpenLDAP support
 ------------------------
 
-  Based on SHA2 implementation by Aaron D. Gifford (http://www.aarongifford.com/), also used in OpenBSD.
-  Adapted for OpenLDAP use by Jeff Turner <jeff at atlassian.com>
-  Distributed under open source BSD license - see code for details.
-
-
 slapd-sha2.c provides support for SHA-512, SHA-384 and SHA-256 hashed passwords in
 OpenLDAP. For instance, one could have the LDAP attribute:
 
@@ -25,20 +20,16 @@
 Building
 --------
 
-1) Obtain the OpenLDAP source, eg. 'apt-get source slapd'.  Really we
-only want the headers, but there doesn't seem to be a Debian package
-with them.
-
-2) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP
+1) Customize the OPENLDAP variable in Makefile to point to the OpenLDAP
 source root.
 
 For initial testing you might also want to edit CCFLAGS to define
 SLAPD_SHA2_DEBUG, which enables logging to stderr (don't leave this on
 in production, as it prints passwords in cleartext).
 
-3) Run 'make' to produce slapd-sha2.so
+2) Run 'make' to produce slapd-sha2.so
 
-4) Copy slapd-sha2.so somewhere permanent.
+3) Copy slapd-sha2.so somewhere permanent.
 
 4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add:
 
@@ -105,7 +96,7 @@
 $ sudo /etc/init.d/slapd stop
 Stopping OpenLDAP: slapd.
 $ sudo /usr/sbin/slapd -f /etc/ldap/slapd.conf -h ldap://localhost:389 -d 256
-@(#) $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/sha2/README,v 1.1.2.1 2009/01/26 21:07:06 quanah Exp $
+@(#) $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/sha2/README,v 1.1.2.2 2009/08/17 22:57:53 quanah Exp $
         buildd at palmer:/build/buildd/openldap2.3-2.4.9/debian/build/servers/slapd
 /etc/ldap/slapd.conf: line 123: rootdn is always granted unlimited privileges.
 /etc/ldap/slapd.conf: line 140: rootdn is always granted unlimited privileges.
@@ -122,10 +113,25 @@
 conn=0 op=1 SRCH base="dc=example,dc=com" scope=2 deref=0 filter="(objectClass=*)"
 conn=0 fd=12 closed (connection lost)
 
+---
 
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
-Origin
-------
+Copyright 2009 The OpenLDAP Foundation.
+All rights reserved.
 
-Based on code maintained at:
-http://confluence.atlassian.com/display/JIRAEXT/OpenLDAP+support+for+SHA-2+(SHA-256%2C+SHA-384%2C+SHA-512)+and+atlassian-sha1+passwords
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+
+---
+
+ACKNOWLEDGEMENT:
+This work was initially developed by Jeff Turner for inclusion in
+OpenLDAP Software, based upon the SHA2 implementation independently
+developed by Aaron Gifford.
+

Modified: openldap/trunk/contrib/slapd-modules/passwd/sha2/slapd-sha2.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/passwd/sha2/slapd-sha2.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/passwd/sha2/slapd-sha2.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,11 +1,29 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/sha2/slapd-sha2.c,v 1.1.2.1 2009/01/26 21:07:06 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/passwd/sha2/slapd-sha2.c,v 1.1.2.3 2009/08/17 22:57:54 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2009 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENT:
+ * This work was initially developed by Jeff Turner for inclusion
+ * in OpenLDAP Software.
+ */
+
 #include <lber.h>
-#include <lber_pvt.h> // Required for BER_BVC
-#include <ac/string.h> // Required for BER_BVC dep
+#include <lber_pvt.h>
+#include <ac/string.h>
 #include "lutil.h"
 #include <stdint.h>
-#include <string.h>	/* memcpy()/memset() or bcopy()/bzero() */
-#include <assert.h>	/* assert() */
+#include <string.h>
+#include <assert.h>
 #include "sha2.h"
 
 #ifdef SLAPD_SHA2_DEBUG

Modified: openldap/trunk/contrib/slapd-modules/proxyOld/Makefile
===================================================================
--- openldap/trunk/contrib/slapd-modules/proxyOld/Makefile	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/proxyOld/Makefile	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,6 +1,9 @@
-# $OpenLDAP: pkg/ldap/contrib/slapd-modules/proxyOld/Makefile,v 1.1 2006/03/30 06:22:39 hyc Exp $
-# Copyright 2005 Howard Chu, Symas Corp. All Rights Reserved.
+# $OpenLDAP: pkg/ldap/contrib/slapd-modules/proxyOld/Makefile,v 1.1.2.1 2009/08/17 21:48:59 quanah Exp $
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
 #
+# Copyright 2005-2009 The OpenLDAP Foundation.
+# Portions Copyright 2005 Howard Chu, Symas Corp. All Rights Reserved.
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted only as authorized by the OpenLDAP
 # Public License.

Modified: openldap/trunk/contrib/slapd-modules/proxyOld/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/proxyOld/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/proxyOld/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,13 +1,3 @@
-Copyright 2005 Howard Chu, Symas Corp. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in the file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-<http://www.OpenLDAP.org/license.html>.
-
 This directory contains a slapd module proxyOld that provides support
 for the obsolete draft-weltman-ldapb3-proxy-05 revision of the LDAP
 Proxy Authorization control. It is merely intended to provide compatibility
@@ -24,3 +14,18 @@
 not be advertised in the rootDSE's supportedControls attribute.
 
 This code only works as a dynamically loaded module.
+
+---
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
+
+Copyright 1998-2009 The OpenLDAP Foundation.
+Portions Copyright 2005 Howard Chu, Symas Corp. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+

Modified: openldap/trunk/contrib/slapd-modules/proxyOld/proxyOld.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/proxyOld/proxyOld.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/proxyOld/proxyOld.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* proxyOld.c - module for supporting obsolete (rev 05) proxyAuthz control */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/proxyOld/proxyOld.c,v 1.1 2006/03/30 06:22:39 hyc Exp $ */
-/*
- * Copyright 2005 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/proxyOld/proxyOld.c,v 1.1.2.1 2009/08/17 21:49:00 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2005-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2005 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without

Modified: openldap/trunk/contrib/slapd-modules/smbk5pwd/Makefile
===================================================================
--- openldap/trunk/contrib/slapd-modules/smbk5pwd/Makefile	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/smbk5pwd/Makefile	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,7 @@
-# $OpenLDAP: pkg/ldap/contrib/slapd-modules/smbk5pwd/Makefile,v 1.1.6.1 2009/04/27 23:36:57 quanah Exp $
+# $OpenLDAP: pkg/ldap/contrib/slapd-modules/smbk5pwd/Makefile,v 1.1.6.3 2009/09/01 22:53:30 quanah Exp $
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
+#
+# Copyright 1998-2009 The OpenLDAP Foundation.
 # Copyright 2004 Howard Chu, Symas Corp. All Rights Reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -26,6 +29,14 @@
 LDAP_LIB=-lldap_r -llber
 LIBS=$(LDAP_LIB) $(HEIMDAL_LIB) $(SSL_LIB)
 
+prefix=/usr/local
+exec_prefix=$(prefix)
+ldap_subdir=/openldap
+
+libdir=$(exec_prefix)/lib
+libexecdir=$(exec_prefix)/libexec
+moduledir = $(libexecdir)$(ldap_subdir)
+
 all:	smbk5pwd.la
 
 
@@ -34,12 +45,11 @@
 
 smbk5pwd.la:	smbk5pwd.lo
 	$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info 0:0:0 \
-	-rpath $(PREFIX)/lib -module -o $@ $? $(LIBS)
+	-rpath $(libdir) -module -o $@ $? $(LIBS)
 
 clean:
 	rm -f smbk5pwd.lo smbk5pwd.la
 
 install: smbk5pwd.la
-	mkdir -p $(PREFIX)/lib/openldap
-	$(LIBTOOL) --mode=install cp smbk5pwd.la $(PREFIX)/lib/openldap
-	$(LIBTOOL) --finish $(PREFIX)/lib
+	mkdir -p $(DESTDIR)$(moduledir)
+	$(LIBTOOL) --mode=install cp smbk5pwd.la $(DESTDIR)$(moduledir)

Modified: openldap/trunk/contrib/slapd-modules/smbk5pwd/README
===================================================================
--- openldap/trunk/contrib/slapd-modules/smbk5pwd/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/smbk5pwd/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,13 +1,3 @@
-Copyright 2004-2005 Howard Chu, Symas Corp. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
-A copy of this license is available in the file LICENSE in the
-top-level directory of the distribution or, alternatively, at
-<http://www.OpenLDAP.org/license.html>.
-
 This directory contains a slapd overlay, smbk5pwd, that extends the
 PasswordModify Extended Operation to update Kerberos keys and Samba
 password hashes for an LDAP user.
@@ -88,3 +78,17 @@
 slapd/overlays directory and edit the Makefile and overlays.c to reference
 it. You will also have to define SLAPD_OVER_SMBK5PWD to SLAPD_MOD_STATIC,
 and add the relevant libraries to the main slapd link command.
+
+---
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
+Copyright 2004-2009 The OpenLDAP Foundation.
+Portions Copyright 2004-2005 Howard Chu, Symas Corp. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+

Modified: openldap/trunk/contrib/slapd-modules/smbk5pwd/smbk5pwd.c
===================================================================
--- openldap/trunk/contrib/slapd-modules/smbk5pwd/smbk5pwd.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-modules/smbk5pwd/smbk5pwd.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,9 @@
 /* smbk5pwd.c - Overlay for managing Samba and Heimdal passwords */
-/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/smbk5pwd/smbk5pwd.c,v 1.17.2.15 2009/06/27 18:48:27 quanah Exp $ */
-/*
- * Copyright 2004-2005 by Howard Chu, Symas Corp.
+/* $OpenLDAP: pkg/ldap/contrib/slapd-modules/smbk5pwd/smbk5pwd.c,v 1.17.2.16 2009/08/17 21:49:00 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2004-2009 The OpenLDAP Foundation.
+ * Portions Copyright 2004-2005 by Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -12,11 +14,9 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
-/*
+/* ACKNOWLEDGEMENTS:
  * Support for table-driven configuration added by Pierangelo Masarati.
  * Support for sambaPwdMustChange and sambaPwdCanChange added by Marco D'Ettorre.
- *
- * The conditions of the OpenLDAP Public License apply.
  */
 
 #include <portable.h>

Modified: openldap/trunk/contrib/slapd-tools/README
===================================================================
--- openldap/trunk/contrib/slapd-tools/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-tools/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,3 +1,11 @@
+Directory contents:
+
+statslog
+	Program to output selected parts of slapd's statslog output
+	(LDAP request/response log), grouping log lines by LDAP
+	connection.  Useful to search and inspect the server log.
+
+---
 Copyright 2004-2009 The OpenLDAP Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -4,9 +12,7 @@
 modification, are permitted only as authorized by the OpenLDAP
 Public License.
 
-Directory contents:
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
 
-statslog
-	Program to output selected parts of slapd's statslog output
-	(LDAP request/response log), grouping log lines by LDAP
-	connection.  Useful to search and inspect the server log.

Modified: openldap/trunk/contrib/slapd-tools/statslog
===================================================================
--- openldap/trunk/contrib/slapd-tools/statslog	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapd-tools/statslog	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,8 +1,10 @@
 #!/usr/bin/perl -w
 # statslog - Rearrange and output selected parts of slapd's statslog output.
-# $OpenLDAP: pkg/ldap/contrib/slapd-tools/statslog,v 1.2 2004/11/02 16:19:17 hallvard Exp $
+# $OpenLDAP: pkg/ldap/contrib/slapd-tools/statslog,v 1.2.6.1 2009/08/17 21:49:00 quanah Exp $
+# This work is part of OpenLDAP Software <http://www.openldap.org/>.
 #
-# Copyright 2004 Hallvard B. Furuseth.
+# Copyright 1998-2009 The OpenLDAP Foundation.
+# Portions Copyright 2004 Hallvard B. Furuseth.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without

Modified: openldap/trunk/contrib/slapi-plugins/addrdnvalues/README
===================================================================
--- openldap/trunk/contrib/slapi-plugins/addrdnvalues/README	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapi-plugins/addrdnvalues/README	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,3 @@
-Copyright 2003-2009 The OpenLDAP Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted only as authorized by the OpenLDAP
-Public License.
-
 This directory contains a SLAPI plugin, addrdnvalues, which will add to
 an entry any attribute values that appear in the entry's RDN but not in
 the entry. This is necessary for compliance with some "broken" clients.
@@ -20,3 +14,16 @@
 
 to compile this plugin.
 
+---
+This work is part of OpenLDAP Software <http://www.openldap.org/>.
+
+Copyright 2003-2009 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
+A copy of this license is available in the file LICENSE in the
+top-level directory of the distribution or, alternatively, at
+<http://www.OpenLDAP.org/license.html>.
+

Modified: openldap/trunk/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c
===================================================================
--- openldap/trunk/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,8 @@
-/* $OpenLDAP: pkg/ldap/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c,v 1.6 2004/05/23 13:45:32 lukeh Exp $ */
-/*
+/* addrdnvalues.c */
+/* $OpenLDAP: pkg/ldap/contrib/slapi-plugins/addrdnvalues/addrdnvalues.c,v 1.6.6.1 2009/08/17 21:49:00 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2003-2009 The OpenLDAP Foundation.
  * Copyright 2003-2004 PADL Software Pty Ltd.
  * All rights reserved.
  *
@@ -11,6 +14,10 @@
  * top-level directory of the distribution or, alternatively, at
  * <http://www.OpenLDAP.org/license.html>.
  */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Luke Howard of PADL Software
+ * for inclusion in OpenLDAP Software.
+ */
 
 #include <string.h>
 #include <unistd.h>

Modified: openldap/trunk/debian/changelog
===================================================================
--- openldap/trunk/debian/changelog	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/debian/changelog	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,3 +1,9 @@
+openldap (2.4.18-1) UNRELEASED; urgency=low
+
+  * New upstream version
+
+ -- Steve Langasek <vorlon at debian.org>  Wed, 23 Sep 2009 10:57:07 -0700
+
 openldap (2.4.17-2) unstable; urgency=low
 
   * Fix up the lintian warnings:

Modified: openldap/trunk/debian/rules
===================================================================
--- openldap/trunk/debian/rules	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/debian/rules	2009-09-23 17:57:37 UTC (rev 1243)
@@ -42,7 +42,7 @@
 
 # These variables are used only by get-orig-source, which will normally only
 # be run by maintainers.
-VERSION = 2.4.15
+VERSION = 2.4.18
 URL     = http://www.openldap.org/software/download/OpenLDAP/openldap-release/
 
 # Download the upstream source and make changes as required for DFSG reasons.

Modified: openldap/trunk/doc/guide/admin/guide.html
===================================================================
--- openldap/trunk/doc/guide/admin/guide.html	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/guide/admin/guide.html	2009-09-23 17:57:37 UTC (rev 1243)
@@ -23,7 +23,7 @@
 <DIV CLASS="title">
 <H1 CLASS="doc-title">OpenLDAP Software 2.4 Administrator's Guide</H1>
 <ADDRESS CLASS="doc-author">The OpenLDAP Project &lt;<A HREF="http://www.openldap.org/">http://www.openldap.org/</A>&gt;</ADDRESS>
-<ADDRESS CLASS="doc-modified">13 July 2009</ADDRESS>
+<ADDRESS CLASS="doc-modified">6 September 2009</ADDRESS>
 <BR CLEAR="All">
 </DIV>
 <DIV CLASS="contents">
@@ -5440,7 +5440,7 @@
 <P>There are two ways password policy can be applied to individual objects:</P>
 <P>1. The pwdPolicySubentry in a user's object - If a user's object has a pwdPolicySubEntry attribute specifying the DN of a policy object, then the policy defined by that object is applied.</P>
 <P>2. Default password policy - If there is no specific pwdPolicySubentry set for an object, and the password policy module was configured with the DN of a default policy object and if that object exists, then the policy defined in that object is applied.</P>
-<P>Please see <EM>slapo-ppolicy(5)</EM> for complete explanations of features and discussion of &quot;Password Management Issues&quot; at <A HREF="http://www.connexitor.com/forums/viewtopic.php?f=6&amp;t=25">http://www.connexitor.com/forums/viewtopic.php?f=6&amp;t=25</A></P>
+<P>Please see <EM>slapo-ppolicy(5)</EM> for complete explanations of features and discussion of &quot;Password Management Issues&quot; at <A HREF="http://www.symas.com/blog/?page_id=66">http://www.symas.com/blog/?page_id=66</A></P>
 <H3><A NAME="Further Information">12.10.3. Further Information</A></H3>
 <P><EM>slapo-ppolicy(5)</EM></P>
 <H2><A NAME="Referential Integrity">12.11. Referential Integrity</A></H2>

Modified: openldap/trunk/doc/guide/admin/overlays.sdf
===================================================================
--- openldap/trunk/doc/guide/admin/overlays.sdf	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/guide/admin/overlays.sdf	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-# $OpenLDAP: pkg/openldap-guide/admin/overlays.sdf,v 1.8.2.26 2009/01/22 00:00:47 kurt Exp $
+# $OpenLDAP: pkg/openldap-guide/admin/overlays.sdf,v 1.8.2.27 2009/08/25 23:01:58 quanah Exp $
 # Copyright 2007-2009 The OpenLDAP Foundation, All Rights Reserved.
 # COPYING RESTRICTIONS APPLY, see COPYRIGHT.
 
@@ -925,7 +925,7 @@
 that object is applied.
 
 Please see {{slapo-ppolicy(5)}} for complete explanations of features and discussion of
- "Password Management Issues" at {{URL:http://www.connexitor.com/forums/viewtopic.php?f=6&t=25}}
+ "Password Management Issues" at {{URL:http://www.symas.com/blog/?page_id=66}}
 
 
 H3: Further Information

Modified: openldap/trunk/doc/man/man1/ldapsearch.1
===================================================================
--- openldap/trunk/doc/man/man1/ldapsearch.1	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man1/ldapsearch.1	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 .TH LDAPSEARCH 1 "RELEASEDATE" "OpenLDAP LDVERSION"
-.\" $OpenLDAP: pkg/ldap/doc/man/man1/ldapsearch.1,v 1.59.2.10 2009/06/03 01:41:52 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man1/ldapsearch.1,v 1.59.2.11 2009/07/22 20:02:20 quanah Exp $
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
 .SH NAME
@@ -93,13 +93,13 @@
 opens a connection to an LDAP server, binds, and performs a search
 using specified parameters.   The \fIfilter\fP should conform to
 the string representation for search filters as defined in RFC 4515.
-If not provided, the default filter, (objectClass=*), is used.
+If not provided, the default filter, \fB(objectClass=*)\fP, is used.
 .LP
 If
 .B ldapsearch
 finds one or more entries, the attributes specified by
-\fIattrs\fP are returned.  If * is listed, all user attributes are
-returned.  If + is listed, all operational attributes are returned.
+\fIattrs\fP are returned.  If \fB*\fP is listed, all user attributes are
+returned.  If \fB+\fP is listed, all operational attributes are returned.
 If no \fIattrs\fP are listed, all user attributes are returned.  If only
 1.1 is listed, no attributes will be returned.
 .LP
@@ -109,12 +109,12 @@
 .TP
 .B \-n
 Show what would be done, but don't actually perform the search.  Useful for
-debugging in conjunction with -v.
+debugging in conjunction with \fB\-v\fP.
 .TP
 .B \-c
 Continuous operation mode. Errors are reported, but ldapsearch will continue
 with searches. The default is to exit after reporting an error.  Only useful
-in conjunction with -f.
+in conjunction with \fB\-f\fP.
 .TP
 .B \-u
 Include the User Friendly Name form of the Distinguished Name (DN)
@@ -274,13 +274,14 @@
 
 Search extensions:
 .nf
-  [!]domainScope                               (domain scope)
-  [!]mv=<filter>                               (matched values filter)
+  [!]domainScope                       (domain scope)
+  [!]mv=<filter>                       (matched values filter)
   [!]pr=<size>[/prompt|noprompt]       (paged results/prompt)
   [!]sss=[\-]<attr[:OID]>[/[\-]<attr[:OID]>...]  (server side sorting)
   [!]subentries[=true|false]           (subentries)
-  [!]sync=ro[/<cookie>]                        (LDAP Sync refreshOnly)
+  [!]sync=ro[/<cookie>]                (LDAP Sync refreshOnly)
           rp[/<cookie>][/<slimit>]     (LDAP Sync refreshAndPersist)
+  [!]vlv=<before>/<after>(/<offset>/<count>|:<value>)  (virtual list view)
 .fi
 .TP
 .BI \-l \ timelimit

Modified: openldap/trunk/doc/man/man3/ldap_get_option.3
===================================================================
--- openldap/trunk/doc/man/man3/ldap_get_option.3	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man3/ldap_get_option.3	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 .TH LDAP_GET_OPTION 3 "RELEASEDATE" "OpenLDAP LDVERSION"
-.\" $OpenLDAP: pkg/ldap/doc/man/man3/ldap_get_option.3,v 1.3.2.7 2009/06/03 01:41:54 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man3/ldap_get_option.3,v 1.3.2.8 2009/08/27 20:30:49 quanah Exp $
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
 .SH NAME
@@ -29,15 +29,142 @@
 argument.
 Global options are set/retrieved by passing a NULL LDAP handle.
 .TP
+.B LDAP_OPT_API_FEATURE_INFO
+Fills-in a 
+.BR "LDAPAPIFeatureInfo" ;
+.BR outvalue 
+must be a 
+.BR "LDAPAPIFeatureInfo *" ,
+pointing to an already allocated struct.
+This is a read-only option.
+.TP
 .B LDAP_OPT_API_INFO
 Fills-in a 
-.BR "struct ldapapiinfo" ;
+.BR "LDAPAPIInfo" ;
 .BR outvalue 
 must be a 
-.BR "struct ldapapiinfo *" ,
+.BR "LDAPAPIInfo *" ,
 pointing to an already allocated struct.
 This is a read-only option.
 .TP
+.B LDAP_OPT_CLIENT_CONTROLS
+Sets/gets the client-side controls to be used for all operations.
+This is now deprecated as modern LDAP C API provides replacements
+for all main operations which accepts client-side controls as
+explicit arguments; see for example
+.BR ldap_search_ext (3),
+.BR ldap_add_ext (3),
+.BR ldap_modify_ext (3)
+and so on.
+.BR outvalue
+must be 
+.BR "LDAPControl ***" ,
+and the caller is responsible of freeing the returned controls, if any,
+by calling 
+.BR ldap_controls_free (3),
+while
+.BR invalue
+must be 
+.BR "LDAPControl *const *" ;
+the library duplicates the controls passed via
+.BR invalue .
+.TP
+.B LDAP_OPT_CONNECT_ASYNC
+Sets/gets the status of the asynchronous connect flag.
+.BR invalue
+should either be
+.BR LDAP_OPT_OFF
+or
+.BR LDAP_OPT_ON ;
+.BR outvalue
+must be
+.BR "int *" .
+When set, the library will call
+.BR connect (2)
+and return, without waiting for response.
+This leaves the handle in a connecting state.
+Subsequent calls to library routines will poll for completion
+of the connect before performing further operations.
+As a consequence, library calls that need to establish a connection
+with a DSA do not block even for the network timeout
+(option
+.BR LDAP_OPT_NETWORK_TIMEOUT ).
+This option is OpenLDAP specific.
+.TP
+.B LDAP_OPT_CONNECT_CB
+This option allows to set a connect callback.
+.B invalue
+must be a 
+.BR "const struct ldap_conncb *" .
+Callbacks are executed in last in-first served order.
+Handle-specific callbacks are executed first, followed by global ones.
+Right before freeing the callback structure, the
+.B lc_del
+callback handler is passed a 
+.B NULL
+.BR Sockbuf .
+Calling
+.BR ldap_get_option (3)
+for this option removes the callback whose pointer matches
+.BR outvalue .
+This option is OpenLDAP specific.
+.TP
+.B LDAP_OPT_DEBUG_LEVEL
+Sets/gets the debug level of the client library.
+.BR invalue
+must be a 
+.BR "const int *" ;
+.BR outvalue
+must be a
+.BR "int *" .
+Valid debug levels are 
+.BR LDAP_DEBUG_ANY ,
+.BR LDAP_DEBUG_ARGS ,
+.BR LDAP_DEBUG_BER ,
+.BR LDAP_DEBUG_CONNS ,
+.BR LDAP_DEBUG_NONE ,
+.BR LDAP_DEBUG_PACKETS ,
+.BR LDAP_DEBUG_PARSE ,
+and
+.BR LDAP_DEBUG_TRACE .
+This option is OpenLDAP specific.
+.TP
+.B LDAP_OPT_DEFBASE
+Sets/gets a string containing the DN to be used as default base
+for search operations.
+.BR outvalue
+must be a
+.BR "char **" ,
+and the caller is responsible of freeing the returned string by calling
+.BR ldap_memfree (3),
+while
+.BR invalue
+must be a 
+.BR "const char *" ;
+the library duplicates the corresponding string.
+This option is OpenLDAP specific.
+.TP
+.B LDAP_OPT_DEREF
+Sets/gets the value that defines when alias dereferencing must occur.
+.BR invalue
+must be
+.BR "const int *" ;
+.BR outvalue 
+must be
+.BR "int *" .
+They cannot be NULL.
+The value of 
+.BR *invalue
+should be one of
+.BR LDAP_DEREF_NEVER
+(the default),
+.BR LDAP_DEREF_SEARCHING ,
+.BR LDAP_DEREF_FINDING ,
+or
+.BR LDAP_DEREF_ALWAYS .
+Note that this has ever been the only means to determine alias dereferencing
+within search operations.
+.TP
 .B LDAP_OPT_DESC
 Returns the file descriptor associated to the socket buffer
 of the LDAP handle passed in as 
@@ -45,30 +172,52 @@
 .BR outvalue
 must be a 
 .BR "int *" .
-This is a read-only, handler-specific option.
+This is a read-only, handle-specific option.
 .TP
-.B LDAP_OPT_SOCKBUF
-Returns a pointer to the socket buffer of the LDAP handle passed in as
-.BR ld ;
+.B LDAP_OPT_DIAGNOSTIC_MESSAGE
+Sets/gets a string containing the error string associated to the LDAP handle.
+This option was formerly known as 
+.BR LDAP_OPT_ERROR_STRING .
 .BR outvalue
+must be a
+.BR "char **" ,
+and the caller is responsible of freeing the returned string by calling
+.BR ldap_memfree (3),
+while
+.BR invalue
 must be a 
-.BR "Sockbuf **" .
-This is a read-only, handler-specific option.
+.BR "char *" ;
+the library duplicates the corresponding string.
 .TP
-.B LDAP_OPT_TIMEOUT
-Sets/gets a timeout value for the synchronous API calls.
-.B outvalue
+.B LDAP_OPT_HOST_NAME
+Sets/gets a space-separated list of hosts to be contacted by the library 
+when trying to establish a connection.
+This is now deprecated in favor of
+.BR LDAP_OPT_URI .
+.BR outvalue
 must be a 
-.BR "struct timeval **"
-(the caller has to free
-.BR *outvalue ) ,
-and
-.B invalue
+.BR "char **" ,
+and the caller is responsible of freeing the resulting string by calling
+.BR ldap_memfree (3),
+while
+.BR invalue
 must be a 
-.BR "struct timeval *" ,
-and they cannot be NULL. Using a struct with seconds set to \-1 results
-in an infinite timeout, which is the default.
+.BR "const char *" ;
+the library duplicates the corresponding string.
 .TP
+.B LDAP_OPT_MATCHED_DN
+Sets/gets a string containing the matched DN associated to the LDAP handle.
+.BR outvalue
+must be a
+.BR "char **" ,
+and the caller is responsible of freeing the returned string by calling
+.BR ldap_memfree (3),
+while
+.BR invalue
+must be a 
+.BR "const char *" ;
+the library duplicates the corresponding string.
+.TP
 .B LDAP_OPT_NETWORK_TIMEOUT
 Sets/gets the network timeout value after which
 .BR poll (2)/ select (2) 
@@ -83,69 +232,72 @@
 and
 .B invalue
 must be a 
-.BR "struct timeval *" ,
-and they cannot be NULL. Using a struct with seconds set to \-1 results
+.BR "const struct timeval *" .
+They cannot be NULL. Using a struct with seconds set to \-1 results
 in an infinite timeout, which is the default.
+This option is OpenLDAP specific.
 .TP
-.B LDAP_OPT_DEREF
-Sets/gets the value that defines when alias dereferencing must occur.
-.BR outvalue 
-and 
+.B LDAP_OPT_PROTOCOL_VERSION
+Sets/gets the protocol version.
+.BR outvalue
+and
 .BR invalue
-must be
-.BR "int *" ,
-and they cannot be NULL.
+must be 
+.BR "int *" .
 .TP
-.B LDAP_OPT_SIZELIMIT
-Sets/gets the value that defines the maximum number of entries
-to be returned by a search operation.
-.BR outvalue 
-and 
+.B LDAP_OPT_REFERRAL_URLS
+Sets/gets an array containing the referral URIs associated to the LDAP handle.
+.BR outvalue
+must be a
+.BR "char ***" ,
+and the caller is responsible of freeing the returned string by calling
+.BR ldap_memvfree (3),
+while
 .BR invalue
-must be
-.BR "int *" ,
-and they cannot be NULL.
+must be a NULL-terminated
+.BR "char *const *" ;
+the library duplicates the corresponding string.
+This option is OpenLDAP specific.
 .TP
-.B LDAP_OPT_TIMELIMIT
-Sets/gets the value that defines the time limit after which
-a search operation should be terminated by the server.
-.BR outvalue 
-and 
-.BR invalue
-must be
-.BR "int *" ,
-and they cannot be NULL.
-.TP
 .B LDAP_OPT_REFERRALS
 Determines whether the library should implicitly chase referrals or not.
-.BR outvalue
-and
 .BR invalue
 must be 
-.BR "int *" ;
-their value should either be
+.BR "const int *" ;
+its value should either be
 .BR LDAP_OPT_OFF
 or
 .BR LDAP_OPT_ON .
+.BR outvalue
+must be
+.BR "int *" .
+.\".TP
+.\".B LDAP_OPT_REFHOPLIMIT
+.\"This option is OpenLDAP specific.
+.\"It is not currently implemented.
 .TP
 .B LDAP_OPT_RESTART
 Determines whether the library should implicitly restart connections (FIXME).
-.BR outvalue
-and
 .BR invalue
 must be 
-.BR "int *" ;
-their value should either be
+.BR "const int *" ;
+its value should either be
 .BR LDAP_OPT_OFF
 or
 .BR LDAP_OPT_ON .
+.BR outvalue
+must be
+.BR "int *" .
 .TP
-.B LDAP_OPT_PROTOCOL_VERSION
-Sets/gets the protocol version.
+.B LDAP_OPT_RESULT_CODE
+Sets/gets the LDAP result code associated to the handle.
+This option was formerly known as
+.BR LDAP_OPT_ERROR_NUMBER .
+.BR invalue
+must be a 
+.BR "const int *" .
 .BR outvalue
-and
-.BR invalue
-must be 
+must be a
 .BR "int *" .
 .TP
 .B LDAP_OPT_SERVER_CONTROLS
@@ -166,50 +318,60 @@
 while
 .BR invalue
 must be 
-.BR "LDAPControl **" ;
+.BR "LDAPControl *const *" ;
 the library duplicates the controls passed via
 .BR invalue .
 .TP
-.B LDAP_OPT_CLIENT_CONTROLS
-Sets/gets the client-side controls to be used for all operations.
-This is now deprecated as modern LDAP C API provides replacements
-for all main operations which accepts client-side controls as
-explicit arguments; see for example
-.BR ldap_search_ext (3),
-.BR ldap_add_ext (3),
-.BR ldap_modify_ext (3)
-and so on.
+.B LDAP_OPT_SIZELIMIT
+Sets/gets the value that defines the maximum number of entries
+to be returned by a search operation.
+.BR invalue
+must be
+.BR "const int *" ,
+while
 .BR outvalue
-must be 
-.BR "LDAPControl ***" ,
-and the caller is responsible of freeing the returned controls, if any,
-by calling 
-.BR ldap_controls_free (3),
-while
-.BR invalue
-must be 
-.BR "LDAPControl **" ;
-the library duplicates the controls passed via
-.BR invalue .
+must be
+.BR "int *" ;
+They cannot be NULL.
 .TP
-.B LDAP_OPT_HOST_NAME
-Sets/gets a space-separated list of hosts to be contacted by the library 
-when trying to establish a connection.
-This is now deprecated in favor of
-.BR LDAP_OPT_URI .
+.B LDAP_OPT_SOCKBUF
+Returns a pointer to the socket buffer of the LDAP handle passed in as
+.BR ld ;
 .BR outvalue
 must be a 
-.BR "char **" ,
-and the caller is responsible of freeing the resulting string by calling
-.BR ldap_memfree (3),
+.BR "Sockbuf **" .
+This is a read-only, handle-specific option.
+This option is OpenLDAP specific.
+.TP
+.B LDAP_OPT_TIMELIMIT
+Sets/gets the value that defines the time limit after which
+a search operation should be terminated by the server.
+.BR invalue
+must be
+.BR "const int *" ,
 while
-.BR invalue
+.BR outvalue
+must be
+.BR "int *" ,
+and they cannot be NULL.
+.TP
+.B LDAP_OPT_TIMEOUT
+Sets/gets a timeout value for the synchronous API calls.
+.B outvalue
 must be a 
-.BR "char *" ;
-the library duplicates the corresponding string.
+.BR "struct timeval **"
+(the caller has to free
+.BR *outvalue ) ,
+and
+.B invalue
+must be a 
+.BR "struct timeval *" ,
+and they cannot be NULL. Using a struct with seconds set to \-1 results
+in an infinite timeout, which is the default.
+This option is OpenLDAP specific.
 .TP
 .B LDAP_OPT_URI
-Sets/gets a space-separated list of URIs to be contacted by the library 
+Sets/gets a comma- or space-separated list of URIs to be contacted by the library 
 when trying to establish a connection.
 .BR outvalue
 must be a 
@@ -219,96 +381,366 @@
 while
 .BR invalue
 must be a 
-.BR "char *" ;
+.BR "const char *" ;
 the library parses the string into a list of 
 .BR LDAPURLDesc
 structures, so the invocation of 
 .BR ldap_set_option (3)
 may fail if URL parsing fails.
+URIs may only contain the
+.BR schema ,
+the
+.BR host ,
+and the
+.BR port
+fields.
+This option is OpenLDAP specific.
+.SH SASL OPTIONS
+The SASL options are OpenLDAP specific.
 .TP
-.B LDAP_OPT_DEFBASE
-Sets/gets a string containing the DN to be used as default base
-for search operations.
+.B LDAP_OPT_X_SASL_AUTHCID
+Gets the SASL authentication identity;
 .BR outvalue
 must be a
 .BR "char **" ,
-and the caller is responsible of freeing the returned string by calling
-.BR ldap_memfree (3),
+its content needs to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_SASL_AUTHZID
+Gets the SASL authorization identity;
+.BR outvalue
+must be a
+.BR "char **" ,
+its content needs to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_SASL_MAXBUFSIZE
+Gets/sets SASL maximum buffer size;
+.BR invalue
+must be
+.BR "const ber_len_t *" ,
 while
-.BR invalue
-must be a 
-.BR "char *" ;
-the library duplicates the corresponding string.
+.BR outvalue
+must be
+.BR "ber_len_t *" .
+See also
+.BR LDAP_OPT_X_SASL_SECPROPS .
 .TP
-.B LDAP_OPT_RESULT_CODE
-Sets/gets the LDAP result code associated to the handle.
-This option was formerly known as
-.BR LDAP_OPT_ERROR_NUMBER .
-Both
+.B LDAP_OPT_X_SASL_MECH
+Gets the SASL mechanism;
 .BR outvalue
-and
+must be a
+.BR "char **" ,
+its content needs to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_SASL_MECHLIST
+Gets the list of the available mechanisms,
+in form of a NULL-terminated array of strings;
+.BR outvalue
+must be
+.BR "char ***" .
+The caller must not free or otherwise muck with it.
+.TP
+.B LDAP_OPT_X_SASL_NOCANON	
+Sets/gets the NOCANON flag.
+When unset, the hostname is canonicalized.
 .BR invalue
-must be a 
+must be
+.BR "const int *" ;
+its value should either be
+.BR LDAP_OPT_OFF
+or
+.BR LDAP_OPT_ON .
+.BR outvalue
+must be
 .BR "int *" .
 .TP
-.B LDAP_OPT_DIAGNOSTIC_MESSAGE
-Sets/gets a string containing the error string associated to the LDAP handle.
-This option was formerly known as 
-.BR LDAP_OPT_ERROR_STRING .
+.B LDAP_OPT_X_SASL_REALM
+Gets the SASL realm;
 .BR outvalue
 must be a
 .BR "char **" ,
-and the caller is responsible of freeing the returned string by calling
-.BR ldap_memfree (3),
-while
+its content needs to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_SASL_SECPROPS
+Sets the SASL secprops;
 .BR invalue
-must be a 
-.BR "char *" ;
-the library duplicates the corresponding string.
+must be a
+.BR "char *" ,
+containing a comma-separated list of properties.
+Legal values are:
+.BR none ,
+.BR nodict ,
+.BR noplain ,
+.BR noactive ,
+.BR passcred ,
+.BR forwardsec ,
+.BR noanonymous ,
+.BR minssf=<minssf> ,
+.BR maxssf=<maxssf> ,
+.BR maxbufsize=<maxbufsize> .
 .TP
-.B LDAP_OPT_MATCHED_DN
-Sets/gets a string containing the matched DN associated to the LDAP handle.
+.B LDAP_OPT_X_SASL_SSF
+Gets the SASL SSF;
 .BR outvalue
 must be a
-.BR "char **" ,
-and the caller is responsible of freeing the returned string by calling
-.BR ldap_memfree (3),
+.BR "ber_len_t *" .
+.TP
+.B LDAP_OPT_X_SASL_SSF_EXTERNAL
+Sets the SASL SSF value related to an authentication
+performed using an EXTERNAL mechanism;
+.BR invalue
+must be a
+.BR "const ber_len_t *" .
+.TP
+.B LDAP_OPT_X_SASL_SSF_MAX
+Gets/sets SASL maximum SSF;
+.BR invalue
+must be
+.BR "const ber_len_t *" ,
 while
+.BR outvalue
+must be
+.BR "ber_len_t *" .
+See also
+.BR LDAP_OPT_X_SASL_SECPROPS .
+.TP
+.B LDAP_OPT_X_SASL_SSF_MIN
+Gets/sets SASL minimum SSF;
 .BR invalue
-must be a 
-.BR "char *" ;
-the library duplicates the corresponding string.
+must be
+.BR "const ber_len_t *" ,
+while
+.BR outvalue
+must be
+.BR "ber_len_t *" .
+See also
+.BR LDAP_OPT_X_SASL_SECPROPS .
 .TP
-.B LDAP_OPT_REFERRAL_URLS
-Sets/gets an array containing the referral URIs associated to the LDAP handle.
+.B LDAP_OPT_X_SASL_USERNAME
+Gets the SASL username;
 .BR outvalue
 must be a
-.BR "char ***" ,
-and the caller is responsible of freeing the returned string by calling
-.BR ber_memvfree (3),
-while
+.BR "char **" .
+Its content needs to be freed by the caller using
+.BR ldap_memfree (3).
+.SH TCP OPTIONS
+The TCP options are OpenLDAP specific.
+Mainly intended for use with Linux, they may not be portable.
+.TP
+.B LDAP_OPT_X_KEEPALIVE_IDLE
+Sets/gets the number of seconds a connection needs to remain idle
+before TCP starts sending keepalive probes.
 .BR invalue
-must be a NULL-terminated
-.BR "char **" ;
-the library duplicates the corresponding string.
+must be
+.BR "const int *" ;
+.BR outvalue
+must be
+.BR "int *" .
 .TP
-.B LDAP_OPT_API_FEATURE_INFO
-Fills-in a 
-.BR "LDAPAPIFeatureInfo" ;
-.BR outvalue 
-must be a 
-.BR "LDAPAPIFeatureInfo *" ,
-pointing to an already allocated struct.
-This is a read-only option.
+.B LDAP_OPT_X_KEEPALIVE_PROBES
+Sets/gets the maximum number of keepalive probes TCP should send
+before dropping the connection.
+.BR invalue
+must be
+.BR "const int *" ;
+.BR outvalue
+must be
+.BR "int *" .
 .TP
-.B LDAP_OPT_DEBUG_LEVEL
-Sets/gets the debug level of the client library.
-Both
+.B LDAP_OPT_X_KEEPALIVE_INTERVAL
+Sets/gets the interval in seconds between individual keepalive probes.
+.BR invalue
+must be
+.BR "const int *" ;
 .BR outvalue
+must be
+.BR "int *" .
+.SH TLS OPTIONS
+The TLS options are OpenLDAP specific.
+.\".TP
+.\".B LDAP_OPT_X_TLS
+.\"Sets/gets the TLS mode.
+.TP
+.B LDAP_OPT_X_TLS_CACERTDIR
+Sets/gets the path of the directory containing CA certificates.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_TLS_CACERTFILE
+Sets/gets the full-path of the CA certificate file.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_TLS_CERTFILE
+Sets/gets the full-path of the certificate file.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_TLS_CIPHER_SUITE
+Sets/gets the allowed cipher suite.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_TLS_CONNECT_ARG
+Sets/gets the connection callback argument.
+.BR invalue
+must be
+.BR "const void *" ;
+.BR outvalue
+must be
+.BR "void **" .
+.TP
+.B LDAP_OPT_X_TLS_CONNECT_CB
+Sets/gets the connection callback handle.
+.BR invalue
+must be
+.BR "const LDAP_TLS_CONNECT_CB *" ;
+.BR outvalue
+must be
+.BR "LDAP_TLS_CONNECT_CB **" .
+.TP
+.B LDAP_OPT_X_TLS_CRLCHECK
+Sets/gets the CRL evaluation strategy, one of
+.BR LDAP_OPT_X_TLS_CRL_NONE ,
+.BR LDAP_OPT_X_TLS_CRL_PEER ,
+or
+.BR LDAP_OPT_X_TLS_CRL_ALL .
+.BR invalue
+must be
+.BR "const int *" ;
+.BR outvalue
+must be
+.BR "int *" .
+Requires OpenSSL.
+.TP
+.B LDAP_OPT_X_TLS_CRLFILE
+Sets/gets the full-path of the CRL file.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+This option is only valid for GnuTLS.
+.TP
+.B LDAP_OPT_X_TLS_CTX
+Sets/gets the TLS library context. New TLS sessions will inherit their
+default settings from this library context.
+.BR invalue
+must be
+.BR "const void *" ;
+.BR outvalue
+must be
+.BR "void **" .
+When using the OpenSSL library this is an SSL_CTX*. When using other
+crypto libraries this is a pointer to an OpenLDAP private structure.
+Applications generally should not use this option or attempt to
+manipulate this structure.
+.TP
+.B LDAP_OPT_X_TLS_DHFILE
+Gets/sets the full-path of the file containing the parameters
+for Diffie-Hellman ephemeral key exchange.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+Ignored by GnuTLS.
+.TP
+.B LDAP_OPT_X_TLS_KEYFILE
+Sets/gets the full-path of the certificate key file.
+.BR invalue
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+.TP
+.B LDAP_OPT_X_TLS_NEWCTX
+Instructs the library to create a new TLS library context.
+.BR invalue
+must be
+.BR "const int *" .
+A non-zero value pointed to by
+.BR invalue
+tells the library to create a context for a server.
+.TP
+.B LDAP_OPT_X_TLS_PROTOCOL_MIN
+Sets/gets the minimum protocol version.
+.BR invalue
+must be
+.BR "const int *" ;
+.BR outvalue
+must be
+.BR "int *" .
+.TP
+.B LDAP_OPT_X_TLS_RANDOM_FILE
+Sets/gets the random file when
+.B /dev/random
 and
+.B /dev/urandom
+are not available.
 .BR invalue
-must be a 
-.BR "int *" .
+must be
+.BR "const char *" ;
+.BR outvalue
+must be
+.BR "char **" ,
+and its contents need to be freed by the caller using
+.BR ldap_memfree (3).
+Ignored by GnuTLS older than version 2.2.
+.TP
+.B LDAP_OPT_X_TLS_REQUIRE_CERT
+Sets/gets the peer certificate checking strategy,
+one of
+.BR LDAP_OPT_X_TLS_NEVER ,
+.BR LDAP_OPT_X_TLS_HARD ,
+.BR LDAP_OPT_X_TLS_DEMAND ,
+.BR LDAP_OPT_X_TLS_ALLOW ,
+.BR LDAP_OPT_X_TLS_TRY .
+.TP
+.B LDAP_OPT_X_TLS_SSL_CTX
+Gets the TLS session context associated with this handle.
+.BR outvalue
+must be
+.BR "void **" .
+When using the OpenSSL library this is an SSL*. When using other
+crypto libraries this is a pointer to an OpenLDAP private structure.
+Applications generally should not use this option.
 .SH ERRORS
 On success, the functions return
 .BR LDAP_OPT_SUCCESS ,
@@ -328,6 +760,16 @@
 referral chasing features, or explicitly disable referral chasing
 by setting that option to
 .BR LDAP_OPT_OFF .
+.P
+The protocol version used by the library defaults to LDAPv2 (now historic),
+which corresponds to the
+.B LDAP_VERSION2
+macro.
+Application developers are encouraged to explicitly set
+.B LDAP_OPT_PROTOCOL_VERSION
+to LDAPv3, using the 
+.B LDAP_VERSION3
+macro, or to allow users to select the protocol version.
 .SH SEE ALSO
 .BR ldap (3),
 .BR ldap_error (3),

Modified: openldap/trunk/doc/man/man3/ldap_open.3
===================================================================
--- openldap/trunk/doc/man/man3/ldap_open.3	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man3/ldap_open.3	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 .TH LDAP_OPEN 3 "RELEASEDATE" "OpenLDAP LDVERSION"
-.\" $OpenLDAP: pkg/ldap/doc/man/man3/ldap_open.3,v 1.16.2.5 2009/06/03 01:41:54 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man3/ldap_open.3,v 1.16.2.6 2009/08/25 22:53:47 quanah Exp $
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
 .SH NAME
@@ -93,6 +93,29 @@
 but it returns an integer indicating either success or the failure reason,
 and it allows to specify details for the connection in the schema portion
 of the URI.
+The
+.I uri
+parameter may be a comma- or whitespace-separated list of URIs
+containing only the
+.IR schema ,
+the
+.IR host ,
+and the
+.I port
+fields.
+Apart from
+.BR ldap ,
+other (non-standard) recognized values of the
+.I schema
+field are
+.B ldaps
+(LDAP over TLS),
+.B ldapi
+(LDAP over IPC),
+and
+.B cldap
+(connectionless LDAP).
+If other fields are present, the behavior is undefined.
 .LP
 At this time,
 .B ldap_open()
@@ -134,14 +157,17 @@
 .B ldap_open()
 and
 .B ldap_init()
-will return NULL and errno should be set appropriately.
+will return NULL and 
+.I errno
+should be set appropriately.
 .B ldap_initialize()
 and
 .B ldap_init_fd()
 will directly return the LDAP code associated to the error (or
 .I LDAP_SUCCESS
 in case of success);
-errno should be set as well whenever appropriate.
+.I errno
+should be set as well whenever appropriate.
 .SH SEE ALSO
 .BR ldap (3),
 .BR ldap_bind (3),

Modified: openldap/trunk/doc/man/man5/slapd-bdb.5
===================================================================
--- openldap/trunk/doc/man/man5/slapd-bdb.5	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man5/slapd-bdb.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,7 @@
 .TH SLAPD-BDB 5 "RELEASEDATE" "OpenLDAP LDVERSION"
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd-bdb.5,v 1.31.2.11 2009/06/19 21:53:42 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd-bdb.5,v 1.31.2.12 2009/07/27 17:38:40 quanah Exp $
 .SH NAME
 slapd\-bdb, slapd\-hdb \- Berkeley DB backends to slapd
 .SH SYNOPSIS
@@ -145,11 +145,12 @@
 will return a different result.
 .TP
 .BI dncachesize \ <integer>
-Specify the maximum number of DNs in the in-memory DN cache. The
-default is twice the \fBcachesize\fP. Ideally this cache should be
+Specify the maximum number of DNs in the in-memory DN cache.
+Ideally this cache should be
 large enough to contain the DNs of every entry in the database. If
 set to a smaller value than the \fBcachesize\fP it will be silently
-increased to equal the \fBcachesize\fP.
+increased to equal the \fBcachesize\fP. The default value is 0 which
+means unlimited, i.e. the DN cache will grow without bound.
 
 It should be noted that the \fBDN cache\fP is allowed to temporarily
 grow beyond the configured size. It does this if many entries are 

Modified: openldap/trunk/doc/man/man5/slapd-config.5
===================================================================
--- openldap/trunk/doc/man/man5/slapd-config.5	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man5/slapd-config.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,7 @@
 .TH SLAPD-CONFIG 5 "RELEASEDATE" "OpenLDAP LDVERSION"
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd-config.5,v 1.13.2.18 2009/06/27 18:45:36 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd-config.5,v 1.13.2.19 2009/08/25 22:44:24 quanah Exp $
 .SH NAME
 slapd\-config \- configuration backend to slapd
 .SH SYNOPSIS
@@ -747,6 +747,16 @@
 Specify the maximum incoming LDAP PDU size for authenticated sessions.
 The default is 4194303.
 .TP
+.B olcTCPBuffer [listener=<URL>] [{read|write}=]<size>
+Specify the size of the TCP buffer.
+A global value for both read and write TCP buffers related to any listener
+is defined, unless the listener is explicitly specified,
+or either the read or write qualifiers are used.
+See
+.BR tcp (7)
+for details.
+Note that some OS-es implement automatic TCP buffer tuning.
+.TP
 .B olcThreads: <integer>
 Specify the maximum size of the primary thread pool.
 The default is 16; the minimum value is 2.

Modified: openldap/trunk/doc/man/man5/slapd.conf.5
===================================================================
--- openldap/trunk/doc/man/man5/slapd.conf.5	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man5/slapd.conf.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,7 +1,7 @@
 .TH SLAPD.CONF 5 "RELEASEDATE" "OpenLDAP LDVERSION"
 .\" Copyright 1998-2009 The OpenLDAP Foundation All Rights Reserved.
 .\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
-.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd.conf.5,v 1.239.2.32 2009/06/27 18:45:36 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapd.conf.5,v 1.239.2.33 2009/08/25 22:44:24 quanah Exp $
 .SH NAME
 slapd.conf \- configuration file for slapd, the stand-alone LDAP daemon
 .SH SYNOPSIS
@@ -961,6 +961,16 @@
 attributes' syntax and matching rules and may not correspond to
 lexical order or any other recognizable order.
 .TP
+.B tcp-buffer [listener=<URL>] [{read|write}=]<size>
+Specify the size of the TCP buffer.
+A global value for both read and write TCP buffers related to any listener
+is defined, unless the listener is explicitly specified,
+or either the read or write qualifiers are used.
+See
+.BR tcp (7)
+for details.
+Note that some OS-es implement automatic TCP buffer tuning.
+.TP
 .B threads <integer>
 Specify the maximum size of the primary thread pool.
 The default is 16; the minimum value is 2.

Modified: openldap/trunk/doc/man/man5/slapo-pcache.5
===================================================================
--- openldap/trunk/doc/man/man5/slapo-pcache.5	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/doc/man/man5/slapo-pcache.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -2,9 +2,9 @@
 .\" Copyright 1998-2009 The OpenLDAP Foundation, All Rights Reserved.
 .\" Copying restrictions apply.  See the COPYRIGHT file.
 .\" Copyright 2001, Pierangelo Masarati, All rights reserved. <ando at sys-net.it>
-.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapo-pcache.5,v 1.14.2.10 2009/06/03 01:41:59 quanah Exp $
+.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapo-pcache.5,v 1.14.2.11 2009/08/25 21:24:46 quanah Exp $
 .SH NAME
-slapo\-pcache \- proxycache overlay to slapd
+slapo\-pcache \- proxy cache overlay to slapd
 .SH SYNOPSIS
 ETCDIR/slapd.conf
 .SH DESCRIPTION
@@ -15,7 +15,7 @@
 allows caching of LDAP search requests (queries) in a local database.
 For an incoming query, the
 proxy cache determines its corresponding \fBtemplate\fP. If the template
-was specified as cacheable using the \fBproxytemplate\fP directive
+was specified as cacheable using the \fBpcacheTemplate\fP directive
 and the request is contained in a cached request, it is answered from 
 the proxy cache.
 Otherwise, the search is performed as usual and cacheable search results 
@@ -32,9 +32,9 @@
 
 .LP 
 The config directives that are specific to the
-.B proxycache
+.B pcache
 overlay can be prefixed by
-.BR proxycache\- ,
+.BR pcache\- ,
 to avoid conflicts with directives specific to the underlying database
 or to other stacked overlays.  This may be particularly useful for those
 directives that refer to the backend used for local storage.
@@ -51,28 +51,28 @@
 .BR sql
 backends.
 .TP
-.B proxycache <database> <max_entries> <numattrsets> <entry_limit> <cc_period> 
+.B pcache <database> <max_entries> <numattrsets> <entry_limit> <cc_period> 
 The directive enables proxy caching in the current backend and sets general
 cache parameters. A <database> backend will be used internally to maintain
 the cached entries. The chosen database will need to be configured as well,
 as shown below. Cache replacement is invoked when the cache size grows to 
 <max_entries> entries and continues till the cache size drops below this size.
-<numattrsets> should be equal to the number of following \fBproxyattrset\fP
+<numattrsets> should be equal to the number of following \fBpcacheAttrset\fP
 directives. Queries are cached only if they correspond to a cacheable template
-(specified by the \fBproxytemplate\fP directive) and the number of entries
+(specified by the \fBpcacheTemplate\fP directive) and the number of entries
 returned is less than <entry_limit>. Consistency check is performed every
 <cc_period> duration (specified in secs). In each cycle queries with expired
 "time to live(\fBTTL\fP)" are removed. A sample cache configuration is: 
 .LP
 .RS
-proxycache \fBbdb 10000 1 50 100\fP
+pcache \fBbdb 10000 1 50 100\fP
 .RE
 
 .TP
-.B proxyattrset <index> <attrs...>
+.B pcacheAttrset <index> <attrs...>
 Used to associate a set of attributes <attrs..> with an <index>. Each attribute
 set is associated with an integer from 0 to <numattrsets>\-1. These indices are
-used by the \fBproxytemplate\fP directive to define cacheable templates. 
+used by the \fBpcacheTemplate\fP directive to define cacheable templates. 
 A set of attributes cannot be empty.  A set of attributes can contain the
 special attributes "*" (all user attributes), "+" (all operational attributes)
 or both; in the latter case, any other attribute is redundant and should
@@ -80,11 +80,11 @@
 attribute; in this case, only the presence of the entries is cached.
 
 .TP
-.B proxycachequeries <queries>
+.B pcacheMaxQueries <queries>
 Specify the maximum number of queries to cache. The default is 10000.
 
 .TP
-.B proxycheckcacheability { TRUE | FALSE }
+.B pcacheValidate { TRUE | FALSE }
 Check whether the results of a query being cached can actually be returned
 from the cache by the proxy DSA.  When enabled, the entries being returned
 while caching the results of a query are checked to ensure consistency
@@ -92,25 +92,33 @@
 is not cached.  By default, the check is off.
 
 .TP
-.B proxysavequeries { TRUE | FALSE }
+.B pcacheOffline { TRUE | FALSE }
+Set the cache to offline mode. While offline, the consistency checker
+will be stopped and no expirations will occur. This allows the cache
+contents to be used indefinitely while the proxy is cut off from network
+access to the remote DSA.  The default is FALSE, i.e. consistency
+checks and expirations will be performed.
+
+.TP
+.B pcachePersist { TRUE | FALSE }
 Specify whether the cached queries should be saved across restarts
 of the caching proxy, to provide hot startup of the cache.  Only non-expired
 queries are reloaded.  The default is FALSE.
 
 .BR CAVEAT :
-of course, the configuration of the proxycache must not change
+of course, the configuration of the proxy cache must not change
 across restarts; the pcache overlay does not perform any consistency
 checks in this sense.
 In detail, this option should be disabled unless the existing
-.B proxyattrset
+.B pcacheAttrset
 and
-.B proxytemplate
+.B pcacheTemplate
 directives are not changed neither in order nor in contents.
 If new sets and templates are added, or if other details of the pcache
 overlay configuration changed, this feature should not be affected.
 
 .TP
-.B proxytemplate <template_string> <attrset_index> <ttl> [<negttl> [<limitttl>]]
+.B pcacheTemplate <template_string> <attrset_index> <ttl> [<negttl> [<limitttl> [<ttr>]]]
 Specifies a cacheable template and "time to live" <ttl> of queries 
 belonging to the template. An optional <negttl> can be used to specify
 that negative results (i.e., queries that returned zero entries)
@@ -119,9 +127,37 @@
 An optional <limitttl> can be used to specify that results
 hitting a sizelimit should also be cached for the specified amount of time.
 Results hitting a sizelimit are not cached by default (<limitttl> set to 0).
+An optional <ttr> "time to refresh" can be used to specify that cached
+entries should be automatically refreshed after a certain time. Entries
+will only be refreshed while they have not expired, so the <ttl> should
+be larger than the <ttr> for this option to be useful. Entries are not
+refreshed by default (<ttr> set to 0).
 
 .TP
-.B response\-callback { head | tail }
+.B pcacheBind <filter_template> <attrset_index> <ttr> <scope> <base>
+Specifies a template for caching Simple Bind credentials based on an
+already defined \fBpcacheTemplate\fP. The <filter_template> is similar
+to a <template_string> except that it may have some values present. Its
+purpose is to allow the overlay to generate filters similar to what other
+applications do when they do a Search immediately before a Bind. E.g.,
+if a client like nss_ldap is configured to search for a user with the
+filter "(&(objectClass=posixAccount)(uid=<username>))" then the corresponding
+template "(&(objectClass=posixAccount)(uid=))" should be used here. When
+converted to a regular template e.g. "(&(objectClass=)(uid=))" this
+template and the <attrset_index> must match an already defined
+\fBpcacheTemplate\fP clause. The "time to refresh" <ttr> determines the
+time interval after which the cached credentials may be refreshed. The
+first Bind request that occurs after that time will trigger the refresh
+attempt. Refreshes are not performed when the overlay is Offline. There
+is no "time to live" parameter for the Bind credentials; the credentials
+will expire according to the \fBpcacheTemplate\fP ttl. The <scope> and
+<base> should match the search scope and base used by the authentication
+clients. The cached credentials are not stored in cleartext, they are
+hashed using the default password hash.
+By default Bind caching is not enabled.
+
+.TP
+.B pcachePosition { head | tail }
 Specifies whether the response callback should be placed at the
 .B tail
 (the default) or at the 
@@ -146,10 +182,10 @@
 
 .B <numattrsets>
 attribute sets SHOULD be defined by using the directive
-.BR proxyattrset ;
+.BR pcacheAttrset ;
 
 all attribute sets SHOULD be referenced by (at least) one
-.B proxytemplate
+.B pcacheTemplate
 directive; 
 
 .LP
@@ -158,8 +194,8 @@
 .LP
 .RS
 .nf
-proxyattrset \fB0 mail postaladdress telephonenumber\fP
-proxytemplate \fB(&(sn=)(givenName=)) 0 3600\fP
+pcacheAttrset \fB0 mail postaladdress telephonenumber\fP
+pcacheTemplate \fB(&(sn=)(givenName=)) 0 3600\fP
 .fi
 .RE
 
@@ -176,14 +212,48 @@
 .LP
 Any valid directives for the chosen database type may be used. Indexing
 should be used as appropriate for the queries being handled. In addition,
-an equality index on the \fBqueryid\fP attribute should be configured, to
+an equality index on the \fBpcacheQueryid\fP attribute should be configured, to
 assist in the removal of expired query data.
+.SH BACKWARD COMPATIBILITY
+The configuration keywords have been renamed and the older form is
+deprecated. These older keywords are still recognized but may disappear
+in future releases.
+
+.TP
+.B proxycache
+use pcache
+
+.TP
+.B proxyattrset
+use pcacheAttrset
+
+.TP
+.B proxycachequeries
+use pcacheMaxQueries
+
+.TP
+.B proxycheckcacheability
+use pcacheValidate
+
+.TP
+.B proxysavequeries
+use pcachePersist
+
+.TP
+.B proxytemplate
+use pcacheTemplate
+
+.TP
+.B response-callback
+use pcachePosition
+
 .SH CAVEATS
 Caching data is prone to inconsistencies because updates on the remote server
 will not be reflected in the response of the cache at least (and at most)
 for the duration of the
-.B proxytemplate
+.B pcacheTemplate
 .BR TTL .
+These inconsistencies can be minimized by careful use of the TTR.
 
 The remote server should expose the
 .B objectClass 

Copied: openldap/trunk/doc/man/man5/slapo-sssvlv.5 (from rev 1241, openldap/vendor/openldap-release/doc/man/man5/slapo-sssvlv.5)
===================================================================
--- openldap/trunk/doc/man/man5/slapo-sssvlv.5	                        (rev 0)
+++ openldap/trunk/doc/man/man5/slapo-sssvlv.5	2009-09-23 17:57:37 UTC (rev 1243)
@@ -0,0 +1,53 @@
+.TH SLAPO-SSSVLV 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 2009 The OpenLDAP Foundation All Rights Reserved.
+.\" Copyright 2009 Symas Corporation All Rights Reserved.
+.\" Copying restrictions apply.  See COPYRIGHT/LICENSE.
+.\" $OpenLDAP: pkg/ldap/doc/man/man5/slapo-sssvlv.5,v 1.1.2.2 2009/07/22 20:02:21 quanah Exp $
+.SH NAME
+slapo\-sssvlv \- Server Side Sorting and Virtual List View overlay to slapd
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+This overlay implements the LDAP Server Side Sorting (RFC2891) control
+as well as the Virtual List View control. It also replaces the default
+implementation of the LDAP PagedResults (RFC2696) control, to ensure
+that it works with Sorting. The overlay can be used with any backend
+or globally for all backends.
+
+Since a complete result set must be generated in memory before sorting can
+be performed, processing sort requests can have a large impact on the
+server's memory use. As such, any connection is limited to having only
+one sort request active at a time. Additional limits may be configured
+as described below.
+
+.SH CONFIGURATION
+These
+.B slapd.conf
+options apply to the SSSVLV overlay.
+They should appear after the
+.B overlay
+directive.
+.TP
+.B sssvlv\-max <num>
+Set the maximum number of concurrent sort requests allowed across all
+connections. The default is one half of the number of server threads.
+.TP
+.B sssvlv\-maxkeys <num>
+Set the maximum number of keys allowed in a sort request. The default is 5.
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.TP
+ETCDIR/slapd.d
+default slapd configuration directory
+.SH SEE ALSO
+.BR slapd.conf (5),
+.BR slapd\-config (5).
+.LP
+"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/)
+.LP
+IETF LDAP Virtual List View proposal by D. Boreham, J. Sermersheim,
+and A. Kashi in IETF document "draft-ietf-ldapext-ldapv3-vlv-09.txt".
+.SH AUTHOR
+Howard Chu

Modified: openldap/trunk/include/ac/unistd.h
===================================================================
--- openldap/trunk/include/ac/unistd.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/include/ac/unistd.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* Generic unistd.h */
-/* $OpenLDAP: pkg/ldap/include/ac/unistd.h,v 1.37.2.4 2009/01/22 00:00:52 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/include/ac/unistd.h,v 1.37.2.5 2009/08/13 00:11:17 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -34,12 +34,7 @@
 #if defined(HAVE_GETPASSPHRASE)
 LDAP_LIBC_F(char*)(getpassphrase)();
 
-#elif defined(HAVE_GETPASS)
-#define getpassphrase(p) getpass(p)
-LDAP_LIBC_F(char*)(getpass)();
-
 #else
-#define NEED_GETPASSPHRASE 1
 #define getpassphrase(p) lutil_getpass(p)
 LDAP_LUTIL_F(char*)(lutil_getpass) LDAP_P((const char *getpass));
 #endif

Modified: openldap/trunk/include/lber.h
===================================================================
--- openldap/trunk/include/lber.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/include/lber.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/include/lber.h,v 1.99.2.6 2009/05/01 19:28:57 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/include/lber.h,v 1.99.2.8 2009/08/13 00:56:58 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -165,7 +165,6 @@
 
 typedef struct berelement BerElement;
 typedef struct sockbuf Sockbuf;
-typedef struct seqorset Seqorset;
 
 typedef struct sockbuf_io Sockbuf_IO;
 
@@ -229,10 +228,6 @@
 ber_dump LDAP_P((
 	BerElement *ber, int inout ));
 
-LBER_F( void )
-ber_sos_dump LDAP_P((
-	Seqorset *sos ));
-
 /*
  * in decode.c:
  */
@@ -256,6 +251,16 @@
 	ber_len_t *len ));
 
 LBER_F( ber_tag_t )
+ber_skip_element LDAP_P((
+	BerElement *ber,
+	struct berval *bv ));
+
+LBER_F( ber_tag_t )
+ber_peek_element LDAP_P((
+	LDAP_CONST BerElement *ber,
+	struct berval *bv ));
+
+LBER_F( ber_tag_t )
 ber_get_int LDAP_P((
 	BerElement *ber,
 	ber_int_t *num ));
@@ -434,7 +439,7 @@
 	BerElement *ber,
 	LDAP_CONST char *buf,
 	ber_len_t len,
-	int nosos ));
+	int zero ));	/* nonzero is unsupported from OpenLDAP 2.4.18 */
 
 LBER_F( void )
 ber_free LDAP_P((

Modified: openldap/trunk/include/ldap.h
===================================================================
--- openldap/trunk/include/ldap.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/include/ldap.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/include/ldap.h,v 1.312.2.20 2009/03/05 20:20:47 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/include/ldap.h,v 1.312.2.23 2009/08/25 22:52:17 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  * 
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -186,11 +186,19 @@
 #define LDAP_OPT_X_SASL_MAXBUFSIZE		0x6109
 #define LDAP_OPT_X_SASL_MECHLIST		0x610a /* read-only */
 #define LDAP_OPT_X_SASL_NOCANON			0x610b
+#define LDAP_OPT_X_SASL_USERNAME		0x610c /* read-only */
 
 /* OpenLDAP GSSAPI options */
 #define LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT      0x6200
 #define LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL   0x6201
 
+/*
+ * OpenLDAP per connection tcp-keepalive settings
+ * (Linux only, ignored where unsupported)
+ */
+#define LDAP_OPT_X_KEEPALIVE_IDLE		0x6300
+#define LDAP_OPT_X_KEEPALIVE_PROBES		0x6301
+#define LDAP_OPT_X_KEEPALIVE_INTERVAL	0x6302
 
 /* Private API Extensions -- reserved for application use */
 #define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x7000  /* Private API inclusive */
@@ -246,7 +254,6 @@
 #define LDAP_CONTROL_PRE_READ			"1.3.6.1.1.13.1"		/* RFC 4527 */
 #define LDAP_CONTROL_POST_READ			"1.3.6.1.1.13.2"		/* RFC 4527 */
 
-/*  standard track - not implemented in slapd(8) */
 #define LDAP_CONTROL_SORTREQUEST    "1.2.840.113556.1.4.473" /* RFC 2891 */
 #define LDAP_CONTROL_SORTRESPONSE	"1.2.840.113556.1.4.474" /* RFC 2891 */
 
@@ -349,11 +356,10 @@
 #define LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY	0x4
 #define LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME	0x8
 
-/* LDAP VLV *//* not implemented in slapd(8) */
+/* LDAP VLV */
 #define LDAP_CONTROL_VLVREQUEST    	"2.16.840.1.113730.3.4.9"
 #define LDAP_CONTROL_VLVRESPONSE    "2.16.840.1.113730.3.4.10"
 
-
 /* LDAP Unsolicited Notifications */
 #define	LDAP_NOTICE_OF_DISCONNECTION	"1.3.6.1.4.1.1466.20036" /* RFC 4511 */
 #define LDAP_NOTICE_DISCONNECT LDAP_NOTICE_OF_DISCONNECTION
@@ -618,6 +624,8 @@
 #define LDAP_RESULTS_TOO_LARGE		0x46 /* CLDAP */
 #define LDAP_AFFECTS_MULTIPLE_DSAS	0x47
 
+#define LDAP_VLV_ERROR				0x4C
+
 #define LDAP_OTHER					0x50
 
 /* LCUP operation codes (113-117) - not implemented */

Modified: openldap/trunk/include/portable.hin
===================================================================
--- openldap/trunk/include/portable.hin	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/include/portable.hin	2009-09-23 17:57:37 UTC (rev 1243)
@@ -48,6 +48,9 @@
 /* end of portable.h.pre */
 
 
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
 /* define to use both <string.h> and <strings.h> */
 #undef BOTH_STRINGS_H
 
@@ -214,9 +217,6 @@
 /* Define to 1 if you have the <getopt.h> header file. */
 #undef HAVE_GETOPT_H
 
-/* Define to 1 if you have the `getpass' function. */
-#undef HAVE_GETPASS
-
 /* Define to 1 if you have the `getpassphrase' function. */
 #undef HAVE_GETPASSPHRASE
 
@@ -253,18 +253,6 @@
 /* Define to 1 if you have the <grp.h> header file. */
 #undef HAVE_GRP_H
 
-/* define if you have GSSAPI */
-#undef HAVE_GSSAPI
-
-/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
-#undef HAVE_GSSAPI_GSSAPI_H
-
-/* Define to 1 if you have the <gssapi.h> header file. */
-#undef HAVE_GSSAPI_H
-
-/* Define to 1 if you have the `gss_oid_to_str' function. */
-#undef HAVE_GSS_OID_TO_STR
-
 /* Define to 1 if you have the `hstrerror' function. */
 #undef HAVE_HSTRERROR
 
@@ -376,6 +364,9 @@
 /* define this if you have mkversion */
 #undef HAVE_MKVERSION
 
+/* define if you have MozNSS */
+#undef HAVE_MOZNSS
+
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #undef HAVE_NDIR_H
 
@@ -385,6 +376,9 @@
 /* define if strerror_r returns char* instead of int */
 #undef HAVE_NONPOSIX_STRERROR_R
 
+/* Define to 1 if you have the <nssutil.h> header file. */
+#undef HAVE_NSSUTIL_H
+
 /* if you have NT Event Log */
 #undef HAVE_NT_EVENT_LOG
 
@@ -397,9 +391,6 @@
 /* define if you have OpenSSL */
 #undef HAVE_OPENSSL
 
-/* define if you have MozNSS */
-#undef HAVE_MOZNSS
-
 /* Define to 1 if you have the <openssl/bn.h> header file. */
 #undef HAVE_OPENSSL_BN_H
 
@@ -813,6 +804,9 @@
 /* define if select implicitly yields */
 #undef HAVE_YIELDING_SELECT
 
+/* Define to 1 if you have the `_vsnprintf' function. */
+#undef HAVE__VSNPRINTF
+
 /* define to 32-bit or greater integer type */
 #undef LBER_INT_T
 
@@ -909,19 +903,19 @@
 /* Define to the type of arg 5 for `select'. */
 #undef SELECT_TYPE_ARG5
 
-/* The size of a `int', as computed by sizeof. */
+/* The size of `int', as computed by sizeof. */
 #undef SIZEOF_INT
 
-/* The size of a `long', as computed by sizeof. */
+/* The size of `long', as computed by sizeof. */
 #undef SIZEOF_LONG
 
-/* The size of a `long long', as computed by sizeof. */
+/* The size of `long long', as computed by sizeof. */
 #undef SIZEOF_LONG_LONG
 
-/* The size of a `short', as computed by sizeof. */
+/* The size of `short', as computed by sizeof. */
 #undef SIZEOF_SHORT
 
-/* The size of a `wchar_t', as computed by sizeof. */
+/* The size of `wchar_t', as computed by sizeof. */
 #undef SIZEOF_WCHAR_T
 
 /* define to support per-object ACIs */
@@ -1014,6 +1008,9 @@
 /* define for Sequential Modify overlay */
 #undef SLAPD_OVER_SEQMOD
 
+/* define for ServerSideSort/VLV overlay */
+#undef SLAPD_OVER_SSSVLV
+
 /* define for Syncrepl Provider overlay */
 #undef SLAPD_OVER_SYNCPROV
 
@@ -1077,9 +1074,17 @@
 /* define to use 'long long' for MP */
 #undef USE_MP_LONG_LONG
 
-/* Define to 1 if your processor stores words with the most significant byte
-   first (like Motorola and SPARC, unlike Intel and VAX). */
-#undef WORDS_BIGENDIAN
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
 
 /* Define to the type of arg 3 for `accept'. */
 #undef ber_socklen_t

Modified: openldap/trunk/libraries/liblber/bprint.c
===================================================================
--- openldap/trunk/libraries/liblber/bprint.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblber/bprint.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/liblber/bprint.c,v 1.57.2.4 2009/01/22 00:00:53 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblber/bprint.c,v 1.57.2.5 2009/08/02 21:06:33 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -276,47 +276,21 @@
 	ber_bprint( ber->ber_ptr, len );
 }
 
+typedef struct seqorset Seqorset;
+
+/* Exists for binary compatibility with OpenLDAP 2.4.17-- */
 int
 ber_log_sos_dump(
 	int errlvl,
 	int loglvl,
 	Seqorset *sos )
 {
-	assert( sos != NULL );
-
-	if ( !ber_log_check( errlvl, loglvl )) {
-		return 0;
-	}
-
-	ber_sos_dump( sos );
-	return 1;
+	return 0;
 }
 
+/* Exists for binary compatibility with OpenLDAP 2.4.17-- */
 void
 ber_sos_dump(
 	Seqorset *sos )
 {
-	char buf[132];
-
-	assert( sos != NULL );
-
-	(*ber_pvt_log_print)( "*** sos dump ***\n" );
-
-	while ( sos != NULL ) {
-		sprintf( buf, "ber_sos_dump: clen %ld first %p ptr %p\n",
-		    (long) sos->sos_clen,
-			sos->sos_first,
-			sos->sos_ptr );
-		(*ber_pvt_log_print)( buf );
-
-		sprintf( buf, "              current len %ld contents:\n",
-		    (long) (sos->sos_ptr - sos->sos_first) );
-		(*ber_pvt_log_print)( buf );
-
-		ber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
-
-		sos = sos->sos_next;
-	}
-
-	(*ber_pvt_log_print)( "*** end dump ***\n" );
 }

Modified: openldap/trunk/libraries/liblber/decode.c
===================================================================
--- openldap/trunk/libraries/liblber/decode.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblber/decode.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* decode.c - ber input decoding routines */
-/* $OpenLDAP: pkg/ldap/libraries/liblber/decode.c,v 1.105.2.6 2009/01/22 00:00:53 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblber/decode.c,v 1.105.2.8 2009/08/13 00:56:58 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -33,17 +33,12 @@
 #include <stdio.h>
 
 #include <ac/stdlib.h>
-
 #include <ac/stdarg.h>
 #include <ac/string.h>
 #include <ac/socket.h>
 
 #include "lber-int.h"
 
-static ber_len_t ber_getnint LDAP_P((
-	BerElement *ber,
-	ber_int_t *num,
-	ber_len_t len ));
 
 /* out->bv_len should be the buffer size on input */
 int
@@ -91,182 +86,207 @@
 	return 0;
 }
 
-/* return the tag - LBER_DEFAULT returned means trouble */
-ber_tag_t
-ber_get_tag( BerElement *ber )
+/* Return tag, with *bv = rest of element (starting at length octets) */
+static ber_tag_t
+ber_tag_and_rest( const BerElement *ber, struct berval *bv )
 {
-	unsigned char	xbyte;
 	ber_tag_t	tag;
-	unsigned int	i;
+	ptrdiff_t	rest;
+	unsigned char	*ptr;
 
 	assert( ber != NULL );
 	assert( LBER_VALID( ber ) );
 
-	if ( ber_pvt_ber_remaining( ber ) < 1 ) {
-		return LBER_DEFAULT;
+	ptr = (unsigned char *) ber->ber_ptr;
+	rest = (unsigned char *) ber->ber_end - ptr;
+	if ( rest <= 0 ) {
+		goto fail;
 	}
 
-	if ( ber->ber_ptr == ber->ber_buf ) {
-		tag = *(unsigned char *)ber->ber_ptr;
-	} else {
-		tag = ber->ber_tag;
+	tag = ber->ber_tag;
+	if ( (char *) ptr == ber->ber_buf ) {
+		tag = *ptr;
 	}
-	ber->ber_ptr++;
-
+	ptr++;
+	rest--;
 	if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
-		return tag;
+		goto done;
 	}
 
-	for ( i = 1; i < sizeof(ber_tag_t); i++ ) {
-		if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 ) {
-			return LBER_DEFAULT;
+	do {
+		if ( rest <= 0 ) {
+			break;
 		}
-
 		tag <<= 8;
-		tag |= 0x00ffUL & (ber_tag_t) xbyte;
+		tag |= *ptr++ & 0xffU;
+		rest--;
 
-		if ( ! (xbyte & LBER_MORE_TAG_MASK) ) {
-			break;
+		if ( ! (tag & LBER_MORE_TAG_MASK) ) {
+			goto done;
 		}
-	}
+	} while ( tag <= (ber_tag_t)-1 / 256 );
 
-	/* tag too big! */
-	if ( i == sizeof(ber_tag_t) ) {
-		return LBER_DEFAULT;
-	}
+ fail:
+	/* Error or unsupported tag size */
+	tag = LBER_DEFAULT;
 
+ done:
+	bv->bv_len = rest;
+	bv->bv_val = (char *) ptr;
 	return tag;
 }
 
+/* Return the tag - LBER_DEFAULT returned means trouble */
 ber_tag_t
-ber_skip_tag( BerElement *ber, ber_len_t *len )
+ber_get_tag( BerElement *ber )
 {
+	struct berval bv;
+	ber_tag_t tag = ber_tag_and_rest( ber, &bv );
+
+	ber->ber_ptr = bv.bv_val;
+	return tag;
+}
+
+/* Return next element's tag and point *bv at its contents in-place */
+ber_tag_t
+ber_peek_element( const BerElement *ber, struct berval *bv )
+{
 	ber_tag_t	tag;
-	unsigned char	lc;
-	ber_len_t	i, noctets;
-	unsigned char netlen[sizeof(ber_len_t)];
+	ber_len_t	len, rest;
+	unsigned	i;
+	unsigned char *ptr;
 
-	assert( ber != NULL );
-	assert( len != NULL );
-	assert( LBER_VALID( ber ) );
+	assert( bv != NULL );
 
 	/*
 	 * Any ber element looks like this: tag length contents.
-	 * Assuming everything's ok, we return the tag byte (we
-	 * can assume a single byte), and return the length in len.
+	 * Assuming everything's ok, we return the tag, and point
+	 * bv at the contents.
 	 *
 	 * Assumptions:
 	 *	1) definite lengths
 	 *	2) primitive encodings used whenever possible
 	 */
 
-	*len = 0;
+	len = 0;
 
 	/*
 	 * First, we read the tag.
 	 */
+	tag = ber_tag_and_rest( ber, bv );
 
-	if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT ) {
-		return LBER_DEFAULT;
+	rest = bv->bv_len;
+	ptr = (unsigned char *) bv->bv_val;
+	if ( tag == LBER_DEFAULT || rest == 0 ) {
+		goto fail;
 	}
 
 	/*
-	 * Next, read the length.  The first byte contains the length of
-	 * the length.	If bit 8 is set, the length is the long form,
-	 * otherwise it's the short form.  We don't allow a length that's
-	 * greater than what we can hold in a ber_len_t.
+	 * Next, read the length.  The first octet determines the length
+	 * of the length.	If bit 8 is 0, the length is the short form,
+	 * otherwise if the octet != 0x80 it's the long form, otherwise
+	 * the ber element has the unsupported indefinite-length format.
+	 * Lengths that do not fit in a ber_len_t are not accepted.
 	 */
 
-	if ( ber_read( ber, (char *) &lc, 1 ) != 1 ) {
-		return LBER_DEFAULT;
-	}
+	len = *ptr++;
+	rest--;
 
-	if ( lc & 0x80U ) {
-		noctets = (lc & 0x7fU);
-
-		if ( noctets > sizeof(ber_len_t) ) {
-			return LBER_DEFAULT;
+	if ( len & 0x80U ) {
+		len &= 0x7fU;
+		if ( len - 1U > sizeof(ber_len_t) - 1U || rest < len ) {
+			/* Indefinite-length/too long length/not enough data */
+			goto fail;
 		}
 
-		if( (unsigned) ber_read( ber, (char *) netlen, noctets ) != noctets ) {
-			return LBER_DEFAULT;
+		rest -= len;
+		i = len;
+		for( len = *ptr++ & 0xffU; --i; len |= *ptr++ & 0xffU ) {
+			len <<= 8;
 		}
-
-		for( i = 0; i < noctets; i++ ) {
-			*len <<= 8;
-			*len |= netlen[i];
-		}
-
-	} else {
-		*len = lc;
 	}
 
 	/* BER element should have enough data left */
-	if( *len > (ber_len_t) ber_pvt_ber_remaining( ber ) ) {
-		return LBER_DEFAULT;
+	if( len > rest ) {
+	fail:
+		tag = LBER_DEFAULT;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
+	bv->bv_len = len;
+	bv->bv_val = (char *) ptr;
 	return tag;
 }
 
+/* Move past next element, point *bv at it in-place, and return its tag.
+ * The caller may \0-terminate *bv, as next octet is saved in ber->ber_tag.
+ * Similar to ber_get_stringbv(ber, bv, LBER_BV_NOTERM) except on error.
+ */
 ber_tag_t
+ber_skip_element( BerElement *ber, struct berval *bv )
+{
+	ber_tag_t tag = ber_peek_element( ber, bv );
+
+	if ( tag != LBER_DEFAULT ) {
+		ber->ber_ptr = bv->bv_val + bv->bv_len;
+		ber->ber_tag = *(unsigned char *) ber->ber_ptr;
+	}
+
+	return tag;
+}
+
+ber_tag_t
 ber_peek_tag(
 	BerElement *ber,
 	ber_len_t *len )
 {
-	/*
-	 * This implementation assumes ber_skip_tag() only
-	 * modifies ber_ptr field of the BerElement.
-	 */
+	struct berval bv;
+	ber_tag_t tag = ber_peek_element( ber, &bv );
 
-	char *save;
-	ber_tag_t	tag, old;
+	*len = bv.bv_len;
+	return tag;
+}
 
-	old = ber->ber_tag;
-	save = ber->ber_ptr;
-	tag = ber_skip_tag( ber, len );
-	ber->ber_ptr = save;
-	ber->ber_tag = old;
+ber_tag_t
+ber_skip_tag( BerElement *ber, ber_len_t *lenp )
+{
+	struct berval bv;
+	ber_tag_t tag = ber_peek_element( ber, &bv );
 
+	ber->ber_ptr = bv.bv_val;
+	ber->ber_tag = *(unsigned char *) ber->ber_ptr;
+
+	*lenp = bv.bv_len;
 	return tag;
 }
 
-static ber_len_t
-ber_getnint(
+ber_tag_t
+ber_get_int(
 	BerElement *ber,
-	ber_int_t *num,
-	ber_len_t len )
+	ber_int_t *num )
 {
-	unsigned char buf[sizeof(ber_int_t)];
+	ber_tag_t	tag;
+	ber_len_t	len;
+	struct berval bv;
 
-	assert( ber != NULL );
 	assert( num != NULL );
-	assert( LBER_VALID( ber ) );
 
-	/*
-	 * The tag and length have already been stripped off.  We should
-	 * be sitting right before len bytes of 2's complement integer,
-	 * ready to be read straight into an int.  We may have to sign
-	 * extend after we read it in.
-	 */
-
-	if ( len > sizeof(ber_int_t) ) {
-		return -1;
+	tag = ber_skip_element( ber, &bv );
+	len = bv.bv_len;
+	if ( tag == LBER_DEFAULT || len > sizeof(ber_int_t) ) {
+		return LBER_DEFAULT;
 	}
 
-	/* read into the low-order bytes of our buffer */
-	if ( (ber_len_t) ber_read( ber, (char *) buf, len ) != len ) {
-		return -1;
-	}
-
+	/* parse two's complement integer */
 	if( len ) {
-		/* sign extend if necessary */
+		unsigned char *buf = (unsigned char *) bv.bv_val;
 		ber_len_t i;
-		ber_int_t netnum = 0x80 & buf[0] ? -1 : 0;
+		ber_int_t netnum = buf[0] & 0xff;
 
+		/* sign extend */
+		netnum = (netnum ^ 0x80) - 0x80;
+
 		/* shift in the bytes */
-		for( i=0 ; i<len; i++ ) {
+		for( i = 1; i < len; i++ ) {
 			netnum = (netnum << 8 ) | buf[i];
 		}
 
@@ -275,30 +295,7 @@
 	} else {
 		*num = 0;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
-	return len;
-}
-
-ber_tag_t
-ber_get_int(
-	BerElement *ber,
-	ber_int_t *num )
-{
-	ber_tag_t	tag;
-	ber_len_t	len;
-
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
-		return LBER_DEFAULT;
-	}
-
-	if ( ber_getnint( ber, num, len ) != len ) {
-		return LBER_DEFAULT;
-	}
-	
 	return tag;
 }
 
@@ -316,29 +313,22 @@
 	char *buf,
 	ber_len_t *len )
 {
-	ber_len_t	datalen;
+	struct berval bv;
 	ber_tag_t	tag;
 
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
+	if ( (tag = ber_skip_element( ber, &bv )) == LBER_DEFAULT ) {
 		return LBER_DEFAULT;
 	}
 
 	/* must fit within allocated space with termination */
-	if ( datalen >= *len ) {
+	if ( bv.bv_len >= *len ) {
 		return LBER_DEFAULT;
 	}
 
-	if ( (ber_len_t) ber_read( ber, buf, datalen ) != datalen ) {
-		return LBER_DEFAULT;
-	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
+	memcpy( buf, bv.bv_val, bv.bv_len );
+	buf[bv.bv_len] = '\0';
 
-	buf[datalen] = '\0';
-
-	*len = datalen;
+	*len = bv.bv_len;
 	return tag;
 }
 
@@ -354,131 +344,132 @@
  * stack use to the absolute minimum.
  */
 typedef struct bgbvr {
-	enum bgbvc choice;
-	BerElement *ber;
-	int alloc;
-	ber_len_t siz;
-	ber_len_t off;
-	union {
-		char ***c;
-		BerVarray *ba;
-		struct berval ***bv;
-	} res;
+	const enum bgbvc choice;
+	const int alloc;	/* choice == BvOff ? 0 : LBER_ALLOC */
+	ber_len_t siz;		/* input array element size, output count */
+	ber_len_t off;		/* BvOff offset to the struct berval */
+	void *result;
 } bgbvr;
 
 static ber_tag_t
-ber_get_stringbvl( bgbvr *b, ber_len_t *rlen )
+ber_get_stringbvl( BerElement *ber, bgbvr *b )
 {
 	int i = 0, n;
 	ber_tag_t tag;
-	ber_len_t len;
+	ber_len_t tot_size = 0, siz = b->siz;
 	char *last, *orig;
 	struct berval bv, *bvp = NULL;
+	union stringbvl_u {
+		char **ca;				/* ChArray */
+		BerVarray ba;			/* BvArray */
+		struct berval **bv;		/* BvVec */
+		char *bo;				/* BvOff */
+	} res;
 
-	/* For rewinding, just like ber_peek_tag() */
-	orig = b->ber->ber_ptr;
-	tag = b->ber->ber_tag;
+	tag = ber_skip_tag( ber, &bv.bv_len );
 
-	if ( ber_first_element( b->ber, &len, &last ) != LBER_DEFAULT ) {
-		for ( ; b->ber->ber_ptr < last; i++ ) {
-			if (ber_skip_tag( b->ber, &len ) == LBER_DEFAULT) break;
-			b->ber->ber_ptr += len;
-			b->ber->ber_tag = *(unsigned char *)b->ber->ber_ptr;
+	if ( tag != LBER_DEFAULT ) {
+		tag = 0;
+		orig = ber->ber_ptr;
+		last = orig + bv.bv_len;
+
+		for ( ; ber->ber_ptr < last; i++, tot_size += siz ) {
+			if ( ber_skip_element( ber, &bv ) == LBER_DEFAULT )
+				break;
 		}
+		if ( ber->ber_ptr != last ) {
+			i = 0;
+			tag = LBER_DEFAULT;
+		}
+
+		ber->ber_ptr = orig;
+		ber->ber_tag = *(unsigned char *) orig;
 	}
 
-	if ( rlen ) *rlen = i;
-
+	b->siz = i;
 	if ( i == 0 ) {
-		*b->res.c = NULL;
-		return 0;
+		return tag;
 	}
 
-	n = i;
-
-	/* Allocate the result vector */
+	/* Allocate and NULL-terminate the result vector */
+	b->result = ber_memalloc_x( tot_size + siz, ber->ber_memctx );
+	if ( b->result == NULL ) {
+		return LBER_DEFAULT;
+	}
 	switch (b->choice) {
 	case ChArray:
-		*b->res.c = ber_memalloc_x( (n+1)*sizeof( char * ),
-			b->ber->ber_memctx);
-		if ( *b->res.c == NULL ) return LBER_DEFAULT;
-		(*b->res.c)[n] = NULL;
+		res.ca = b->result;
+		res.ca[i] = NULL;
 		break;
 	case BvArray:
-		*b->res.ba = ber_memalloc_x( (n+1)*sizeof( struct berval ),
-			b->ber->ber_memctx);
-		if ( *b->res.ba == NULL ) return LBER_DEFAULT;
-		(*b->res.ba)[n].bv_val = NULL;
+		res.ba = b->result;
+		res.ba[i].bv_val = NULL;
 		break;
 	case BvVec:
-		*b->res.bv = ber_memalloc_x( (n+1)*sizeof( struct berval *),
-			b->ber->ber_memctx);
-		if ( *b->res.bv == NULL ) return LBER_DEFAULT;
-		(*b->res.bv)[n] = NULL;
+		res.bv = b->result;
+		res.bv[i] = NULL;
 		break;
 	case BvOff:
-		*b->res.ba = ber_memalloc_x( (n+1) * b->siz, b->ber->ber_memctx );
-		if ( *b->res.ba == NULL ) return LBER_DEFAULT;
-		((struct berval *)((char *)(*b->res.ba) + n*b->siz +
-			b->off))->bv_val = NULL;
+		res.bo = (char *) b->result + b->off;
+		((struct berval *) (res.bo + tot_size))->bv_val = NULL;
+		tot_size = 0;
 		break;
 	}
-	b->ber->ber_ptr = orig;
-	b->ber->ber_tag = tag;
-	ber_skip_tag( b->ber, &len );
-	
-	for (n=0; n<i; n++)
-	{
-		tag = ber_next_element( b->ber, &len, last );
-		if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT ) {
+
+	n = 0;
+	do {
+		tag = ber_get_stringbv( ber, &bv, b->alloc );
+		if ( tag == LBER_DEFAULT ) {
 			goto nomem;
 		}
 
 		/* store my result */
 		switch (b->choice) {
 		case ChArray:
-			(*b->res.c)[n] = bv.bv_val;
+			res.ca[n] = bv.bv_val;
 			break;
 		case BvArray:
-			(*b->res.ba)[n] = bv;
+			res.ba[n] = bv;
 			break;
 		case BvVec:
-			bvp = ber_memalloc_x( sizeof( struct berval ), b->ber->ber_memctx);
+			bvp = ber_memalloc_x( sizeof( struct berval ),
+				ber->ber_memctx );
 			if ( !bvp ) {
-				LBER_FREE(bv.bv_val);
+				ber_memfree_x( bv.bv_val, ber->ber_memctx );
 				goto nomem;
 			}
-			(*b->res.bv)[n] = bvp;
+			res.bv[n] = bvp;
 			*bvp = bv;
 			break;
 		case BvOff:
-			*(BerVarray)((char *)(*b->res.ba)+n*b->siz+b->off) = bv;
+			*(struct berval *)(res.bo + tot_size) = bv;
+			tot_size += siz;
 			break;
 		}
-	}
+	} while (++n < i);
 	return tag;
 
 nomem:
-	if (b->alloc || b->choice == BvVec) {
-		for (--n; n>=0; n--) {
+	if (b->choice != BvOff) {	/* BvOff does not have b->alloc set */
+		while (--n >= 0) {
 			switch(b->choice) {
 			case ChArray:
-				LBER_FREE((*b->res.c)[n]);
+				ber_memfree_x(res.ca[n], ber->ber_memctx);
 				break;
 			case BvArray:
-				LBER_FREE((*b->res.ba)[n].bv_val);
+				ber_memfree_x(res.ba[n].bv_val, ber->ber_memctx);
 				break;
 			case BvVec:
-				LBER_FREE((*b->res.bv)[n]->bv_val);
-				LBER_FREE((*b->res.bv)[n]);
+				ber_memfree_x(res.bv[n]->bv_val, ber->ber_memctx);
+				ber_memfree_x(res.bv[n], ber->ber_memctx);
 				break;
 			default:
 				break;
 			}
 		}
 	}
-	LBER_FREE(*b->res.c);
-	*b->res.c = NULL;
+	ber_memfree_x(b->result, ber->ber_memctx);
+	b->result = NULL;
 	return LBER_DEFAULT;
 }
 
@@ -486,21 +477,15 @@
 ber_get_stringbv( BerElement *ber, struct berval *bv, int option )
 {
 	ber_tag_t	tag;
+	char		*data;
 
-	assert( ber != NULL );
-	assert( bv != NULL );
-
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) {
+	tag = ber_skip_element( ber, bv );
+	if ( tag == LBER_DEFAULT ) {
 		bv->bv_val = NULL;
-		return LBER_DEFAULT;
+		return tag;
 	}
 
-	if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) {
-		return LBER_DEFAULT;
-	}
-
+	data = bv->bv_val;
 	if ( option & LBER_BV_ALLOC ) {
 		bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
 			ber->ber_memctx );
@@ -508,20 +493,13 @@
 			return LBER_DEFAULT;
 		}
 
-		if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val,
-			bv->bv_len ) != bv->bv_len )
-		{
-			LBER_FREE( bv->bv_val );
-			bv->bv_val = NULL;
-			return LBER_DEFAULT;
+		if ( bv->bv_len != 0 ) {
+			memcpy( bv->bv_val, data, bv->bv_len );
 		}
-	} else {
-		bv->bv_val = ber->ber_ptr;
-		ber->ber_ptr += bv->bv_len;
+		data = bv->bv_val;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 	if ( !( option & LBER_BV_NOTERM ))
-		bv->bv_val[bv->bv_len] = '\0';
+		data[bv->bv_len] = '\0';
 
 	return tag;
 }
@@ -530,27 +508,15 @@
 ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option )
 {
 	ber_tag_t	tag;
+	char		*data;
 
-	assert( ber != NULL );
-	assert( bv != NULL );
-
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) {
+	tag = ber_skip_element( ber, bv );
+	if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) {
 		bv->bv_val = NULL;
-		return LBER_DEFAULT;
-	}
-
-	if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) {
-		return LBER_DEFAULT;
-	}
-
-	if ( bv->bv_len == 0 ) {
-		bv->bv_val = NULL;
-		ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 		return tag;
 	}
 
+	data = bv->bv_val;
 	if ( option & LBER_BV_ALLOC ) {
 		bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
 			ber->ber_memctx );
@@ -558,20 +524,11 @@
 			return LBER_DEFAULT;
 		}
 
-		if ( bv->bv_len > 0 && (ber_len_t) ber_read( ber, bv->bv_val,
-			bv->bv_len ) != bv->bv_len )
-		{
-			LBER_FREE( bv->bv_val );
-			bv->bv_val = NULL;
-			return LBER_DEFAULT;
-		}
-	} else {
-		bv->bv_val = ber->ber_ptr;
-		ber->ber_ptr += bv->bv_len;
+		memcpy( bv->bv_val, data, bv->bv_len );
+		data = bv->bv_val;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 	if ( !( option & LBER_BV_NOTERM ))
-		bv->bv_val[bv->bv_len] = '\0';
+		data[bv->bv_len] = '\0';
 
 	return tag;
 }
@@ -620,7 +577,7 @@
 
 	tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC );
 	if ( tag == LBER_DEFAULT ) {
-		LBER_FREE( *bv );
+		ber_memfree_x( *bv, ber->ber_memctx );
 		*bv = NULL;
 	}
 	return tag;
@@ -632,63 +589,46 @@
 	char **buf,
 	ber_len_t *blen )
 {
-	ber_len_t	datalen;
 	ber_tag_t	tag;
+	struct berval	data;
 	unsigned char	unusedbits;
 
-	assert( ber != NULL );
 	assert( buf != NULL );
 	assert( blen != NULL );
 
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
-		*buf = NULL;
-		return LBER_DEFAULT;
+	if ( (tag = ber_skip_element( ber, &data )) == LBER_DEFAULT ) {
+		goto fail;
 	}
-	--datalen;
 
-	*buf = (char *) ber_memalloc_x( datalen, ber->ber_memctx );
-	if ( *buf == NULL ) {
-		return LBER_DEFAULT;
+	if ( --data.bv_len > (ber_len_t)-1 / 8 ) {
+		goto fail;
 	}
-
-	if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) {
-		LBER_FREE( buf );
-		*buf = NULL;
-		return LBER_DEFAULT;
+	unusedbits = *(unsigned char *) data.bv_val++;
+	if ( unusedbits > 7 ) {
+		goto fail;
 	}
 
-	if ( (ber_len_t) ber_read( ber, *buf, datalen ) != datalen ) {
-		LBER_FREE( buf );
-		*buf = NULL;
+	*buf = (char *) ber_memalloc_x( data.bv_len, ber->ber_memctx );
+	if ( *buf == NULL ) {
 		return LBER_DEFAULT;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
+	memcpy( *buf, data.bv_val, data.bv_len );
 
-	*blen = datalen * 8 - unusedbits;
+	*blen = data.bv_len * 8 - unusedbits;
 	return tag;
+
+ fail:
+	*buf = NULL;
+	return LBER_DEFAULT;
 }
 
 ber_tag_t
 ber_get_null( BerElement *ber )
 {
 	ber_len_t	len;
-	ber_tag_t	tag;
+	ber_tag_t	tag = ber_skip_tag( ber, &len );
 
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
-		return LBER_DEFAULT;
-	}
-
-	if ( len != 0 ) {
-		return LBER_DEFAULT;
-	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
-
-	return( tag );
+	return( len == 0 ? tag : LBER_DEFAULT );
 }
 
 ber_tag_t
@@ -696,18 +636,7 @@
 	BerElement *ber,
 	ber_int_t *boolval )
 {
-	ber_int_t	longbool;
-	ber_tag_t	rc;
-
-	assert( ber != NULL );
-	assert( boolval != NULL );
-
-	assert( LBER_VALID( ber ) );
-
-	rc = ber_get_int( ber, &longbool );
-	*boolval = longbool;
-
-	return rc;
+	return ber_get_int( ber, boolval );
 }
 
 ber_tag_t
@@ -716,8 +645,6 @@
 	ber_len_t *len,
 	char **last )
 {
-	assert( ber != NULL );
-	assert( len != NULL );
 	assert( last != NULL );
 
 	/* skip the sequence header, use the len to mark where to stop */
@@ -725,11 +652,10 @@
 		*last = NULL;
 		return LBER_DEFAULT;
 	}
-	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
 	*last = ber->ber_ptr + *len;
 
-	if ( *last == ber->ber_ptr ) {
+	if ( *len == 0 ) {
 		return LBER_DEFAULT;
 	}
 
@@ -743,9 +669,7 @@
 	LDAP_CONST char *last )
 {
 	assert( ber != NULL );
-	assert( len != NULL );
 	assert( last != NULL );
-
 	assert( LBER_VALID( ber ) );
 
 	if ( ber->ber_ptr >= last ) {
@@ -763,8 +687,8 @@
 {
 	va_list		ap;
 	LDAP_CONST char		*fmt_reset;
-	char		*s, **ss;
-	struct berval	**bvp, *bval;
+	char		*s, **ss, ***sss;
+	struct berval	data, *bval, **bvp, ***bvpp;
 	ber_int_t	*i;
 	ber_len_t	*l;
 	ber_tag_t	*t;
@@ -775,7 +699,6 @@
 
 	assert( ber != NULL );
 	assert( fmt != NULL );
-
 	assert( LBER_VALID( ber ) );
 
 	fmt_reset = fmt;
@@ -823,7 +746,7 @@
 			break;
 
 		case 'e':	/* enumerated */
-		case 'i':	/* int */
+		case 'i':	/* integer */
 			i = va_arg( ap, ber_int_t * );
 			rc = ber_get_int( ber, i );
 			break;
@@ -844,14 +767,14 @@
 				 * len ptr on finish. parsed in-place.
 				 */
 		{
-			bgbvr cookie = { BvOff };
-			cookie.ber = ber;
-			cookie.res.ba = va_arg( ap, struct berval ** );
-			cookie.alloc = 0;
+			bgbvr cookie = { BvOff, 0 };
+			bvp = va_arg( ap, struct berval ** );
 			l = va_arg( ap, ber_len_t * );
 			cookie.siz = *l;
 			cookie.off = va_arg( ap, ber_len_t );
-			rc = ber_get_stringbvl( &cookie, l );
+			rc = ber_get_stringbvl( ber, &cookie );
+			*bvp = cookie.result;
+			*l = cookie.siz;
 			break;
 		}
 
@@ -887,46 +810,47 @@
 
 		case 'v':	/* sequence of strings */
 		{
-			bgbvr cookie = { ChArray };
-			cookie.ber = ber;
-			cookie.res.c = va_arg( ap, char *** );
-			cookie.alloc = LBER_BV_ALLOC;
-			rc = ber_get_stringbvl( &cookie, NULL );
+			bgbvr cookie = {
+				ChArray, LBER_BV_ALLOC, sizeof( char * )
+			};
+			rc = ber_get_stringbvl( ber, &cookie );
+			*(va_arg( ap, char *** )) = cookie.result;
 			break;
 		}
 
 		case 'V':	/* sequence of strings + lengths */
 		{
-			bgbvr cookie = { BvVec };
-			cookie.ber = ber;
-			cookie.res.bv = va_arg( ap, struct berval *** );
-			cookie.alloc = LBER_BV_ALLOC;
-			rc = ber_get_stringbvl( &cookie, NULL );
+			bgbvr cookie = {
+				BvVec, LBER_BV_ALLOC, sizeof( struct berval * )
+			};
+			rc = ber_get_stringbvl( ber, &cookie );
+			*(va_arg( ap, struct berval *** )) = cookie.result;
 			break;
 		}
 
 		case 'W':	/* bvarray */
 		{
-			bgbvr cookie = { BvArray };
-			cookie.ber = ber;
-			cookie.res.ba = va_arg( ap, struct berval ** );
-			cookie.alloc = LBER_BV_ALLOC;
-			rc = ber_get_stringbvl( &cookie, NULL );
+			bgbvr cookie = {
+				BvArray, LBER_BV_ALLOC, sizeof( struct berval )
+			};
+			rc = ber_get_stringbvl( ber, &cookie );
+			*(va_arg( ap, struct berval ** )) = cookie.result;
 			break;
 		}
 
 		case 'x':	/* skip the next element - whatever it is */
-			if ( (rc = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
-				break;
-			ber->ber_ptr += len;
-			ber->ber_tag = *(unsigned char *)ber->ber_ptr;
+			rc = ber_skip_element( ber, &data );
 			break;
 
 		case '{':	/* begin sequence */
 		case '[':	/* begin set */
-			if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V'
-				&& *(fmt + 1) != 'W' && *(fmt + 1) != 'M' )
+			switch ( fmt[1] ) {
+			case 'v': case 'V': case 'W': case 'M':
+				break;
+			default:
 				rc = ber_skip_tag( ber, &len );
+				break;
+			}
 			break;
 
 		case '}':	/* end sequence */
@@ -944,6 +868,7 @@
 	}
 
 	va_end( ap );
+
 	if ( rc == LBER_DEFAULT ) {
 		/*
 		 * Error.  Reclaim malloced memory that was given to the caller.
@@ -966,42 +891,48 @@
 		case 'a':	/* octet string - allocate storage as needed */
 		case 'A':
 			ss = va_arg( ap, char ** );
-			if ( *ss ) {
-				LBER_FREE( *ss );
-				*ss = NULL;
-			}
+			ber_memfree_x( *ss, ber->ber_memctx );
+			*ss = NULL;
 			break;
 
 		case 'b':	/* boolean */
 		case 'e':	/* enumerated */
-		case 'i':	/* int */
-			(void) va_arg( ap, int * );
+		case 'i':	/* integer */
+			(void) va_arg( ap, ber_int_t * );
 			break;
 
 		case 'l':	/* length of next item */
-			(void) va_arg( ap, ber_len_t * );
+			*(va_arg( ap, ber_len_t * )) = 0;
 			break;
 
+		case 'm':	/* berval in-place */
+			bval = va_arg( ap, struct berval * );
+			BER_BVZERO( bval );
+			break;
+
+		case 'M':	/* BVoff array in-place */
+			bvp = va_arg( ap, struct berval ** );
+			ber_memfree_x( *bvp, ber->ber_memctx );
+			*bvp = NULL;
+			*(va_arg( ap, ber_len_t * )) = 0;
+			(void) va_arg( ap, ber_len_t );
+			break;
+
 		case 'o':	/* octet string in a supplied berval */
 			bval = va_arg( ap, struct berval * );
-			if ( bval->bv_val != NULL ) {
-				LBER_FREE( bval->bv_val );
-				bval->bv_val = NULL;
-			}
-			bval->bv_len = 0;
+			ber_memfree_x( bval->bv_val, ber->ber_memctx );
+			BER_BVZERO( bval );
 			break;
 
 		case 'O':	/* octet string - allocate & include length */
 			bvp = va_arg( ap, struct berval ** );
-			if ( *bvp ) {
-				ber_bvfree( *bvp );
-				*bvp = NULL;
-			}
+			ber_bvfree_x( *bvp, ber->ber_memctx );
+			*bvp = NULL;
 			break;
 
 		case 's':	/* octet string - in a buffer */
 			(void) va_arg( ap, char * );
-			(void) va_arg( ap, ber_len_t * );
+			*(va_arg( ap, ber_len_t * )) = 0;
 			break;
 
 		case 't':	/* tag of next item */
@@ -1011,19 +942,30 @@
 
 		case 'B':	/* bit string - allocate storage as needed */
 			ss = va_arg( ap, char ** );
-			if ( *ss ) {
-				LBER_FREE( *ss );
-				*ss = NULL;
-			}
+			ber_memfree_x( *ss, ber->ber_memctx );
+			*ss = NULL;
 			*(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */
 			break;
 
-		case 'm':	/* berval in-place */
-		case 'M':	/* BVoff array in-place */
-		case 'n':	/* null */
 		case 'v':	/* sequence of strings */
+			sss = va_arg( ap, char *** );
+			ber_memvfree_x( (void **) *sss, ber->ber_memctx );
+			*sss = NULL;
+			break;
+
 		case 'V':	/* sequence of strings + lengths */
+			bvpp = va_arg( ap, struct berval *** );
+			ber_bvecfree_x( *bvpp, ber->ber_memctx );
+			*bvpp = NULL;
+			break;
+
 		case 'W':	/* BerVarray */
+			bvp = va_arg( ap, struct berval ** );
+			ber_bvarray_free_x( *bvp, ber->ber_memctx );
+			*bvp = NULL;
+			break;
+
+		case 'n':	/* null */
 		case 'x':	/* skip the next element - whatever it is */
 		case '{':	/* begin sequence */
 		case '[':	/* begin set */

Modified: openldap/trunk/libraries/liblber/encode.c
===================================================================
--- openldap/trunk/libraries/liblber/encode.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblber/encode.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* encode.c - ber output encoding routines */
-/* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.64.2.4 2009/01/22 00:00:53 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.64.2.6 2009/08/13 00:56:58 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -31,6 +31,7 @@
 #include "portable.h"
 
 #include <ctype.h>
+#include <limits.h>
 #include <stdio.h>
 
 #include <ac/stdlib.h>
@@ -41,141 +42,69 @@
 
 #include "lber-int.h"
 
-static int ber_put_len LDAP_P((
-	BerElement *ber,
-	ber_len_t len,
-	int nosos ));
 
-static int ber_start_seqorset LDAP_P((
-	BerElement *ber,
-	ber_tag_t tag ));
+#define OCTET_SIZE(type) ((ber_len_t) (sizeof(type)*CHAR_BIT + 7) / 8)
+#define TAGBUF_SIZE OCTET_SIZE(ber_tag_t)
+#define LENBUF_SIZE (1 + OCTET_SIZE(ber_len_t))
+#define HEADER_SIZE (TAGBUF_SIZE + LENBUF_SIZE)
 
-static int ber_put_seqorset LDAP_P(( BerElement *ber ));
+/*
+ * BER element size constrains:
+ *
+ * - We traditionally support a length of max 0xffffffff.  However
+ *   some functions return an int length so that is their max.
+ *   MAXINT_BERSIZE is the max for those functions.
+ *
+ * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets.
+ *
+ * - sizeof(ber_elem_size_t) is normally MAXINT_BERSIZE_OCTETS:
+ *   Big enough for MAXINT_BERSIZE, but not more.  (Larger wastes
+ *   space in the working encoding and DER encoding of a sequence
+ *   or set.  Smaller further limits sizes near a sequence/set.)
+ *
+ * ber_len_t is mostly unrelated to this.  Which may be for the best,
+ * since it is also used for lengths of data that are never encoded.
+ */
+#define MAXINT_BERSIZE \
+	(INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE)
+#define MAXINT_BERSIZE_OCTETS 4
+typedef ber_uint_t ber_elem_size_t; /* normally 32 bits */
 
-static int ber_put_int_or_enum LDAP_P((
-	BerElement *ber,
-	ber_int_t num,
-	ber_tag_t tag ));
 
-#define	BER_TOP_BYTE(type)	(sizeof(type)-1)
-#define	BER_TOP_MASK(type)	((type)0xffU << (BER_TOP_BYTE(type)*8))
-
-static int
-ber_calc_taglen( ber_tag_t tag )
+/* Prepend tag to ptr, which points to the end of a tag buffer */
+static unsigned char *
+ber_prepend_tag( unsigned char *ptr, ber_tag_t tag )
 {
-	int	i = BER_TOP_BYTE(ber_tag_t);
-	ber_tag_t	mask = BER_TOP_MASK(ber_tag_t);
+	do {
+		*--ptr = (unsigned char) tag & 0xffU;
+	} while ( (tag >>= 8) != 0 );
 
-	/* find the first non-all-zero byte in the tag */
-	for ( ; i > 0; i-- ) {
-		/* not all zero */
-		if ( tag & mask ) break;
-		mask >>= 8;
-	}
-
-	return i + 1;
+	return ptr;
 }
 
-static int
-ber_put_tag(
-	BerElement	*ber,
-	ber_tag_t tag,
-	int nosos )
+/* Prepend ber length to ptr, which points to the end of a length buffer */
+static unsigned char *
+ber_prepend_len( unsigned char *ptr, ber_len_t len )
 {
-	int rc;
-	int taglen;
-	int	i;
-	unsigned char nettag[sizeof(ber_tag_t)];
-
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	taglen = ber_calc_taglen( tag );
-
-	for( i=taglen-1; i>=0; i-- ) {
-		nettag[i] = (unsigned char)(tag & 0xffU);
-		tag >>= 8;
-	}
-
-	rc = ber_write( ber, (char *) nettag, taglen, nosos );
-
-	return rc;
-}
-
-static ber_len_t
-ber_calc_lenlen( ber_len_t len )
-{
 	/*
 	 * short len if it's less than 128 - one byte giving the len,
 	 * with bit 8 0.
-	 */
-
-	if ( len <= (ber_len_t) 0x7FU ) return 1;
-
-	/*
 	 * long len otherwise - one byte with bit 8 set, giving the
 	 * length of the length, followed by the length itself.
 	 */
 
-	if ( len <= (ber_len_t) 0xffU ) return 2;
-	if ( len <= (ber_len_t) 0xffffU ) return 3;
-	if ( len <= (ber_len_t) 0xffffffU ) return 4;
+	*--ptr = (unsigned char) len & 0xffU;
 
-	return 5;
-}
+	if ( len >= 0x80 ) {
+		unsigned char *endptr = ptr--;
 
-static int
-ber_put_len( BerElement *ber, ber_len_t len, int nosos )
-{
-	int rc;
-	int		i,j;
-	char		lenlen;
-	ber_len_t	mask;
-	unsigned char netlen[sizeof(ber_len_t)];
-
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	/*
-	 * short len if it's less than 128 - one byte giving the len,
-	 * with bit 8 0.
-	 */
-
-	if ( len <= 127 ) {
-		char length_byte = (char) len;
-		return ber_write( ber, &length_byte, 1, nosos );
+		while ( (len >>= 8) != 0 ) {
+			*ptr-- = (unsigned char) len & 0xffU;
+		}
+		*ptr = (unsigned char) (endptr - ptr) + 0x80U;
 	}
 
-	/*
-	 * long len otherwise - one byte with bit 8 set, giving the
-	 * length of the length, followed by the length itself.
-	 */
-
-	/* find the first non-all-zero byte */
-	i = BER_TOP_BYTE(ber_len_t);
-	mask = BER_TOP_MASK(ber_len_t);
-	for ( ; i > 0; i-- ) {
-		/* not all zero */
-		if ( len & mask ) break;
-		mask >>= 8;
-	}
-	lenlen = (unsigned char) ++i;
-	if ( lenlen > 4 ) return -1;
-
-	lenlen |= 0x80UL;
-
-	/* write the length of the length */
-	if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) return -1;
-
-	for( j=i-1; j>=0; j-- ) {
-		netlen[j] = (unsigned char)(len & 0xffU);
-		len >>= 8;
-	}
-
-	/* write the length itself */
-	rc = ber_write( ber, (char *) netlen, i, nosos );
-
-	return rc == i ?  i+1 : -1;
+	return ptr;
 }
 
 /* out->bv_len should be the buffer size on input */
@@ -210,6 +139,7 @@
 	for (;;) {
 		if ( ptr > inend ) return -1;
 
+		/* Write the OID component little-endian, then reverse it */
 		len = 0;
 		do {
 			der[len++] = (val & 0xff) | 0x80;
@@ -241,64 +171,25 @@
 	ber_int_t num,
 	ber_tag_t tag )
 {
-	int rc;
-	int	i, j, sign, taglen, lenlen;
-	ber_len_t	len;
-	ber_uint_t	unum, mask;
-	unsigned char netnum[sizeof(ber_uint_t)];
+	ber_uint_t unum;
+	unsigned char sign, data[TAGBUF_SIZE+1 + OCTET_SIZE(ber_int_t)], *ptr;
 
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
-	sign = (num < 0);
+	sign = 0;
 	unum = num;	/* Bit fiddling should be done with unsigned values */
-
-	/*
-	 * high bit is set - look for first non-all-one byte
-	 * high bit is clear - look for first non-all-zero byte
-	 */
-	i = BER_TOP_BYTE(ber_int_t);
-	mask = BER_TOP_MASK(ber_uint_t);
-	for ( ; i > 0; i-- ) {
-		if ( sign ) {
-			/* not all ones */
-			if ( (unum & mask) != mask ) break;
-		} else {
-			/* not all zero */
-			if ( unum & mask ) break;
-		}
-		mask >>= 8;
+	if ( num < 0 ) {
+		sign = 0xffU;
+		unum = ~unum;
 	}
-
-	/*
-	 * we now have the "leading byte".  if the high bit on this
-	 * byte matches the sign bit, we need to "back up" a byte.
-	 */
-	mask = (unum & ((ber_uint_t)0x80U << (i * 8)));
-	if ( (mask && !sign) || (sign && !mask) ) {
-		i++;
+	for ( ptr = &data[sizeof(data) - 1] ;; unum >>= 8 ) {
+		*ptr-- = (sign ^ (unsigned char) unum) & 0xffU;
+		if ( unum < 0x80 )	/* top bit at *ptr is sign bit */
+			break;
 	}
 
-	len = i + 1;
+	*ptr = (unsigned char) (&data[sizeof(data) - 1] - ptr); /* length */
+	ptr = ber_prepend_tag( ptr, tag );
 
-	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
-		return -1;
-	}
-
-	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) {
-		return -1;
-	}
-	i++;
-
-	for( j=i-1; j>=0; j-- ) {
-		netnum[j] = (unsigned char)(unum & 0xffU);
-		unum >>= 8;
-	}
-
-	rc = ber_write( ber, (char *) netnum, i, 0 );
-
-	/* length of tag + length + contents */
-	return rc == i ? taglen + lenlen + i : -1;
+	return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
 }
 
 int
@@ -307,9 +198,6 @@
 	ber_int_t num,
 	ber_tag_t tag )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_ENUMERATED;
 	}
@@ -323,9 +211,6 @@
 	ber_int_t num,
 	ber_tag_t tag )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_INTEGER;
 	}
@@ -340,27 +225,24 @@
 	ber_len_t len,
 	ber_tag_t tag )
 {
-	int taglen, lenlen, rc;
+	int rc;
+	unsigned char header[HEADER_SIZE], *ptr;
 
-	assert( ber != NULL );
-	assert( str != NULL );
-
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_OCTETSTRING;
 	}
 
-	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
+	if ( len > MAXINT_BERSIZE ) {
 		return -1;
+	}
 
-	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
-		(ber_len_t) ber_write( ber, str, len, 0 ) != len )
-	{
-		rc = -1;
-	} else {
-		/* return length of tag + length + contents */
-		rc = taglen + lenlen + len;
+	ptr = ber_prepend_len( &header[sizeof(header)], len );
+	ptr = ber_prepend_tag( ptr, tag );
+
+	rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
+	if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
+		/* length(tag + length + contents) */
+		rc += (int) len;
 	}
 
 	return rc;
@@ -372,9 +254,6 @@
 	struct berval *bv,
 	ber_tag_t tag )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if( bv == NULL || bv->bv_len == 0 ) {
 		return ber_put_ostring( ber, "", (ber_len_t) 0, tag );
 	}
@@ -388,11 +267,8 @@
 	LDAP_CONST char *str,
 	ber_tag_t tag )
 {
-	assert( ber != NULL );
 	assert( str != NULL );
 
-	assert( LBER_VALID( ber ) );
-
 	return ber_put_ostring( ber, str, strlen( str ), tag );
 }
 
@@ -403,62 +279,46 @@
 	ber_len_t blen /* in bits */,
 	ber_tag_t tag )
 {
-	int				taglen, lenlen;
+	int rc;
 	ber_len_t		len;
-	unsigned char	unusedbits;
+	unsigned char	unusedbits, header[HEADER_SIZE + 1], *ptr;
 
-	assert( ber != NULL );
-	assert( str != NULL );
-
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_BITSTRING;
 	}
 
-	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
+	unusedbits = (unsigned char) -blen & 7;
+	len = blen / 8 + (unusedbits != 0); /* (blen+7)/8 without overflow */
+	if ( len >= MAXINT_BERSIZE ) {
 		return -1;
 	}
 
-	len = ( blen + 7 ) / 8;
-	unusedbits = (unsigned char) ((len * 8) - blen);
-	if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) {
-		return -1;
-	}
+	header[sizeof(header) - 1] = unusedbits;
+	ptr = ber_prepend_len( &header[sizeof(header) - 1], len + 1 );
+	ptr = ber_prepend_tag( ptr, tag );
 
-	if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) {
-		return -1;
+	rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
+	if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
+		/* length(tag + length + unused bit count + bitstring) */
+		rc += (int) len;
 	}
 
-	if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len ) {
-		return -1;
-	}
-
-	/* return length of tag + length + unused bit count + contents */
-	return taglen + 1 + lenlen + len;
+	return rc;
 }
 
 int
 ber_put_null( BerElement *ber, ber_tag_t tag )
 {
-	int	taglen;
+	unsigned char data[TAGBUF_SIZE + 1], *ptr;
 
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_NULL;
 	}
 
-	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
-		return -1;
-	}
+	data[sizeof(data) - 1] = 0;			/* length */
+	ptr = ber_prepend_tag( &data[sizeof(data) - 1], tag );
 
-	if ( ber_put_len( ber, 0, 0 ) != 1 ) {
-		return -1;
-	}
-
-	return taglen + 1;
+	return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
 }
 
 int
@@ -467,73 +327,91 @@
 	ber_int_t boolval,
 	ber_tag_t tag )
 {
-	int				taglen;
-	unsigned char	c;
+	unsigned char data[TAGBUF_SIZE + 2], *ptr;
 
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT )
 		tag = LBER_BOOLEAN;
 
-	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
-		return -1;
-	}
+	data[sizeof(data) - 1] = boolval ? 0xff : 0;
+	data[sizeof(data) - 2] = 1;			/* length */
+	ptr = ber_prepend_tag( &data[sizeof(data) - 2], tag );
 
-	if ( ber_put_len( ber, 1, 0 ) != 1 ) {
-		return -1;
-	}
+	return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
+}
 
-	c = boolval ? (unsigned char) ~0U : (unsigned char) 0U;
 
-	if ( ber_write( ber, (char *) &c, 1, 0 ) != 1 ) {
-		return -1;
-	}
+/* Max number of length octets in a sequence or set, normally 5 */
+#define SOS_LENLEN (1 + (sizeof(ber_elem_size_t) > MAXINT_BERSIZE_OCTETS ? \
+		(ber_len_t) sizeof(ber_elem_size_t) : MAXINT_BERSIZE_OCTETS))
 
-	return taglen + 2;
-}
+/* Header of incomplete sequence or set */
+typedef struct seqorset_header {
+	char xtagbuf[TAGBUF_SIZE + 1];	/* room for tag + len(tag or len) */
+	union {
+		ber_elem_size_t offset;		/* enclosing seqence/set */
+		char padding[SOS_LENLEN-1];	/* for final length encoding */
+	} next_sos;
+#	define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1)
+} Seqorset_header;
 
-#define FOUR_BYTE_LEN	5
-
+/* Start a sequence or set */
 static int
 ber_start_seqorset(
 	BerElement *ber,
 	ber_tag_t tag )
 {
-	Seqorset	*new;
+	/*
+	 * Write the tag and SOS_LENLEN octets reserved for length, to ber.
+	 * For now, length octets = (tag length, previous ber_sos_inner).
+	 *
+	 * Update ber_sos_inner and the write-cursor ber_sos_ptr.  ber_ptr
+	 * will not move until the outermost sequence or set is complete.
+	 */
 
+	Seqorset_header	header;
+	unsigned char	*headptr;
+	ber_len_t		taglen, headlen;
+	char			*dest, **p;
+
 	assert( ber != NULL );
 	assert( LBER_VALID( ber ) );
 
-	new = (Seqorset *) ber_memcalloc_x( 1, sizeof(Seqorset), ber->ber_memctx );
-
-	if ( new == NULL ) {
-		return -1;
+	if ( ber->ber_sos_ptr == NULL ) {	/* outermost sequence/set? */
+		header.next_sos.offset = 0;
+		p = &ber->ber_ptr;
+	} else {
+		if ( (ber_len_t) -1 > (ber_elem_size_t) -1 ) {
+			if ( ber->ber_sos_inner > (ber_elem_size_t) -1 )
+				return -1;
+		}
+		header.next_sos.offset = ber->ber_sos_inner;
+		p = &ber->ber_sos_ptr;
 	}
+	headptr = ber_prepend_tag( SOS_TAG_END(header), tag );
+	*SOS_TAG_END(header) = taglen = SOS_TAG_END(header) - headptr;
+	headlen = taglen + SOS_LENLEN;
 
-	new->sos_ber = ber;
-	if ( ber->ber_sos == NULL ) {
-		new->sos_first = ber->ber_ptr;
-	} else {
-		new->sos_first = ber->ber_sos->sos_ptr;
+	/* As ber_write(,headptr,headlen,) except update ber_sos_ptr, not *p */
+	if ( headlen > (ber_len_t) (ber->ber_end - *p) ) {
+		if ( ber_realloc( ber, headlen ) != 0 )
+			return -1;
 	}
+	dest = *p;
+	AC_MEMCPY( dest, headptr, headlen );
+	ber->ber_sos_ptr = dest + headlen;
 
-	/* Set aside room for a 4 byte length field */
-	new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
-	new->sos_tag = tag;
+	ber->ber_sos_inner = dest + taglen - ber->ber_buf;
 
-	new->sos_next = ber->ber_sos;
-	ber->ber_sos = new;
-
+	/*
+	 * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset()
+	 * should return lenlen - SOS_LENLEN + len, which can be < 0.
+	 */
 	return 0;
 }
 
 int
 ber_start_seq( BerElement *ber, ber_tag_t tag )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_SEQUENCE;
 	}
@@ -544,9 +422,6 @@
 int
 ber_start_set( BerElement *ber, ber_tag_t tag )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	if ( tag == LBER_DEFAULT ) {
 		tag = LBER_SET;
 	}
@@ -554,180 +429,67 @@
 	return ber_start_seqorset( ber, tag );
 }
 
+/* End a sequence or set */
 static int
 ber_put_seqorset( BerElement *ber )
 {
-	int rc;
-	ber_len_t	len;
-	unsigned char netlen[sizeof(ber_len_t)];
-	int			taglen;
-	ber_len_t	lenlen;
-	unsigned char	ltag = 0x80U + FOUR_BYTE_LEN - 1;
-	Seqorset	*next;
-	Seqorset	**sos = &ber->ber_sos;
+	Seqorset_header	header;
+	unsigned char	*lenptr;	/* length octets in the sequence/set */
+	ber_len_t		len;		/* length(contents) */
+	ber_len_t		xlen;		/* len + length(length) */
 
 	assert( ber != NULL );
 	assert( LBER_VALID( ber ) );
 
-	if( *sos == NULL ) return -1;
+	if ( ber->ber_sos_ptr == NULL ) return -1;
 
-	/*
-	 * If this is the toplevel sequence or set, we need to actually
-	 * write the stuff out.	 Otherwise, it's already been put in
-	 * the appropriate buffer and will be written when the toplevel
-	 * one is written.  In this case all we need to do is update the
-	 * length and tag.
-	 */
-
-	len = (*sos)->sos_clen;
-
-	if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL ) {
+	lenptr = (unsigned char *) ber->ber_buf + ber->ber_sos_inner;
+	xlen = ber->ber_sos_ptr - (char *) lenptr;
+	if ( xlen > MAXINT_BERSIZE + SOS_LENLEN ) {
 		return -1;
 	}
 
-	if ( ber->ber_options & LBER_USE_DER ) {
-		lenlen = ber_calc_lenlen( len );
+	/* Extract sequence/set information from length octets */
+	memcpy( SOS_TAG_END(header), lenptr, SOS_LENLEN );
 
-	} else {
-		lenlen = FOUR_BYTE_LEN;
-	}
-
-	if( lenlen > 1 ) {
+	/* Store length, and close gap of leftover reserved length octets */
+	len = xlen - SOS_LENLEN;
+	if ( ber->ber_options & LBER_USE_DER ) {
 		int i;
-		ber_len_t j = len;
-		for( i=lenlen-2; i >= 0; i-- ) {
-			netlen[i] = j & 0xffU;
-			j >>= 8;
+		lenptr[0] = SOS_LENLEN - 1 + 0x80; /* length(length)-1 */
+		for( i = SOS_LENLEN; --i > 0; len >>= 8 ) {
+			lenptr[i] = len & 0xffU;
 		}
 	} else {
-		netlen[0] = (unsigned char)(len & 0x7fU);
+		unsigned char *p = ber_prepend_len( lenptr + SOS_LENLEN, len );
+		ber_len_t unused = p - lenptr;
+		if ( unused != 0 ) {
+			/* length(length) < the reserved SOS_LENLEN bytes */
+			xlen -= unused;
+			AC_MEMCPY( lenptr, p, xlen );
+			ber->ber_sos_ptr = (char *) lenptr + xlen;
+		}
 	}
 
-	if ( (next = (*sos)->sos_next) == NULL ) {
-		/* write the tag */
-		if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) {
-			return( -1 );
-		}
-
-		if ( ber->ber_options & LBER_USE_DER ) {
-			/* Write the length in the minimum # of octets */
-			if ( ber_put_len( ber, len, 1 ) == -1 ) {
-				return -1;
-			}
-
-			if (lenlen != FOUR_BYTE_LEN) {
-				/*
-				 * We set aside FOUR_BYTE_LEN bytes for
-				 * the length field.  Move the data if
-				 * we don't actually need that much
-				 */
-				AC_MEMCPY( (*sos)->sos_first + taglen +
-				    lenlen, (*sos)->sos_first + taglen +
-				    FOUR_BYTE_LEN, len );
-			}
-		} else {
-			/* Fill FOUR_BYTE_LEN bytes for length field */
-			/* one byte of length length */
-			if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 ) {
-				return -1;
-			}
-
-			/* the length itself */
-			rc  = ber_write( ber, (char *) netlen, FOUR_BYTE_LEN-1, 1 );
-
-			if( rc != FOUR_BYTE_LEN - 1 ) {
-				return -1;
-			}
-		}
+	ber->ber_sos_inner = header.next_sos.offset;
+	if ( header.next_sos.offset == 0 ) { /* outermost sequence/set? */
 		/* The ber_ptr is at the set/seq start - move it to the end */
-		(*sos)->sos_ber->ber_ptr += len;
-
-	} else {
-		int i;
-		unsigned char nettag[sizeof(ber_tag_t)];
-		ber_tag_t tmptag = (*sos)->sos_tag;
-
-		if( ber->ber_sos->sos_ptr > ber->ber_end ) {
-			/* The sos_ptr exceeds the end of the BerElement
-			 * this can happen, for example, when the sos_ptr
-			 * is near the end and no data was written for the
-			 * 'V'.	 We must realloc the BerElement to ensure
-			 * we don't overwrite the buffer when writing
-			 * the tag and length fields.
-			 */
-			ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end;
-
-			if( ber_realloc( ber,  ext ) != 0 ) {
-				return -1;
-			}
-		}
-
-		/* the tag */
-		taglen = ber_calc_taglen( tmptag );
-
-		for( i = taglen-1; i >= 0; i-- ) {
-			nettag[i] = (unsigned char)(tmptag & 0xffU);
-			tmptag >>= 8;
-		}
-
-		AC_FMEMCPY( (*sos)->sos_first, nettag, taglen );
-
-		if ( ber->ber_options & LBER_USE_DER ) {
-			ltag = (lenlen == 1)
-				? (unsigned char) len
-				: (unsigned char) (0x80U + (lenlen - 1));
-		}
-
-		/* one byte of length length */
-		(*sos)->sos_first[1] = ltag;
-
-		if ( ber->ber_options & LBER_USE_DER ) {
-			if (lenlen > 1) {
-				/* Write the length itself */
-				AC_FMEMCPY( (*sos)->sos_first + 2, netlen, lenlen - 1 );
-			}
-			if (lenlen != FOUR_BYTE_LEN) {
-				/*
-				 * We set aside FOUR_BYTE_LEN bytes for
-				 * the length field.  Move the data if
-				 * we don't actually need that much
-				 */
-				AC_FMEMCPY( (*sos)->sos_first + taglen +
-				    lenlen, (*sos)->sos_first + taglen +
-				    FOUR_BYTE_LEN, len );
-			}
-		} else {
-			/* the length itself */
-			AC_FMEMCPY( (*sos)->sos_first + taglen + 1,
-			    netlen, FOUR_BYTE_LEN - 1 );
-		}
-
-		next->sos_clen += (taglen + lenlen + len);
-		next->sos_ptr += (taglen + lenlen + len);
+		ber->ber_ptr = ber->ber_sos_ptr;
+		ber->ber_sos_ptr = NULL;
 	}
 
-	/* we're done with this seqorset, so free it up */
-	ber_memfree_x( (char *) (*sos), ber->ber_memctx );
-	*sos = next;
-
-	return taglen + lenlen + len;
+	return xlen + *SOS_TAG_END(header); /* lenlen + len + taglen */
 }
 
 int
 ber_put_seq( BerElement *ber )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	return ber_put_seqorset( ber );
 }
 
 int
 ber_put_set( BerElement *ber )
 {
-	assert( ber != NULL );
-	assert( LBER_VALID( ber ) );
-
 	return ber_put_seqorset( ber );
 }
 
@@ -747,7 +509,6 @@
 
 	assert( ber != NULL );
 	assert( fmt != NULL );
-
 	assert( LBER_VALID( ber ) );
 
 	va_start( ap, fmt );
@@ -758,10 +519,15 @@
 				BEREncodeCallback *f;
 				void *p;
 
+				ber->ber_usertag = 0;
+
 				f = va_arg( ap, BEREncodeCallback * );
 				p = va_arg( ap, void * );
-
 				rc = (*f)( ber, p );
+
+				if ( ber->ber_usertag ) {
+					goto next;
+				}
 			} break;
 
 		case 'b':	/* boolean */
@@ -784,11 +550,10 @@
 			break;
 
 		case 'N':	/* Debug NULL */
+			rc = 0;
 			if( lber_int_null != 0 ) {
 				/* Insert NULL to ensure peer ignores unknown tags */
 				rc = ber_put_null( ber, lber_int_null );
-			} else {
-				rc = 0;
 			}
 			break;
 
@@ -812,14 +577,13 @@
 		case 'B':	/* bit string */
 		case 'X':	/* bit string (deprecated) */
 			s = va_arg( ap, char * );
-			len = va_arg( ap, int );	/* in bits */
+			len = va_arg( ap, ber_len_t );	/* in bits */
 			rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
 			break;
 
 		case 't':	/* tag for the next element */
 			ber->ber_tag = va_arg( ap, ber_tag_t );
-			ber->ber_usertag = 1;
-			break;
+			goto next;
 
 		case 'v':	/* vector of strings */
 			if ( (ss = va_arg( ap, char ** )) == NULL )
@@ -876,11 +640,8 @@
 			break;
 		}
 
-		if ( ber->ber_usertag == 0 ) {
-			ber->ber_tag = LBER_DEFAULT;
-		} else {
-			ber->ber_usertag = 0;
-		}
+		ber->ber_tag = LBER_DEFAULT;
+	next:;
 	}
 
 	va_end( ap );

Modified: openldap/trunk/libraries/liblber/io.c
===================================================================
--- openldap/trunk/libraries/liblber/io.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblber/io.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* io.c - ber general i/o routines */
-/* $OpenLDAP: pkg/ldap/libraries/liblber/io.c,v 1.111.2.10 2009/03/17 16:21:28 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblber/io.c,v 1.111.2.11 2009/08/02 21:06:34 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -55,7 +55,6 @@
 	ber_len_t	actuallen, nleft;
 
 	assert( ber != NULL );
-
 	assert( LBER_VALID( ber ) );
 
 	nleft = ber_pvt_ber_remaining( ber );
@@ -66,6 +65,10 @@
 	return( (ber_slen_t) actuallen );
 }
 
+/*
+ * Read from the ber buffer.  The caller must maintain ber->ber_tag.
+ * Do not use to read whole tags.  See ber_get_tag() and ber_skip_data().
+ */
 ber_slen_t
 ber_read(
 	BerElement *ber,
@@ -76,7 +79,6 @@
 
 	assert( ber != NULL );
 	assert( buf != NULL );
-
 	assert( LBER_VALID( ber ) );
 
 	nleft = ber_pvt_ber_remaining( ber );
@@ -89,49 +91,54 @@
 	return( (ber_slen_t) actuallen );
 }
 
+/*
+ * Write to the ber buffer.
+ * Note that ber_start_seqorset/ber_put_seqorset() bypass ber_write().
+ */
 ber_slen_t
 ber_write(
 	BerElement *ber,
 	LDAP_CONST char *buf,
 	ber_len_t len,
-	int nosos )
+	int zero )	/* nonzero is unsupported from OpenLDAP 2.4.18 */
 {
+	char **p;
+
 	assert( ber != NULL );
 	assert( buf != NULL );
-
 	assert( LBER_VALID( ber ) );
 
-	if ( nosos || ber->ber_sos == NULL ) {
-		if ( ber->ber_ptr + len > ber->ber_end ) {
-			if ( ber_realloc( ber, len ) != 0 ) return( -1 );
-		}
-		AC_MEMCPY( ber->ber_ptr, buf, (size_t)len );
-		ber->ber_ptr += len;
-		return( (ber_slen_t) len );
+	if ( zero != 0 ) {
+		ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "%s",
+			"ber_write: nonzero 4th argument not supported\n" );
+		return( -1 );
+	}
 
-	} else {
-		if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
-			if ( ber_realloc( ber, len ) != 0 ) return( -1 );
-		}
-		AC_MEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
-		ber->ber_sos->sos_ptr += len;
-		ber->ber_sos->sos_clen += len;
-		return( (ber_slen_t) len );
+	p = ber->ber_sos_ptr == NULL ? &ber->ber_ptr : &ber->ber_sos_ptr;
+	if ( len > (ber_len_t) (ber->ber_end - *p) ) {
+		if ( ber_realloc( ber, len ) != 0 ) return( -1 );
 	}
+	AC_MEMCPY( *p, buf, len );
+	*p += len;
+
+	return( (ber_slen_t) len );
 }
 
+/* Resize the ber buffer */
 int
 ber_realloc( BerElement *ber, ber_len_t len )
 {
-	ber_len_t	total;
-	Seqorset	*s;
-	long		off;
-	char		*oldbuf;
+	ber_len_t	total, offset, sos_offset;
+	char		*buf;
 
 	assert( ber != NULL );
-	assert( len > 0 );
 	assert( LBER_VALID( ber ) );
 
+	/* leave room for ber_flatten() to \0-terminate ber_buf */
+	if ( ++len == 0 ) {
+		return( -1 );
+	}
+
 	total = ber_pvt_ber_total( ber );
 
 #define LBER_EXBUFSIZ	4060 /* a few words less than 2^N for binary buddy */
@@ -140,7 +147,7 @@
 	/* don't realloc by small amounts */
 	total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len;
 # else
-	{	/* not sure what value this adds */
+	{	/* not sure what value this adds.  reduce fragmentation? */
 		ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ;
 		ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ;
 		total = ( have + need ) * LBER_EXBUFSIZ;
@@ -150,54 +157,38 @@
 	total += len;	/* realloc just what's needed */
 #endif
 
-	oldbuf = ber->ber_buf;
-
-	ber->ber_buf = (char *) ber_memrealloc_x( oldbuf, total, ber->ber_memctx );
-	
-	if ( ber->ber_buf == NULL ) {
-		ber->ber_buf = oldbuf;
+	if ( total < len || total > (ber_len_t)-1 / 2 /* max ber_slen_t */ ) {
 		return( -1 );
 	}
 
-	ber->ber_end = ber->ber_buf + total;
+	buf = ber->ber_buf;
+	offset = ber->ber_ptr - buf;
+	sos_offset = ber->ber_sos_ptr ? ber->ber_sos_ptr - buf : 0;
+	/* if ber_sos_ptr != NULL, it is > ber_buf so that sos_offset > 0 */
 
-	/*
-	 * If the stinking thing was moved, we need to go through and
-	 * reset all the sos and ber pointers.	Offsets would've been
-	 * a better idea... oh well.
-	 */
-
-	if ( ber->ber_buf != oldbuf ) {
-		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
-
-		for ( s = ber->ber_sos; s != NULL; s = s->sos_next ) {
-			off = s->sos_first - oldbuf;
-			s->sos_first = ber->ber_buf + off;
-
-			off = s->sos_ptr - oldbuf;
-			s->sos_ptr = ber->ber_buf + off;
-		}
+	buf = (char *) ber_memrealloc_x( buf, total, ber->ber_memctx );
+	if ( buf == NULL ) {
+		return( -1 );
 	}
 
+	ber->ber_buf = buf;
+	ber->ber_end = buf + total;
+	ber->ber_ptr = buf + offset;
+	if ( sos_offset )
+		ber->ber_sos_ptr = buf + sos_offset;
+
 	return( 0 );
 }
 
 void
 ber_free_buf( BerElement *ber )
 {
-	Seqorset *s, *next;
-
 	assert( LBER_VALID( ber ) );
 
 	if ( ber->ber_buf) ber_memfree_x( ber->ber_buf, ber->ber_memctx );
 
-	for( s = ber->ber_sos ; s != NULL ; s = next ) {
-		next = s->sos_next;
-		ber_memfree_x( s, ber->ber_memctx );
-	}
-
 	ber->ber_buf = NULL;
-	ber->ber_sos = NULL;
+	ber->ber_sos_ptr = NULL;
 	ber->ber_valid = LBER_UNINITIALIZED;
 }
 
@@ -230,7 +221,6 @@
 
 	assert( sb != NULL );
 	assert( ber != NULL );
-
 	assert( SOCKBUF_VALID( sb ) );
 	assert( LBER_VALID( ber ) );
 
@@ -415,10 +405,13 @@
 				return -1;
 			}
 			AC_MEMCPY( bv->bv_val, ber->ber_buf, len );
-		} else {
+			bv->bv_val[len] = '\0';
+		} else if ( ber->ber_buf != NULL ) {
 			bv->bv_val = ber->ber_buf;
+			bv->bv_val[len] = '\0';
+		} else {
+			bv->bv_val = "";
 		}
-		bv->bv_val[len] = '\0';
 		bv->bv_len = len;
 	}
 	return 0;
@@ -484,7 +477,6 @@
 	assert( sb != NULL );
 	assert( len != NULL );
 	assert( ber != NULL );
-
 	assert( SOCKBUF_VALID( sb ) );
 	assert( LBER_VALID( ber ) );
 
@@ -725,9 +717,13 @@
 ber_rewind ( BerElement * ber )
 {
 	ber->ber_rwptr = NULL;
-	ber->ber_sos = NULL;
+	ber->ber_sos_ptr = NULL;
 	ber->ber_end = ber->ber_ptr;
 	ber->ber_ptr = ber->ber_buf;
+#if 0	/* TODO: Should we add this? */
+	ber->ber_tag = LBER_DEFAULT;
+	ber->ber_usertag = 0;
+#endif
 }
 
 int

Modified: openldap/trunk/libraries/liblber/lber-int.h
===================================================================
--- openldap/trunk/libraries/liblber/lber-int.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblber/lber-int.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/liblber/lber-int.h,v 1.68.2.4 2009/01/22 00:00:53 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblber/lber-int.h,v 1.68.2.5 2009/08/02 21:06:34 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -72,12 +72,39 @@
 LBER_V (struct lber_options) ber_int_options;
 #define ber_int_debug ber_int_options.lbo_debug
 
+/* Data encoded in ASN.1 BER format */
 struct berelement {
 	struct		lber_options ber_opts;
 #define ber_valid		ber_opts.lbo_valid
 #define ber_options		ber_opts.lbo_options
 #define ber_debug		ber_opts.lbo_debug
 
+	/*
+	 * The members below, when not NULL/LBER_DEFAULT/etc, are:
+	 *   ber_buf       Data buffer.  Other pointers normally point into it.
+	 *   ber_rwptr     Read/write cursor for Sockbuf I/O.
+	 *   ber_memctx    Context passed to ber_memalloc() & co.
+	 * When decoding data (reading it from the BerElement):
+	 *   ber_end       End of BER data.
+	 *   ber_ptr       Read cursor, except for 1st octet of tags.
+	 *   ber_tag       1st octet of next tag, saved from *ber_ptr when
+	 *                 ber_ptr may be pointing at a tag and is >ber_buf.
+	 *                 The octet *ber_ptr itself may get overwritten with
+	 *                 a \0, to terminate the preceding element.
+	 * When encoding data (writing it to the BerElement):
+	 *   ber_end       End of allocated buffer - 1 (allowing a final \0).
+	 *   ber_ptr       Last complete BER element (normally write cursor).
+	 *   ber_sos_ptr   NULL or write cursor for incomplete sequence or set.
+	 *   ber_sos_inner offset(seq/set length octets) if ber_sos_ptr!=NULL.
+	 *   ber_tag       Default tag for next ber_printf() element.
+	 *   ber_usertag   True after a ber_printf format char set ber_tag.
+	 *   ber_len       Reused for ber_sos_inner.
+	 * When output to a Sockbuf:
+	 *   ber_ptr       End of encoded data to write.
+	 * When input from a Sockbuf:
+	 *   See ber_get_next().
+	 */
+
 	/* Do not change the order of these 3 fields! see ber_get_next */
 	ber_tag_t	ber_tag;
 	ber_len_t	ber_len;
@@ -87,7 +114,9 @@
 	char		*ber_ptr;
 	char		*ber_end;
 
-	struct seqorset	*ber_sos;
+	char		*ber_sos_ptr;
+#	define		ber_sos_inner	ber_len /* reused for binary compat */
+
 	char		*ber_rwptr;
 	void		*ber_memctx;
 };
@@ -115,16 +144,7 @@
 
 #define SOCKBUF_VALID( sb )	( (sb)->sb_valid == LBER_VALID_SOCKBUF )
 
-struct seqorset {
-	BerElement	*sos_ber;
-	ber_len_t	sos_clen;
-	ber_tag_t	sos_tag;
-	char		*sos_first;
-	char		*sos_ptr;
-	struct seqorset	*sos_next;
-};
 
-
 /*
  * decode.c, encode.c
  */
@@ -165,12 +185,6 @@
 	BerElement *ber,
 	int inout ));
 
-LBER_F( int )
-ber_log_sos_dump LDAP_P((
-	int errlvl,
-	int loglvl,
-	Seqorset *sos ));
-
 LBER_V (BER_LOG_FN) ber_int_log_proc;
 LBER_V (FILE *) ber_pvt_err_file;
 

Modified: openldap/trunk/libraries/libldap/cyrus.c
===================================================================
--- openldap/trunk/libraries/libldap/cyrus.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/cyrus.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/cyrus.c,v 1.133.2.13 2009/02/08 06:06:04 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/cyrus.c,v 1.133.2.15 2009/08/25 23:04:13 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -1013,6 +1013,31 @@
 			*(int *)arg = (int) LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON );
 			break;
 
+		case LDAP_OPT_X_SASL_USERNAME: {
+			int sc;
+			char *username;
+			sasl_conn_t *ctx;
+
+			if( ld->ld_defconn == NULL ) {
+				return -1;
+			}
+
+			ctx = ld->ld_defconn->lconn_sasl_authctx;
+
+			if ( ctx == NULL ) {
+				return -1;
+			}
+
+			sc = sasl_getprop( ctx, SASL_USERNAME,
+				(SASL_CONST void **)(char **) &username );
+
+			if ( sc != SASL_OK ) {
+				return -1;
+			}
+
+			*(char **)arg = username ? LDAP_STRDUP( username ) : NULL;
+		} break;
+
 		case LDAP_OPT_X_SASL_SECPROPS:
 			/* this option is write only */
 			return -1;
@@ -1034,6 +1059,7 @@
 
 	switch ( option ) {
 	case LDAP_OPT_X_SASL_SSF:
+	case LDAP_OPT_X_SASL_USERNAME:
 		/* This option is read-only */
 		return -1;
 

Modified: openldap/trunk/libraries/libldap/error.c
===================================================================
--- openldap/trunk/libraries/libldap/error.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/error.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/error.c,v 1.76.2.4 2009/01/22 00:00:54 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/error.c,v 1.76.2.6 2009/08/12 23:54:21 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -25,155 +25,142 @@
 
 #include "ldap-int.h"
 
-struct ldaperror {
-	int	e_code;
-	char *e_reason;
-};
+void ldap_int_error_init( void ) {
+}
 
-static struct ldaperror ldap_builtin_errlist[] = {
-	{LDAP_SUCCESS, 					N_("Success")},
-	{LDAP_OPERATIONS_ERROR, 		N_("Operations error")},
-	{LDAP_PROTOCOL_ERROR, 			N_("Protocol error")},
-	{LDAP_TIMELIMIT_EXCEEDED,		N_("Time limit exceeded")},
-	{LDAP_SIZELIMIT_EXCEEDED, 		N_("Size limit exceeded")},
-	{LDAP_COMPARE_FALSE, 			N_("Compare False")},
-	{LDAP_COMPARE_TRUE, 			N_("Compare True")},
-	{LDAP_STRONG_AUTH_NOT_SUPPORTED, N_("Authentication method not supported")},
-	{LDAP_STRONG_AUTH_REQUIRED, 	N_("Strong(er) authentication required")},
-	{LDAP_PARTIAL_RESULTS, 			N_("Partial results and referral received")},
+char *
+ldap_err2string( int err )
+{
+	char *m;
 
-	{LDAP_REFERRAL,					N_("Referral")},
-	{LDAP_ADMINLIMIT_EXCEEDED,		N_("Administrative limit exceeded")},
-	{LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
-									N_("Critical extension is unavailable")},
-	{LDAP_CONFIDENTIALITY_REQUIRED,	N_("Confidentiality required")},
-	{LDAP_SASL_BIND_IN_PROGRESS,	N_("SASL bind in progress")},
+	Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
 
-	{LDAP_NO_SUCH_ATTRIBUTE, 		N_("No such attribute")},
-	{LDAP_UNDEFINED_TYPE, 			N_("Undefined attribute type")},
-	{LDAP_INAPPROPRIATE_MATCHING, 	N_("Inappropriate matching")},
-	{LDAP_CONSTRAINT_VIOLATION, 	N_("Constraint violation")},
-	{LDAP_TYPE_OR_VALUE_EXISTS, 	N_("Type or value exists")},
-	{LDAP_INVALID_SYNTAX, 			N_("Invalid syntax")},
+	switch ( err ) {
+#	define C(code, message) case code: m = message; break
 
-	{LDAP_NO_SUCH_OBJECT, 			N_("No such object")},
-	{LDAP_ALIAS_PROBLEM, 			N_("Alias problem")},
-	{LDAP_INVALID_DN_SYNTAX,		N_("Invalid DN syntax")},
-	{LDAP_IS_LEAF, 					N_("Entry is a leaf")},
-	{LDAP_ALIAS_DEREF_PROBLEM,	 	N_("Alias dereferencing problem")},
+	/* LDAPv3 (RFC 4511) codes */
+	C(LDAP_SUCCESS,					N_("Success"));
+	C(LDAP_OPERATIONS_ERROR, 		N_("Operations error"));
+	C(LDAP_PROTOCOL_ERROR, 			N_("Protocol error"));
+	C(LDAP_TIMELIMIT_EXCEEDED,		N_("Time limit exceeded"));
+	C(LDAP_SIZELIMIT_EXCEEDED, 		N_("Size limit exceeded"));
+	C(LDAP_COMPARE_FALSE, 			N_("Compare False"));
+	C(LDAP_COMPARE_TRUE, 			N_("Compare True"));
+	C(LDAP_STRONG_AUTH_NOT_SUPPORTED,N_("Authentication method not supported"));
+	C(LDAP_STRONG_AUTH_REQUIRED,	N_("Strong(er) authentication required"));
 
-	{LDAP_INAPPROPRIATE_AUTH, 		N_("Inappropriate authentication")},
-	{LDAP_INVALID_CREDENTIALS, 		N_("Invalid credentials")},
-	{LDAP_INSUFFICIENT_ACCESS, 		N_("Insufficient access")},
-	{LDAP_BUSY, 					N_("Server is busy")},
-	{LDAP_UNAVAILABLE, 				N_("Server is unavailable")},
-	{LDAP_UNWILLING_TO_PERFORM, 	N_("Server is unwilling to perform")},
-	{LDAP_LOOP_DETECT, 				N_("Loop detected")},
+	C(LDAP_REFERRAL,				N_("Referral"));
+	C(LDAP_ADMINLIMIT_EXCEEDED,		N_("Administrative limit exceeded"));
+	C(LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
+									N_("Critical extension is unavailable"));
+	C(LDAP_CONFIDENTIALITY_REQUIRED,N_("Confidentiality required"));
+	C(LDAP_SASL_BIND_IN_PROGRESS,	N_("SASL bind in progress"));
 
-	{LDAP_NAMING_VIOLATION, 		N_("Naming violation")},
-	{LDAP_OBJECT_CLASS_VIOLATION, 	N_("Object class violation")},
-	{LDAP_NOT_ALLOWED_ON_NONLEAF, 	N_("Operation not allowed on non-leaf")},
-	{LDAP_NOT_ALLOWED_ON_RDN,	 	N_("Operation not allowed on RDN")},
-	{LDAP_ALREADY_EXISTS, 			N_("Already exists")},
-	{LDAP_NO_OBJECT_CLASS_MODS, 	N_("Cannot modify object class")},
-	{LDAP_RESULTS_TOO_LARGE,		N_("Results too large")},
-	{LDAP_AFFECTS_MULTIPLE_DSAS,	N_("Operation affects multiple DSAs")},
+	C(LDAP_NO_SUCH_ATTRIBUTE, 		N_("No such attribute"));
+	C(LDAP_UNDEFINED_TYPE, 			N_("Undefined attribute type"));
+	C(LDAP_INAPPROPRIATE_MATCHING, 	N_("Inappropriate matching"));
+	C(LDAP_CONSTRAINT_VIOLATION, 	N_("Constraint violation"));
+	C(LDAP_TYPE_OR_VALUE_EXISTS, 	N_("Type or value exists"));
+	C(LDAP_INVALID_SYNTAX, 			N_("Invalid syntax"));
 
-	{LDAP_OTHER, 					N_("Other (e.g., implementation specific) error")},
+	C(LDAP_NO_SUCH_OBJECT, 			N_("No such object"));
+	C(LDAP_ALIAS_PROBLEM, 			N_("Alias problem"));
+	C(LDAP_INVALID_DN_SYNTAX,		N_("Invalid DN syntax"));
 
-	{LDAP_CANCELLED,				N_("Cancelled")},
-	{LDAP_NO_SUCH_OPERATION,		N_("No Operation to Cancel")},
-	{LDAP_TOO_LATE,					N_("Too Late to Cancel")},
-	{LDAP_CANNOT_CANCEL,			N_("Cannot Cancel")},
+	C(LDAP_ALIAS_DEREF_PROBLEM,	 	N_("Alias dereferencing problem"));
 
-	{LDAP_ASSERTION_FAILED,			N_("Assertion Failed")},
-	{LDAP_X_ASSERTION_FAILED,		N_("Assertion Failed (X)")},
+	C(LDAP_INAPPROPRIATE_AUTH, 		N_("Inappropriate authentication"));
+	C(LDAP_INVALID_CREDENTIALS, 	N_("Invalid credentials"));
+	C(LDAP_INSUFFICIENT_ACCESS, 	N_("Insufficient access"));
+	C(LDAP_BUSY, 					N_("Server is busy"));
+	C(LDAP_UNAVAILABLE, 			N_("Server is unavailable"));
+	C(LDAP_UNWILLING_TO_PERFORM, 	N_("Server is unwilling to perform"));
+	C(LDAP_LOOP_DETECT, 			N_("Loop detected"));
 
-	{LDAP_PROXIED_AUTHORIZATION_DENIED, N_("Proxied Authorization Denied")},
-	{LDAP_X_PROXY_AUTHZ_FAILURE,		N_("Proxy Authorization Failure (X)")},
+	C(LDAP_NAMING_VIOLATION, 		N_("Naming violation"));
+	C(LDAP_OBJECT_CLASS_VIOLATION, 	N_("Object class violation"));
+	C(LDAP_NOT_ALLOWED_ON_NONLEAF, 	N_("Operation not allowed on non-leaf"));
+	C(LDAP_NOT_ALLOWED_ON_RDN,	 	N_("Operation not allowed on RDN"));
+	C(LDAP_ALREADY_EXISTS, 			N_("Already exists"));
+	C(LDAP_NO_OBJECT_CLASS_MODS, 	N_("Cannot modify object class"));
 
-	{LDAP_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required")},
-	{LDAP_X_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required (X)")},
+	C(LDAP_AFFECTS_MULTIPLE_DSAS,	N_("Operation affects multiple DSAs"));
 
-	{LDAP_X_NO_OPERATION,			N_("No Operation (X)")},
+	/* Virtual List View draft */
+	C(LDAP_VLV_ERROR,				N_("Virtual List View error"));
 
-	{LDAP_CUP_RESOURCES_EXHAUSTED,	N_("LCUP Resources Exhausted")},
-	{LDAP_CUP_SECURITY_VIOLATION,	N_("LCUP Security Violation")},
-	{LDAP_CUP_INVALID_DATA,			N_("LCUP Invalid Data")},
-	{LDAP_CUP_UNSUPPORTED_SCHEME,	N_("LCUP Unsupported Scheme")},
-	{LDAP_CUP_RELOAD_REQUIRED,		N_("LCUP Reload Required")},
+	C(LDAP_OTHER, N_("Other (e.g., implementation specific) error"));
 
-#ifdef LDAP_X_TXN
-	{LDAP_X_TXN_SPECIFY_OKAY,		N_("TXN specify okay")},
-	{LDAP_X_TXN_ID_INVALID,			N_("TXN ID is invalid")},
-#endif
+	/* LDAPv2 (RFC 1777) codes */
+	C(LDAP_PARTIAL_RESULTS, N_("Partial results and referral received"));
+	C(LDAP_IS_LEAF, 				N_("Entry is a leaf"));
 
-	/* API ResultCodes */
-	{LDAP_SERVER_DOWN,				N_("Can't contact LDAP server")},
-	{LDAP_LOCAL_ERROR,				N_("Local error")},
-	{LDAP_ENCODING_ERROR,			N_("Encoding error")},
-	{LDAP_DECODING_ERROR,			N_("Decoding error")},
-	{LDAP_TIMEOUT,					N_("Timed out")},
-	{LDAP_AUTH_UNKNOWN,				N_("Unknown authentication method")},
-	{LDAP_FILTER_ERROR,				N_("Bad search filter")},
-	{LDAP_USER_CANCELLED,			N_("User cancelled operation")},
-	{LDAP_PARAM_ERROR,				N_("Bad parameter to an ldap routine")},
-	{LDAP_NO_MEMORY,				N_("Out of memory")},
+	/* Connection-less LDAP (CLDAP - RFC 1798) code */
+	C(LDAP_RESULTS_TOO_LARGE,		N_("Results too large"));
 
-	{LDAP_CONNECT_ERROR,			N_("Connect error")},
-	{LDAP_NOT_SUPPORTED,			N_("Not Supported")},
-	{LDAP_CONTROL_NOT_FOUND,		N_("Control not found")},
-	{LDAP_NO_RESULTS_RETURNED,		N_("No results returned")},
-	{LDAP_MORE_RESULTS_TO_RETURN,	N_("More results to return")},
-	{LDAP_CLIENT_LOOP,				N_("Client Loop")},
-	{LDAP_REFERRAL_LIMIT_EXCEEDED,	N_("Referral Limit Exceeded")},
+	/* Cancel Operation (RFC 3909) codes */
+	C(LDAP_CANCELLED,				N_("Cancelled"));
+	C(LDAP_NO_SUCH_OPERATION,		N_("No Operation to Cancel"));
+	C(LDAP_TOO_LATE,				N_("Too Late to Cancel"));
+	C(LDAP_CANNOT_CANCEL,			N_("Cannot Cancel"));
 
-	{0, NULL}
-};
+	/* Assert Control (RFC 4528 and old internet-draft) codes */
+	C(LDAP_ASSERTION_FAILED,		N_("Assertion Failed"));
+	C(LDAP_X_ASSERTION_FAILED,		N_("Assertion Failed (X)"));
 
-static struct ldaperror *ldap_errlist = ldap_builtin_errlist; 
+	/* Proxied Authorization Control (RFC 4370 and I-D) codes */
+	C(LDAP_PROXIED_AUTHORIZATION_DENIED, N_("Proxied Authorization Denied"));
+	C(LDAP_X_PROXY_AUTHZ_FAILURE,	N_("Proxy Authorization Failure (X)"));
 
-void ldap_int_error_init( void ) {
-}
+	/* Content Sync Operation (RFC 4533 and I-D) codes */
+	C(LDAP_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required"));
+	C(LDAP_X_SYNC_REFRESH_REQUIRED,	N_("Content Sync Refresh Required (X)"));
 
-static const struct ldaperror *
-ldap_int_error( int err )
-{
-	int	i;
+	/* No-Op Control (draft-zeilenga-ldap-noop) code */
+	C(LDAP_X_NO_OPERATION,			N_("No Operation (X)"));
 
-	/* XXYYZ: O(n) search instead of O(1) lookup */
-	for ( i=0; ldap_errlist[i].e_reason != NULL; i++ ) {
-		if ( err == ldap_errlist[i].e_code ) {
-			return &ldap_errlist[i];
-		}
-	}
+	/* Client Update Protocol (RFC 3928) codes */
+	C(LDAP_CUP_RESOURCES_EXHAUSTED,	N_("LCUP Resources Exhausted"));
+	C(LDAP_CUP_SECURITY_VIOLATION,	N_("LCUP Security Violation"));
+	C(LDAP_CUP_INVALID_DATA,		N_("LCUP Invalid Data"));
+	C(LDAP_CUP_UNSUPPORTED_SCHEME,	N_("LCUP Unsupported Scheme"));
+	C(LDAP_CUP_RELOAD_REQUIRED,		N_("LCUP Reload Required"));
 
-	return NULL;
-}
+#ifdef LDAP_X_TXN
+	/* Codes related to LDAP Transactions (draft-zeilenga-ldap-txn) */
+	C(LDAP_X_TXN_SPECIFY_OKAY,		N_("TXN specify okay"));
+	C(LDAP_X_TXN_ID_INVALID,		N_("TXN ID is invalid"));
+#endif
 
-char *
-ldap_err2string( int err )
-{
-	const struct ldaperror *e;
-	
-	Debug( LDAP_DEBUG_TRACE, "ldap_err2string\n", 0, 0, 0 );
+	/* API codes - renumbered since draft-ietf-ldapext-ldap-c-api */
+	C(LDAP_SERVER_DOWN,				N_("Can't contact LDAP server"));
+	C(LDAP_LOCAL_ERROR,				N_("Local error"));
+	C(LDAP_ENCODING_ERROR,			N_("Encoding error"));
+	C(LDAP_DECODING_ERROR,			N_("Decoding error"));
+	C(LDAP_TIMEOUT,					N_("Timed out"));
+	C(LDAP_AUTH_UNKNOWN,			N_("Unknown authentication method"));
+	C(LDAP_FILTER_ERROR,			N_("Bad search filter"));
+	C(LDAP_USER_CANCELLED,			N_("User cancelled operation"));
+	C(LDAP_PARAM_ERROR,				N_("Bad parameter to an ldap routine"));
+	C(LDAP_NO_MEMORY,				N_("Out of memory"));
+	C(LDAP_CONNECT_ERROR,			N_("Connect error"));
+	C(LDAP_NOT_SUPPORTED,			N_("Not Supported"));
+	C(LDAP_CONTROL_NOT_FOUND,		N_("Control not found"));
+	C(LDAP_NO_RESULTS_RETURNED,		N_("No results returned"));
+	C(LDAP_MORE_RESULTS_TO_RETURN,	N_("More results to return"));
+	C(LDAP_CLIENT_LOOP,				N_("Client Loop"));
+	C(LDAP_REFERRAL_LIMIT_EXCEEDED,	N_("Referral Limit Exceeded"));
+#	undef C
 
-	e = ldap_int_error( err );
-
-	if (e) {
-		return e->e_reason;
-
-	} else if ( LDAP_API_ERROR(err) ) {
-		return _("Unknown API error");
-
-	} else if ( LDAP_E_ERROR(err) ) {
-		return _("Unknown (extension) error");
-
-	} else if ( LDAP_X_ERROR(err) ) {
-		return _("Unknown (private extension) error");
+	default:
+		m = (LDAP_API_ERROR(err) ? N_("Unknown API error")
+			 : LDAP_E_ERROR(err) ? N_("Unknown (extension) error")
+			 : LDAP_X_ERROR(err) ? N_("Unknown (private extension) error")
+			 : N_("Unknown error"));
+		break;
 	}
 
-	return _("Unknown error");
+	return _(m);
 }
 
 /* deprecated */
@@ -181,18 +168,14 @@
 ldap_perror( LDAP *ld, LDAP_CONST char *str )
 {
     int i;
-	const struct ldaperror *e;
-	Debug( LDAP_DEBUG_TRACE, "ldap_perror\n", 0, 0, 0 );
 
 	assert( ld != NULL );
 	assert( LDAP_VALID( ld ) );
 	assert( str != NULL );
 
-	e = ldap_int_error( ld->ld_errno );
-
 	fprintf( stderr, "%s: %s (%d)\n",
 		str ? str : "ldap_perror",
-		e ? _(e->e_reason) : _("unknown result code"),
+		ldap_err2string( ld->ld_errno ),
 		ld->ld_errno );
 
 	if ( ld->ld_matched != NULL && ld->ld_matched[0] != '\0' ) {

Modified: openldap/trunk/libraries/libldap/init.c
===================================================================
--- openldap/trunk/libraries/libldap/init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/init.c,v 1.102.2.11 2009/01/26 23:29:53 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/init.c,v 1.102.2.12 2009/08/12 23:40:55 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -545,6 +545,9 @@
 	gopts->ldo_tls_connect_arg = NULL;
 	gopts->ldo_tls_require_cert = LDAP_OPT_X_TLS_DEMAND;
 #endif
+	gopts->ldo_keepalive_probes = 0;
+	gopts->ldo_keepalive_interval = 0;
+	gopts->ldo_keepalive_idle = 0;
 
 	gopts->ldo_valid = LDAP_INITIALIZED;
    	return;

Modified: openldap/trunk/libraries/libldap/ldap-int.h
===================================================================
--- openldap/trunk/libraries/libldap/ldap-int.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/ldap-int.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /*  ldap-int.h - defines & prototypes internal to the LDAP library */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/ldap-int.h,v 1.168.2.15 2009/05/01 19:39:03 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/ldap-int.h,v 1.168.2.16 2009/08/12 23:40:55 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -244,6 +244,14 @@
 	unsigned ldo_gssapi_options;
 #endif
 
+	/*
+	 * Per connection tcp-keepalive settings (Linux only,
+	 * ignored where unsupported)
+	 */
+	ber_int_t ldo_keepalive_idle;
+	ber_int_t ldo_keepalive_probes;
+	ber_int_t ldo_keepalive_interval;
+
 	int		ldo_refhoplimit;	/* limit on referral nesting */
 
 	/* LDAPv3 server and client controls */

Modified: openldap/trunk/libraries/libldap/options.c
===================================================================
--- openldap/trunk/libraries/libldap/options.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/options.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/options.c,v 1.75.2.10 2009/01/22 00:00:54 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/options.c,v 1.75.2.11 2009/08/12 23:40:56 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -342,7 +342,19 @@
 	case LDAP_OPT_DEBUG_LEVEL:
 		* (int *) outvalue = lo->ldo_debug;
 		return LDAP_OPT_SUCCESS;
+	
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+		* (int *) outvalue = lo->ldo_keepalive_idle;
+		return LDAP_OPT_SUCCESS;
 
+	case LDAP_OPT_X_KEEPALIVE_PROBES:
+		* (int *) outvalue = lo->ldo_keepalive_probes;
+		return LDAP_OPT_SUCCESS;
+
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
+		* (int *) outvalue = lo->ldo_keepalive_interval;
+		return LDAP_OPT_SUCCESS;
+
 	default:
 #ifdef HAVE_TLS
 		if ( ldap_pvt_tls_get_option( ld, option, outvalue ) == 0 ) {
@@ -681,6 +693,9 @@
 	case LDAP_OPT_TIMEOUT:
 	case LDAP_OPT_NETWORK_TIMEOUT:
 	case LDAP_OPT_CONNECT_CB:
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+	case LDAP_OPT_X_KEEPALIVE_PROBES :
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
 		if(invalue == NULL) {
 			/* no place to set from */
 			return LDAP_OPT_ERROR;
@@ -770,6 +785,16 @@
 			lo->ldo_conn_cbs = ll;
 		}
 		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_IDLE:
+		lo->ldo_keepalive_idle = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_PROBES :
+		lo->ldo_keepalive_probes = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	case LDAP_OPT_X_KEEPALIVE_INTERVAL :
+		lo->ldo_keepalive_interval = * (const int *) invalue;
+		return LDAP_OPT_SUCCESS;
+	
 	}
 	return LDAP_OPT_ERROR;
 }

Modified: openldap/trunk/libraries/libldap/os-ip.c
===================================================================
--- openldap/trunk/libraries/libldap/os-ip.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/os-ip.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* os-ip.c -- platform-specific TCP & UDP related code */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.118.2.15 2009/02/17 21:02:51 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.118.2.19 2009/08/14 20:31:32 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -142,6 +142,57 @@
 				"setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n",
 				s, 0, 0 );
 		}
+		if ( ld->ld_options.ldo_keepalive_idle > 0 )
+		{
+#ifdef TCP_KEEPIDLE
+			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE,
+					(void*) &ld->ld_options.ldo_keepalive_idle,
+					sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n",
+					s, 0, 0 );
+			}
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPIDLE not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPIDLE */
+		}
+		if ( ld->ld_options.ldo_keepalive_probes > 0 )
+		{
+#ifdef TCP_KEEPCNT
+			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT,
+					(void*) &ld->ld_options.ldo_keepalive_probes,
+					sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n",
+					s, 0, 0 );
+			}
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPCNT not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPCNT */
+		}
+		if ( ld->ld_options.ldo_keepalive_interval > 0 )
+		{
+#ifdef TCP_KEEPINTVL
+			if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL,
+					(void*) &ld->ld_options.ldo_keepalive_interval,
+					sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR )
+			{
+				osip_debug( ld, "ldap_prepare_socket: "
+					"setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n",
+					s, 0, 0 );
+			} 
+#else
+			osip_debug( ld, "ldap_prepare_socket: "
+					"sockopt TCP_KEEPINTVL not supported on this system.\n", 
+					0, 0, 0 );
+#endif /* TCP_KEEPINTVL */
+		}
 #endif /* SO_KEEPALIVE */
 #ifdef TCP_NODELAY
 		if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY,

Modified: openldap/trunk/libraries/libldap/os-local.c
===================================================================
--- openldap/trunk/libraries/libldap/os-local.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/os-local.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* os-local.c -- platform-specific domain socket code */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/os-local.c,v 1.44.2.8 2009/02/17 21:02:51 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/os-local.c,v 1.44.2.9 2009/08/12 23:48:32 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -234,7 +234,7 @@
 				msg.msg_accrights = (char *)fds;
 				msg.msg_accrightslen = sizeof(int);
 # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
-				getpeername( s, sa, &salen );
+				getpeername( s, (struct sockaddr *) sa, &salen );
 				fchmod( fds[0], S_ISUID|S_IRWXU );
 				write( fds[1], sa, salen );
 				sendmsg( s, &msg, 0 );

Modified: openldap/trunk/libraries/libldap/tls_g.c
===================================================================
--- openldap/trunk/libraries/libldap/tls_g.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/tls_g.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* tls_g.c - Handle tls/ssl using GNUTLS. */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_g.c,v 1.6.2.5 2009/04/29 01:25:43 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_g.c,v 1.6.2.6 2009/08/13 00:52:04 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
@@ -722,9 +722,24 @@
 	if ( ret >= 0 ) {
 		ret = LDAP_SUCCESS;
 	} else {
-		altnamesize = sizeof(altname);
-		ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
-			0, 0, altname, &altnamesize );
+		/* find the last CN */
+		i=0;
+		do {
+			altnamesize = 0;
+			ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
+				i, 1, altname, &altnamesize );
+			if ( ret == GNUTLS_E_SHORT_MEMORY_BUFFER )
+				i++;
+			else
+				break;
+		} while ( 1 );
+
+		if ( i ) {
+			altnamesize = sizeof(altname);
+			ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
+				i-1, 0, altname, &altnamesize );
+		}
+
 		if ( ret < 0 ) {
 			Debug( LDAP_DEBUG_ANY,
 				"TLS: unable to get common name from peer certificate.\n",

Modified: openldap/trunk/libraries/libldap/tls_m.c
===================================================================
--- openldap/trunk/libraries/libldap/tls_m.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/tls_m.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* tls_m.c - Handle tls/ssl using Mozilla NSS. */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_m.c,v 1.3.2.4 2009/07/06 19:31:48 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_m.c,v 1.3.2.7 2009/08/30 22:55:46 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
@@ -53,14 +53,16 @@
 #include <termios.h> /* for echo on/off */
 #endif
 
-#include <nspr.h>
-#include <private/pprio.h>
-#include <nss.h>
-#include <ssl.h>
-#include <sslproto.h>
-#include <pk11pub.h>
-#include <secerr.h>
-#include <keyhi.h>
+#include <nspr/nspr.h>
+#include <nspr/private/pprio.h>
+#include <nss/nss.h>
+#include <nss/ssl.h>
+#include <nss/sslerr.h>
+#include <nss/sslproto.h>
+#include <nss/pk11pub.h>
+#include <nss/secerr.h>
+#include <nss/keyhi.h>
+#include <nss/secmod.h>
 
 typedef struct tlsm_ctx {
 	PRFileDesc *tc_model;
@@ -73,6 +75,8 @@
 	int tc_is_server;
 	int tc_require_cert;
 	PRCallOnceType tc_callonce;
+	PRBool tc_using_pem;
+	char *tc_slotname; /* if using pem */
 #ifdef LDAP_R_COMPILE
 	ldap_pvt_thread_mutex_t tc_refmutex;
 #endif
@@ -86,8 +90,18 @@
 
 static int tlsm_did_init;
 
+static const char* pem_library = "nsspem";
+static SECMODModule* pemMod = NULL;
+
 #define DEFAULT_TOKEN_NAME "default"
+/* sprintf format used to create token name */
+#define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
 
+static int tlsm_slot_count;
+
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+                (x)->pValue=(v); (x)->ulValueLen = (l);
+
 /* forward declaration */
 static int tlsm_init( void );
 
@@ -639,6 +653,9 @@
 			success = SECFailure;
 		}
 		break;
+	/* we bypass NSS's hostname checks and do our own */
+	case SSL_ERROR_BAD_CERT_DOMAIN:
+		break;
 	default:
 		success = SECFailure;
 		break;
@@ -679,116 +696,6 @@
 	return "";
 }
 
-static SECStatus
-tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
-                       PRBool checksig, PRBool isServer)
-{
-	SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
-
-	Debug( LDAP_DEBUG_TRACE,
-		   "TLS certificate verification: %s: %s,",
-		   ret == SECSuccess ? "ok" : "bad",
-		   tlsm_dump_security_status( fd ), 0 );
-
-	if ( ret != SECSuccess ) {
-		PRErrorCode errcode = PORT_GetError();
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS certificate verification: Error, %d: %s\n",
-			   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
-	}
-
-	return ret;
-}
-
-static char *
-tlsm_dirname(const char *pathname)
-{
-	char *ret = NULL;
-	char *p = NULL;
-	char sep = PR_GetDirectorySeparator();
-
-	if (pathname && (p = PL_strrchr(pathname, sep)) && (p > pathname)) {
-		ret = PL_strndup(pathname, (p - pathname));
-	}
-
-	return ret;
-}
-
-/*
- * This is the part of the init we defer until we get the
- * actual security configuration information.  This is
- * only called once, protected by a PRCallOnce
- * NOTE: This must be done before the first call to SSL_ImportFD,
- * especially the setting of the policy
- * NOTE: This must be called after fork()
- */
-static int
-tlsm_deferred_init( void *arg )
-{
-	tlsm_ctx *ctx = (tlsm_ctx *)arg;
-	struct ldaptls *lt = ctx->tc_config;
-	char *securitydir = NULL;
-	int needfree = 0;
-	char *val;
-	PRErrorCode errcode;
-
-	/* NSS support for multi-init is coming */
-#ifndef NSS_MULTI_INIT
-	if ( !NSS_IsInitialized() ) {
-#endif /* NSS_MULTI_INIT */
-		/*
-		  MOZNSS_DIR will override everything else - you can
-		  always set MOZNSS_DIR to force the use of this
-		  directory
-		  DEFAULT_MOZNSS_DIR will only be used if the code cannot
-		  find a security dir to use based on the current
-		  settings
-		*/
-		if ( (val = PR_GetEnv( "MOZNSS_DIR" ) ) && (*val) ) {
-			securitydir = PL_strdup( val );
-			needfree = 1;
-		} else if ( lt->lt_cacertdir ) {
-			securitydir = lt->lt_cacertdir;
-		} else if ( lt->lt_cacertfile ) {
-			securitydir = tlsm_dirname( lt->lt_cacertfile );
-			needfree = 1;
-		} else if ( lt->lt_certfile ) {
-			securitydir = tlsm_dirname( lt->lt_certfile );
-			needfree = 1;
-		} else if ( lt->lt_keyfile ) {
-			securitydir = tlsm_dirname( lt->lt_keyfile );
-			needfree = 1;
-		} else if ( (val = PR_GetEnv( "DEFAULT_MOZNSS_DIR" ) ) && (*val) ) {
-			securitydir = PL_strdup( val );
-			needfree = 1;
-		} else {
-			securitydir = "/etc/pki/nssdb";
-		}
-
-		if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) {
-			errcode = PORT_GetError();
-			Debug( LDAP_DEBUG_ANY,
-				   "TLS: could not initialize moznss using security dir %s - error %d:%s.\n",
-				   securitydir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
-			if ( needfree ) {
-				PL_strfree( securitydir );
-			}
-			return -1;
-		}
-
-		if ( needfree ) {
-			PL_strfree( securitydir );
-		}
-
-		NSS_SetDomesticPolicy();
-		tlsm_did_init = 1; /* we did the init - we should also clean up */
-#ifndef NSS_MULTI_INIT
-	}
-#endif /* NSS_MULTI_INIT */
-
-	return 0;
-}
-
 #ifdef READ_PASSWORD_FROM_FILE
 static char *
 tlsm_get_pin_from_file(const char *token_name, tlsm_ctx *ctx)
@@ -968,7 +875,389 @@
 	return tlsm_get_pin( slot, retry, ctx );
 }
 
+static SECStatus
+tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
+                       PRBool checksig, PRBool isServer)
+{
+	SECStatus ret = SSL_AuthCertificate(arg, fd, checksig, isServer);
+
+	tlsm_dump_security_status( fd );
+	Debug( LDAP_DEBUG_TRACE,
+		   "TLS certificate verification: %s\n",
+		   ret == SECSuccess ? "ok" : "bad", 0, 0 );
+
+	if ( ret != SECSuccess ) {
+		PRErrorCode errcode = PORT_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS certificate verification: Error, %d: %s\n",
+			   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 ) ;
+	}
+
+	return ret;
+}
+
 static int
+tlsm_authenticate_to_slot( tlsm_ctx *ctx, PK11SlotInfo *slot )
+{
+	int rc = -1;
+
+	if ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) {
+		char *token_name = PK11_GetTokenName( slot );
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not authenticate to the security token %s - error %d:%s.\n",
+			   token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
+			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+	} else {
+		rc = 0; /* success */
+	}
+
+	return rc;
+}
+
+static int
+tlsm_init_tokens( tlsm_ctx *ctx )
+{
+	PK11SlotList *slotList;
+	PK11SlotListElement *listEntry;
+	int rc = 0;
+
+	slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL );
+
+	for ( listEntry = PK11_GetFirstSafe( slotList ); !rc && listEntry;
+		  listEntry = listEntry->next) {
+		PK11SlotInfo *slot = listEntry->slot;
+		rc = tlsm_authenticate_to_slot( ctx, slot );
+		PK11_FreeSlot(slot);
+	}
+
+	return rc;
+}
+
+static int
+tlsm_init_pem_module( void )
+{
+	int rc = 0;
+	char *fullname = NULL;
+	char *configstring = NULL;
+
+	/* get the system dependent library name */
+	fullname = PR_GetLibraryName( NULL, pem_library );
+	/* Load our PKCS#11 module */
+	configstring = PR_smprintf( "library=%s name=PEM parameters=\"\"", fullname );
+	PR_smprintf_free( fullname );
+
+	pemMod = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE );
+	PR_smprintf_free( configstring );
+
+	if ( !pemMod || !pemMod->loaded ) {
+		if ( pemMod ) {
+			SECMOD_DestroyModule( pemMod );
+			pemMod = NULL;
+		}
+		rc = -1;
+	}
+
+	return rc;
+}
+
+static int
+tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
+{
+	CK_SLOT_ID slotID;
+	PK11SlotInfo *slot = NULL;
+	PK11GenericObject *rv;
+	CK_ATTRIBUTE *attrs;
+	CK_ATTRIBUTE theTemplate[20];
+	CK_BBOOL cktrue = CK_TRUE;
+	CK_BBOOL ckfalse = CK_FALSE;
+	CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+	char tmpslotname[64];
+	char *slotname = NULL;
+	const char *ptr = NULL;
+	char sep = PR_GetDirectorySeparator();
+
+	attrs = theTemplate;
+
+	if ( isca ) {
+		slotID = 0; /* CA and trust objects use slot 0 */
+		PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
+		slotname = tmpslotname;
+	} else {
+		if ( ctx->tc_slotname == NULL ) { /* need new slot */
+			slotID = ++tlsm_slot_count;
+			ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
+		}
+		slotname = ctx->tc_slotname;
+
+		if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
+			PL_strfree( ctx->tc_certname );
+			++ptr;
+			ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
+		}
+	}
+
+	slot = PK11_FindSlotByName( slotname );
+
+	if ( !slot ) {
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not find the slot for certificate %s - error %d:%s.\n",
+			   ctx->tc_certname, errcode,
+			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		return -1;
+	}
+
+	PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
+	PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+	PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
+	if ( isca ) {
+		PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+	} else {
+		PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	}
+	/* This loads the certificate in our PEM module into the appropriate
+	 * slot.
+	 */
+	rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
+
+	PK11_FreeSlot( slot );
+
+	if ( !rv ) {
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not add the certificate %s - error %d:%s.\n",
+			   ctx->tc_certname, errcode,
+			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
+{
+	CK_SLOT_ID slotID;
+	PK11SlotInfo * slot = NULL;
+	PK11GenericObject *rv;
+	CK_ATTRIBUTE *attrs;
+	CK_ATTRIBUTE theTemplate[20];
+	CK_BBOOL cktrue = CK_TRUE;
+	CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
+	int retcode = 0;
+
+	attrs = theTemplate;
+
+	if ( ctx->tc_slotname == NULL ) { /* need new slot */
+		slotID = ++tlsm_slot_count;
+		ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
+	}
+	slot = PK11_FindSlotByName( ctx->tc_slotname );
+
+	if ( !slot ) {
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not find the slot %s for the private key - error %d:%s.\n",
+			   ctx->tc_slotname, errcode,
+			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		return -1;
+	}
+
+	PK11_SETATTRS( attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
+	PK11_SETATTRS( attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+	PK11_SETATTRS( attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 ); attrs++;
+	rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
+
+	if ( !rv ) {
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not add the certificate %s - error %d:%s.\n",
+			   ctx->tc_certname, errcode,
+			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		retcode = -1;
+	} else {
+		/* When adding an encrypted key the PKCS#11 will be set as removed */
+		/* This will force the token to be seen as re-inserted */
+		SECMOD_WaitForAnyTokenEvent( pemMod, 0, 0 );
+		PK11_IsPresent( slot );
+		retcode = 0;
+	}
+
+	PK11_FreeSlot( slot );
+
+	return retcode;
+}
+
+static int
+tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir )
+{
+	PRBool isca = PR_TRUE;
+
+	if ( cacertfile ) {
+		int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
+		if ( rc ) {
+			return rc;
+		}
+	}
+
+	if ( cacertdir ) {
+		PRFileInfo fi;
+		PRStatus status;
+		PRDir *dir;
+		PRDirEntry *entry;
+
+		memset( &fi, 0, sizeof(fi) );
+		status = PR_GetFileInfo( cacertdir, &fi );
+		if ( PR_SUCCESS != status) {
+			PRErrorCode errcode = PR_GetError();
+			Debug( LDAP_DEBUG_ANY,
+				   "TLS: could not get info about the CA certificate directory %s - error %d:%s.\n",
+				   cacertdir, errcode,
+				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			return -1;
+		}
+
+		if ( fi.type != PR_FILE_DIRECTORY ) {
+			Debug( LDAP_DEBUG_ANY,
+				   "TLS: error: the CA certificate directory %s is not a directory.\n",
+				   cacertdir, 0 ,0 );
+			return -1;
+		}
+
+		dir = PR_OpenDir( cacertdir );
+		if ( NULL == dir ) {
+			PRErrorCode errcode = PR_GetError();
+			Debug( LDAP_DEBUG_ANY,
+				   "TLS: could not open the CA certificate directory %s - error %d:%s.\n",
+				   cacertdir, errcode,
+				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			return -1;
+		}
+
+		status = -1;
+		do {
+			entry = PR_ReadDir( dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN );
+			if ( NULL != entry ) {
+				char *fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
+				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
+					status = 0; /* found at least 1 valid CA file in the dir */
+				}
+				PR_smprintf_free( fullpath );
+			}
+		} while ( NULL != entry );
+		PR_CloseDir( dir );
+
+		if ( status ) {
+			PRErrorCode errcode = PR_GetError();
+			Debug( LDAP_DEBUG_ANY,
+				   "TLS: did not find any valid CA certificate files in the CA certificate directory %s - error %d:%s.\n",
+				   cacertdir, errcode,
+				   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This is the part of the init we defer until we get the
+ * actual security configuration information.  This is
+ * only called once, protected by a PRCallOnce
+ * NOTE: This must be done before the first call to SSL_ImportFD,
+ * especially the setting of the policy
+ * NOTE: This must be called after fork()
+ */
+static int
+tlsm_deferred_init( void *arg )
+{
+	tlsm_ctx *ctx = (tlsm_ctx *)arg;
+	struct ldaptls *lt = ctx->tc_config;
+	const char *securitydirs[3];
+	int ii;
+	int nn;
+	PRErrorCode errcode = 1;
+
+	/* NSS support for multi-init is coming */
+#ifndef NSS_MULTI_INIT
+	if ( !NSS_IsInitialized() ) {
+#endif /* NSS_MULTI_INIT */
+		/*
+		  MOZNSS_DIR will override everything else - you can
+		  always set MOZNSS_DIR to force the use of this
+		  directory
+		  If using MOZNSS, specify the location of the moznss db dir
+		  in the cacertdir directive of the OpenLDAP configuration.
+		  DEFAULT_MOZNSS_DIR will only be used if the code cannot
+		  find a security dir to use based on the current
+		  settings
+		*/
+		nn = 0;
+		securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" );
+		securitydirs[nn++] = lt->lt_cacertdir;
+		securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" );
+		for (ii = 0; ii < nn; ++ii) {
+			const char *securitydir = securitydirs[ii];
+			if ( NULL == securitydir ) {
+				continue;
+			}
+			if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) {
+				errcode = PORT_GetError();
+				Debug( LDAP_DEBUG_TRACE,
+					   "TLS: could not initialize moznss using security dir %s - error %d:%s.\n",
+					   securitydir, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			} else {
+				/* success */
+				Debug( LDAP_DEBUG_TRACE, "TLS: using moznss security dir %s.\n",
+					   securitydir, 0, 0 );
+				errcode = 0;
+				break;
+			}
+		}
+
+		if ( errcode ) { /* no moznss db found, or not using moznss db */
+			if ( NSS_NoDB_Init( NULL ) ) {
+				errcode = PORT_GetError();
+				Debug( LDAP_DEBUG_ANY,
+					   "TLS: could not initialize moznss - error %d:%s.\n",
+					   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
+				return -1;
+			}
+
+			/* initialize the PEM module */
+			if ( tlsm_init_pem_module() ) {
+				errcode = PORT_GetError();
+				Debug( LDAP_DEBUG_ANY,
+					   "TLS: could not initialize moznss PEM module - error %d:%s.\n",
+					   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
+				return -1;
+			}
+
+			if ( tlsm_init_ca_certs( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) {
+				return -1;
+			}
+
+			ctx->tc_using_pem = PR_TRUE;
+		}
+
+		NSS_SetDomesticPolicy();
+
+		PK11_SetPasswordFunc( tlsm_pin_prompt );
+
+		if ( tlsm_init_tokens( ctx ) ) {
+			return -1;
+		}
+
+		tlsm_did_init = 1; /* we did the init - we should also clean up */
+#ifndef NSS_MULTI_INIT
+	}
+#endif /* NSS_MULTI_INIT */
+
+	return 0;
+}
+
+static int
 tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
 {
 	const char *colon = NULL;
@@ -980,8 +1269,6 @@
 		return 0;
 	}
 
-	PK11_SetPasswordFunc( tlsm_pin_prompt );
-
 	if ( ( colon = PL_strchr( certname, ':' ) ) ) {
 		token_name = PL_strndup( certname, colon-certname );
 	}
@@ -1001,23 +1288,8 @@
 		goto done;
 	}
 
-	if ( pininfo ) {
-		PL_strfree( ctx->tc_pin_file );
-		ctx->tc_pin_file = PL_strdup( pininfo );
-	}
+	rc = tlsm_authenticate_to_slot( ctx, slot );
 
-	if ( PK11_NeedLogin( slot ) &&
-		 ( SECSuccess != PK11_Authenticate( slot, PR_FALSE, ctx ) ) ) {
-		PRErrorCode errcode = PR_GetError();
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not authenticate to the security token %s - error %d:%s.\n",
-			   token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
-		goto done;
-	} else {
-		rc = 0; /* success */
-	}
-
 done:
 	PL_strfree( token_name );
 	if ( slot ) {
@@ -1064,7 +1336,14 @@
 		isServer = !isServer; /* verify the peer's cert instead */
 	}
 
-	key = PK11_FindKeyByAnyCert( cert, pin_arg );
+	if ( ctx->tc_slotname ) {
+		PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
+		key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
+		PK11_FreeSlot( slot );
+	} else {
+		key = PK11_FindKeyByAnyCert( cert, pin_arg );
+	}
+
 	if (key) {
 		SECCertificateUsage certUsage;
 		PRBool checkSig = PR_TRUE;
@@ -1170,6 +1449,11 @@
 static void
 tlsm_destroy( void )
 {
+	if (pemMod) {
+		SECMOD_DestroyModule(pemMod);
+		pemMod = NULL;
+	}
+
 	/* Only if we did the actual initialization */
 	if ( tlsm_did_init ) {
 		tlsm_did_init = 0;
@@ -1200,9 +1484,9 @@
 		ctx->tc_model = NULL;
 		memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
 		ctx->tc_require_cert = lo->ldo_tls_require_cert;
-	} else {
-		LDAP_FREE( ctx );
-		ctx = NULL;
+		ctx->tc_verify_cert = PR_FALSE;
+		ctx->tc_using_pem = PR_FALSE;
+		ctx->tc_slotname = NULL;
 	}
 	return (tls_ctx *)ctx;
 }
@@ -1237,12 +1521,14 @@
 #endif
 	if ( refcount )
 		return;
-	PR_Close( c->tc_model );
+	if ( c->tc_model )
+		PR_Close( c->tc_model );
 	c->tc_certdb = NULL; /* if not the default, may have to clean up */
 	PL_strfree( c->tc_certname );
 	c->tc_certname = NULL;
 	PL_strfree( c->tc_pin_file );
 	c->tc_pin_file = NULL;
+	PL_strfree( c->tc_slotname );
 #ifdef LDAP_R_COMPILE
 	ldap_pvt_thread_mutex_destroy( &c->tc_refmutex );
 #endif
@@ -1366,7 +1652,8 @@
 		     ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
 			require_cert = SSL_REQUIRE_ALWAYS;
 		}
-		ctx->tc_verify_cert = PR_TRUE;
+		if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
+			ctx->tc_verify_cert = PR_TRUE;
 	} else {
 		ctx->tc_verify_cert = PR_FALSE;
 	}
@@ -1385,6 +1672,37 @@
 		return -1;
 	}
 
+	/* set up our cert and key, if any */
+	if ( lt->lt_certfile ) {
+		/* if using the PEM module, load the PEM file specified by lt_certfile */
+		/* otherwise, assume this is the name of a cert already in the db */
+		if ( ctx->tc_using_pem ) {
+			/* this sets ctx->tc_certname to the correct value */
+			int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE /* not a ca */ );
+			if ( rc ) {
+				return rc;
+			}
+		} else {
+			PL_strfree( ctx->tc_certname );
+			ctx->tc_certname = PL_strdup( lt->lt_certfile );
+		}
+	}
+
+	if ( lt->lt_keyfile ) {
+		/* if using the PEM module, load the PEM file specified by lt_keyfile */
+		/* otherwise, assume this is the pininfo for the key */
+		if ( ctx->tc_using_pem ) {
+			/* this sets ctx->tc_certname to the correct value */
+			int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
+			if ( rc ) {
+				return rc;
+			}
+		} else {
+			PL_strfree( ctx->tc_pin_file );
+			ctx->tc_pin_file = PL_strdup( lt->lt_keyfile );
+		}
+	}
+
 	/* Set up callbacks for use by clients */
 	if ( !ctx->tc_is_server ) {
 		if ( SSL_OptionSet( ctx->tc_model, SSL_NO_CACHE, PR_TRUE ) != SECSuccess ) {
@@ -1403,21 +1721,20 @@
 			return -1;
 		}
 
-		/* we don't currently support import of cert/key pair - assume the certfile
-		   is really the name of a cert/key in the database in the form of
-		   tokenname:certname - also assume since this is specified, the caller
-		   wants to attempt client cert auth */
-		if ( lt->lt_certfile ) {
-			if ( tlsm_authenticate( ctx, lt->lt_certfile, lt->lt_keyfile ) ) {
+		/* 
+		   since a cert has been specified, assume the client wants to do cert auth
+		*/
+		if ( ctx->tc_certname ) {
+			if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
 				Debug( LDAP_DEBUG_ANY, 
 				       "TLS: error: unable to authenticate to the security device for certificate %s\n",
-				       lt->lt_certfile, 0, 0 );
+				       ctx->tc_certname, 0, 0 );
 				return -1;
 			}
-			if ( tlsm_clientauth_init( ctx, lt->lt_certfile ) ) {
+			if ( tlsm_clientauth_init( ctx, ctx->tc_certname ) ) {
 				Debug( LDAP_DEBUG_ANY, 
 				       "TLS: error: unable to set up client certificate authentication using %s\n",
-				       lt->lt_certfile, 0, 0 );
+				       ctx->tc_certname, 0, 0 );
 				return -1;
 			}
 		}
@@ -1428,7 +1745,7 @@
 		SECStatus status;
 
 		/* must have a certificate for the server to use */
-		if ( !lt->lt_certfile ) {
+		if ( !ctx->tc_certname ) {
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: no server certificate: must specify a certificate for the server to use\n",
 			       0, 0, 0 );
@@ -1437,19 +1754,19 @@
 
 		/* authenticate to the server's token - this will do nothing
 		   if the key/cert db is not password protected */
-		if ( tlsm_authenticate( ctx, lt->lt_certfile, lt->lt_keyfile ) ) {
+		if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: unable to authenticate to the security device for certificate %s\n",
-			       lt->lt_certfile, 0, 0 );
+			       ctx->tc_certname, 0, 0 );
 			return -1;
 		}
 
 		/* get the server's key and cert */
-		if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, lt->lt_certfile, ctx->tc_is_server,
+		if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
 						    &serverCert, &serverKey ) ) {
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
-			       lt->lt_certfile, 0, 0 );
+			       ctx->tc_certname, 0, 0 );
 			return -1;
 		}
 
@@ -1464,7 +1781,7 @@
 			PRErrorCode err = PR_GetError();
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
-			       lt->lt_certfile, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
+			       ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
 			return -1;
 		}
 	}
@@ -1663,7 +1980,6 @@
 	int rc;
 	PRErrorCode err;
 
-	/* By default, NSS checks the cert hostname for us */
 	rc = SSL_ResetHandshake( s, PR_FALSE /* server */ );
 	if (rc) {
 		err = PR_GetError();
@@ -1673,15 +1989,6 @@
 			   err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
 	}
 
-	rc = SSL_SetURL( s, ld->ld_options.ldo_defludp->lud_host );
-	if (rc) {
-		err = PR_GetError();
-		Debug( LDAP_DEBUG_TRACE, 
-			   "TLS: error: connect - seturl failure %d - error %d:%s\n",
-			   rc, err,
-			   err ? PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) : "unknown" );
-	}
-
 	rc = SSL_ForceHandshake( s );
 	if (rc) {
 		err = PR_GetError();
@@ -1754,11 +2061,179 @@
 	return 0;
 }
 
+/* what kind of hostname were we given? */
+#define	IS_DNS	0
+#define	IS_IP4	1
+#define	IS_IP6	2
+
 static int
 tlsm_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
 {
-/* NSS already does a hostname check */
-	return LDAP_SUCCESS;
+	tlsm_session *s = (tlsm_session *)session;
+	CERTCertificate *cert;
+	const char *name, *domain = NULL, *ptr;
+	int i, ret, ntype = IS_DNS, nlen, dlen;
+#ifdef LDAP_PF_INET6
+	struct in6_addr addr;
+#else
+	struct in_addr addr;
+#endif
+	SECItem altname;
+	SECStatus rv;
+
+	if( ldap_int_hostname &&
+		( !name_in || !strcasecmp( name_in, "localhost" ) ) )
+	{
+		name = ldap_int_hostname;
+	} else {
+		name = name_in;
+	}
+	nlen = strlen( name );
+
+	cert = SSL_PeerCertificate( s );
+	if (!cert) {
+		Debug( LDAP_DEBUG_ANY,
+			"TLS: unable to get peer certificate.\n",
+			0, 0, 0 );
+		/* if this was a fatal condition, things would have
+		 * aborted long before now.
+		 */
+		return LDAP_SUCCESS;
+	}
+
+#ifdef LDAP_PF_INET6
+	if (name[0] == '[' && strchr(name, ']')) {
+		char *n2 = ldap_strdup(name+1);
+		*strchr(n2, ']') = 0;
+		if (inet_pton(AF_INET6, n2, &addr))
+			ntype = IS_IP6;
+		LDAP_FREE(n2);
+	} else 
+#endif
+	if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
+		if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
+	}
+	if (ntype == IS_DNS ) {
+		domain = strchr( name, '.' );
+		if ( domain )
+			dlen = nlen - ( domain - name );
+	}
+
+	ret = LDAP_LOCAL_ERROR;
+
+	rv = CERT_FindCertExtension( cert, SEC_OID_X509_SUBJECT_ALT_NAME,
+		&altname );
+	if ( rv == SECSuccess && altname.data ) {
+		PRArenaPool *arena;
+		CERTGeneralName *names, *cur;
+
+		arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+		if ( !arena ) {
+			ret = LDAP_NO_MEMORY;
+			goto fail;
+		}
+
+		names = cur = CERT_DecodeAltNameExtension(arena, &altname);
+		if ( !cur )
+			goto altfail;
+
+		do {
+			char *host;
+			int hlen;
+
+			/* ignore empty */
+			if ( !cur->name.other.len ) continue;
+
+			host = cur->name.other.data;
+			hlen = cur->name.other.len;
+
+			if ( cur->type == certDNSName ) {
+				if ( ntype != IS_DNS )	continue;
+
+				/* is this an exact match? */
+				if ( nlen == hlen && !strncasecmp( name, host, nlen )) {
+					ret = LDAP_SUCCESS;
+					break;
+				}
+
+				/* is this a wildcard match? */
+				if ( domain && host[0] == '*' && host[1] == '.' &&
+					dlen == hlen-1 && !strncasecmp( domain, host+1, dlen )) {
+					ret = LDAP_SUCCESS;
+					break;
+				}
+			} else if ( cur->type == certIPAddress ) {
+				if ( ntype == IS_DNS )	continue;
+				
+#ifdef LDAP_PF_INET6
+				if (ntype == IS_IP6 && hlen != sizeof(struct in6_addr)) {
+					continue;
+				} else
+#endif
+				if (ntype == IS_IP4 && hlen != sizeof(struct in_addr)) {
+					continue;
+				}
+				if (!memcmp(host, &addr, hlen)) {
+					ret = LDAP_SUCCESS;
+					break;
+				}
+			}
+		} while (( cur = CERT_GetNextGeneralName( cur )) != names );
+altfail:
+		PORT_FreeArena( arena, PR_FALSE );
+		SECITEM_FreeItem( &altname, PR_FALSE );
+	}
+	/* no altnames matched, try the CN */
+	if ( ret != LDAP_SUCCESS ) {
+		/* find the last CN */
+		CERTRDN *rdn, **rdns;
+		CERTAVA *lastava = NULL;
+		char buf[2048];
+
+		buf[0] = '\0';
+		rdns = cert->subject.rdns;
+		while ( rdns && ( rdn = *rdns++ )) {
+			CERTAVA *ava, **avas = rdn->avas;
+			while ( avas && ( ava = *avas++ )) {
+				if ( CERT_GetAVATag( ava ) == SEC_OID_AVA_COMMON_NAME )
+					lastava = ava;
+			}
+		}
+		if ( lastava ) {
+			SECItem *av = CERT_DecodeAVAValue( &lastava->value );
+			if ( av ) {
+				if ( av->len == nlen && !strncasecmp( name, av->data, nlen )) {
+					ret = LDAP_SUCCESS;
+				} else if ( av->data[0] == '*' && av->data[1] == '.' &&
+					domain && dlen == av->len - 1 && !strncasecmp( name,
+						av->data+1, dlen )) {
+					ret = LDAP_SUCCESS;
+				} else {
+					int len = av->len;
+					if ( len >= sizeof(buf) )
+						len = sizeof(buf)-1;
+					memcpy( buf, av->data, len );
+					buf[len] = '\0';
+				}
+				SECITEM_FreeItem( av, PR_TRUE );
+			}
+		}
+		if ( ret != LDAP_SUCCESS ) {
+			Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
+				"common name in certificate (%s).\n", 
+				name, buf, 0 );
+			ret = LDAP_CONNECT_ERROR;
+			if ( ld->ld_error ) {
+				LDAP_FREE( ld->ld_error );
+			}
+			ld->ld_error = LDAP_STRDUP(
+				_("TLS: hostname does not match CN in peer certificate"));
+		}
+	}
+
+fail:
+	CERT_DestroyCertificate( cert );
+	return ret;
 }
 
 static int
@@ -2005,6 +2480,7 @@
 
 /*
  * Initialize TLS subsystem. Should be called only once.
+ * See tlsm_deferred_init for the bulk of the init process
  */
 static int
 tlsm_init( void )
@@ -2013,7 +2489,6 @@
 
 	tlsm_layer_id = PR_GetUniqueIdentity( "OpenLDAP" );
 
-	/* see deferred init */
 	return 0;
 }
 
@@ -2190,3 +2665,10 @@
 };
 
 #endif /* HAVE_MOZNSS */
+/*
+  emacs settings
+  Local Variables:
+  indent-tabs-mode: t
+  tab-width: 4
+  End:
+*/

Modified: openldap/trunk/libraries/libldap/tls_o.c
===================================================================
--- openldap/trunk/libraries/libldap/tls_o.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/tls_o.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
-/* tls_o.c - Handle tls/ssl using SSLeay or OpenSSL */
-/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_o.c,v 1.5.2.4 2009/07/01 23:04:49 quanah Exp $ */
+/* tls_o.c - Handle tls/ssl using OpenSSL */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_o.c,v 1.5.2.7 2009/08/25 22:58:08 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
@@ -466,7 +466,7 @@
 	X509 *x;
 	const char *name;
 	char *ptr;
-	int ntype = IS_DNS;
+	int ntype = IS_DNS, nlen;
 #ifdef LDAP_PF_INET6
 	struct in6_addr addr;
 #else
@@ -480,6 +480,7 @@
 	} else {
 		name = name_in;
 	}
+	nlen = strlen(name);
 
 	x = tlso_get_cert(s);
 	if (!x) {
@@ -513,15 +514,14 @@
 		ex = X509_get_ext(x, i);
 		alt = X509V3_EXT_d2i(ex);
 		if (alt) {
-			int n, len1 = 0, len2 = 0;
+			int n, len2 = 0;
 			char *domain = NULL;
 			GENERAL_NAME *gn;
 
 			if (ntype == IS_DNS) {
-				len1 = strlen(name);
 				domain = strchr(name, '.');
 				if (domain) {
-					len2 = len1 - (domain-name);
+					len2 = nlen - (domain-name);
 				}
 			}
 			n = sk_GENERAL_NAME_num(alt);
@@ -539,7 +539,7 @@
 					if (sl == 0) continue;
 
 					/* Is this an exact match? */
-					if ((len1 == sl) && !strncasecmp(name, sn, len1)) {
+					if ((nlen == sl) && !strncasecmp(name, sn, nlen)) {
 						break;
 					}
 
@@ -579,13 +579,28 @@
 
 	if (ret != LDAP_SUCCESS) {
 		X509_NAME *xn;
-		char buf[2048];
-		buf[0] = '\0';
+		X509_NAME_ENTRY *ne;
+		ASN1_OBJECT *obj;
+		ASN1_STRING *cn = NULL;
+		int navas;
 
+		/* find the last CN */
+		obj = OBJ_nid2obj( NID_commonName );
+		if ( !obj ) goto no_cn;	/* should never happen */
+
 		xn = X509_get_subject_name(x);
-		if( X509_NAME_get_text_by_NID( xn, NID_commonName,
-			buf, sizeof(buf)) == -1)
+		navas = X509_NAME_entry_count( xn );
+		for ( i=navas-1; i>=0; i-- ) {
+			ne = X509_NAME_get_entry( xn, i );
+			if ( !OBJ_cmp( ne->object, obj )) {
+				cn = X509_NAME_ENTRY_get_data( ne );
+				break;
+			}
+		}
+
+		if( !cn )
 		{
+no_cn:
 			Debug( LDAP_DEBUG_ANY,
 				"TLS: unable to get common name from peer certificate.\n",
 				0, 0, 0 );
@@ -596,21 +611,20 @@
 			ld->ld_error = LDAP_STRDUP(
 				_("TLS: unable to get CN from peer certificate"));
 
-		} else if (strcasecmp(name, buf) == 0 ) {
+		} else if ( cn->length == nlen &&
+			strncasecmp( name, (char *) cn->data, nlen ) == 0 ) {
 			ret = LDAP_SUCCESS;
 
-		} else if (( buf[0] == '*' ) && ( buf[1] == '.' )) {
+		} else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) {
 			char *domain = strchr(name, '.');
 			if( domain ) {
-				size_t dlen = 0;
-				size_t sl;
+				int dlen;
 
-				sl = strlen(name);
-				dlen = sl - (domain-name);
-				sl = strlen(buf);
+				dlen = nlen - (domain-name);
 
 				/* Is this a wildcard match? */
-				if ((dlen == sl-1) && !strncasecmp(domain, &buf[1], dlen)) {
+				if ((dlen == cn->length-1) &&
+					!strncasecmp(domain, (char *) &cn->data[1], dlen)) {
 					ret = LDAP_SUCCESS;
 				}
 			}
@@ -618,8 +632,8 @@
 
 		if( ret == LDAP_LOCAL_ERROR ) {
 			Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
-				"common name in certificate (%s).\n", 
-				name, buf, 0 );
+				"common name in certificate (%.*s).\n", 
+				name, cn->length, cn->data );
 			ret = LDAP_CONNECT_ERROR;
 			if ( ld->ld_error ) {
 				LDAP_FREE( ld->ld_error );

Modified: openldap/trunk/libraries/libldap/utf-8-conv.c
===================================================================
--- openldap/trunk/libraries/libldap/utf-8-conv.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap/utf-8-conv.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/libldap/utf-8-conv.c,v 1.16.2.4 2009/01/22 00:00:56 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap/utf-8-conv.c,v 1.16.2.5 2009/08/25 22:58:08 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -191,7 +191,10 @@
 			return 4;
 		if( wchar < 0x4000000 ) 
 			return 5;
-		if( wchar < 0x80000000 )
+#if SIZEOF_WCHAR_T > 4
+		/* UL is not strictly needed by ANSI C */
+		if( wchar < (wchar_t)0x80000000UL )
+#endif /* SIZEOF_WCHAR_T > 4 */
 			return 6;
 		return -1;
 	}
@@ -235,7 +238,12 @@
 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
 		}
 
-	} else if( wchar < 0x80000000 ) {
+	} else
+#if SIZEOF_WCHAR_T > 4
+		/* UL is not strictly needed by ANSI C */
+		if( wchar < (wchar_t)0x80000000UL )
+#endif /* SIZEOF_WCHAR_T > 4 */
+	{
 		if (count >= 6) {
 			utf8char[len++] = 0xfc | ( wchar >> 30 );
 			utf8char[len++] = 0x80 | ( (wchar >> 24) & 0x3f );
@@ -245,8 +253,11 @@
 			utf8char[len++] = 0x80 | ( wchar & 0x3f );
 		}
 
-	} else
+#if SIZEOF_WCHAR_T > 4
+	} else {
 		len = -1;
+#endif /* SIZEOF_WCHAR_T > 4 */
+	}
 	
 	return len;
 
@@ -467,4 +478,4 @@
 	return n;	
 }
 
-#endif
+#endif /* SIZEOF_WCHAR_T >= 4 */

Modified: openldap/trunk/libraries/libldap_r/thr_debug.c
===================================================================
--- openldap/trunk/libraries/libldap_r/thr_debug.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/libldap_r/thr_debug.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
-/* $OpenLDAP: pkg/ldap/libraries/libldap_r/thr_debug.c,v 1.5.2.7 2009/01/22 00:00:56 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/libldap_r/thr_debug.c,v 1.5.2.8 2009/08/02 22:07:31 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2005-2009 The OpenLDAP Foundation.
@@ -555,18 +555,21 @@
 	int detached )
 {
 	ldap_debug_thread_t *t;
+
 	if( thread_info_used >= thread_info_size ) {
 		unsigned int more = thread_info_size + 8;
 		unsigned int new_size = thread_info_size + more;
+
 		t = calloc( more, sizeof(ldap_debug_thread_t) );
 		assert( t != NULL );
 		thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
 		assert( thread_info != NULL );
-		while( thread_info_size < new_size ) {
+		do {
 			t->idx = thread_info_size;
 			thread_info[thread_info_size++] = t++;
-		}
+		} while( thread_info_size < new_size );
 	}
+
 	t = thread_info[thread_info_used];
 	init_usage( &t->usage, msg );
 	t->wrapped = *thread;
@@ -779,6 +782,7 @@
 	if( !options_done )
 		get_options();
 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
+
 	if( wrap_threads ) {
 		ldap_debug_thread_call_t *call = malloc(
 			sizeof( ldap_debug_thread_call_t ) );
@@ -843,6 +847,7 @@
 				remove_thread_info( t, "ldap_pvt_thread_join" ) );
 		adjust_count( Idx_unjoined_thread, -1 );
 	}
+
 	return rc;
 }
 

Modified: openldap/trunk/libraries/liblutil/getpass.c
===================================================================
--- openldap/trunk/libraries/liblutil/getpass.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblutil/getpass.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* getpass.c -- get password from user */
-/* $OpenLDAP: pkg/ldap/libraries/liblutil/getpass.c,v 1.17.2.4 2009/01/22 00:00:58 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblutil/getpass.c,v 1.17.2.6 2009/08/25 23:09:33 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -26,7 +26,7 @@
  */
 /* This work was originally developed by the University of Michigan
  * and distributed as part of U-MICH LDAP.  It was adapted for use in
- * -llutil by Kurt D. Zeilenga.
+ * -llutil by Kurt D. Zeilenga and subsequently rewritten by Howard Chu.
  */
 
 #include "portable.h"
@@ -42,7 +42,7 @@
 #include <ac/time.h>
 #include <ac/unistd.h>
 
-#ifdef NEED_GETPASSPHRASE
+#ifndef HAVE_GETPASSPHRASE
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
@@ -57,38 +57,26 @@
 
 #include "ldap_defaults.h"
 
-char *
-lutil_getpass( const char *prompt )
-{
-#if !defined(HAVE_TERMIOS_H) && !defined(HAVE_SGTTY_H)
-	static char buf[256];
-	int i, c;
+#define PBUF	512
 
-	if( prompt == NULL ) prompt = _("Password: ");
-
-#ifdef DEBUG
-	if (debug & D_TRACE)
-		printf("->getpass(%s)\n", prompt);
+#ifdef HAVE_WINSOCK
+#define TTY "con:"
+#else
+#define TTY "/dev/tty"
 #endif
 
-	printf("%s", prompt);
-	i = 0;
-	while ( (c = getch()) != EOF && c != '\n' && c != '\r' )
-		buf[i++] = c;
-	if ( c == EOF )
-		return( NULL );
-	buf[i] = '\0';
-	return (buf);
-#else
-	int no_pass = 0;
-	char i, j, k;
+char *
+lutil_getpass( const char *prompt )
+{
+	static char pbuf[PBUF];
+	FILE *fi;
+	int c;
+	unsigned i;
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
 	TERMIO_TYPE ttyb;
 	TERMFLAG_TYPE flags;
-	static char pbuf[513];
-	register char *p;
-	register int c;
-	FILE *fi;
 	RETSIGTYPE (*sig)( int sig );
+#endif
 
 	if( prompt == NULL ) prompt = _("Password: ");
 
@@ -96,82 +84,46 @@
 	if (debug & D_TRACE)
 		printf("->getpass(%s)\n", prompt);
 #endif
-	/*
-	 *  Stolen from the getpass() routine.  Can't use the plain
-	 *  getpass() for two reasons.  One is that LDAP passwords
-	 *  can be really, really long - much longer than 8 chars.
-	 *  The second is that we like to make this client available
-	 *  out of inetd via a Merit asynch port, and we need to be
-	 *  able to do telnet control codes to turn on and off line
-	 *  blanking.
-	 */
-	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
+
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
+	if ((fi = fopen(TTY, "r")) == NULL)
 		fi = stdin;
 	else
 		setbuf(fi, (char *)NULL);
-	sig = SIGNAL (SIGINT, SIG_IGN);
 	if (fi != stdin) {
 		if (GETATTR(fileno(fi), &ttyb) < 0)
 			perror("GETATTR");
-	}
-	flags = GETFLAGS( ttyb );
-	SETFLAGS( ttyb, flags & ~ECHO );
-	if (fi != stdin) {
+		sig = SIGNAL (SIGINT, SIG_IGN);
+		flags = GETFLAGS( ttyb );
+		SETFLAGS( ttyb, flags & ~ECHO );
 		if (SETATTR(fileno(fi), &ttyb) < 0)
 			perror("SETATTR");
 	}
-
-	/*  blank the line if through Merit */
-	if (fi == stdin) {
-		printf("%c%c%c", 255, 251, 1);
-		fflush(stdout);
-		(void) scanf("%c%c%c", &i, &j, &k);
-		fflush(stdin);
-	}
-
-	/* fetch the password */
+#else
+	fi = stdin;
+#endif
 	fprintf(stdout, "%s", prompt); 
 	fflush(stdout);
-	for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
-		if (c == '\r')
-			break;
-		if (p < &pbuf[512])
-			*p++ = c;
-	}
-	if (c == EOF)
-		no_pass = 1;
-	else {
-		*p = '\0';
-		if (*(p - 1) == '\r')
-			*(p - 1) = '\0';
-	}
-
-	/*  unblank the line if through Merit */
-	if (fi == stdin) {
-		printf("%c%c%c", 255, 252, 1);
-		fflush(stdout);
-		(void) scanf("%c%c%c", &i, &j, &k);
-		fflush(stdin);
-		printf("\n"); fflush(stdout);
-	}
-	fprintf(stdout, "\n"); 
-	fflush(stdout);
-
+	i = 0;
+	while ( (c = getc(fi)) != EOF && c != '\n' && c != '\r' )
+		if ( i < (sizeof(pbuf)-1) )
+			pbuf[i++] = c;
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_SGTTY_H)
 	/* tidy up */
-	SETFLAGS( ttyb, flags );
 	if (fi != stdin) {
+		fprintf(stdout, "\n"); 
+		fflush(stdout);
+		SETFLAGS( ttyb, flags );
 		if (SETATTR(fileno(fi), &ttyb) < 0)
 			perror("SETATTR");
-	}
-	(void) SIGNAL (SIGINT, sig);
-	if (fi != stdin)
+		(void) SIGNAL (SIGINT, sig);
 		(void) fclose(fi);
-	else
-		i = getchar();
-	if (no_pass)
-		return(NULL);
-	return(pbuf);
+	}
 #endif
+	if ( c == EOF )
+		return( NULL );
+	pbuf[i] = '\0';
+	return (pbuf);
 }
 
 #endif /* !NEED_GETPASSPHRASE */

Modified: openldap/trunk/libraries/liblutil/passwd.c
===================================================================
--- openldap/trunk/libraries/liblutil/passwd.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/libraries/liblutil/passwd.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/libraries/liblutil/passwd.c,v 1.104.2.8 2009/07/06 19:31:49 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/libraries/liblutil/passwd.c,v 1.104.2.9 2009/08/30 22:55:47 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -45,7 +45,14 @@
 #define des_finish(key, schedule) 
 
 #elif defined(HAVE_MOZNSS)
-#	include <pk11pub.h>
+/*
+  hack hack hack
+  We need to define this here so that nspr/obsolete/protypes.h will not be included
+  if that file is included, it will create a uint32 typedef that will cause the
+  one in lutil_sha1.h to blow up
+*/
+#define PROTYPES_H 1
+#	include <nss/pk11pub.h>
 typedef PK11SymKey *des_key;
 typedef unsigned char des_data_block[8];
 typedef PK11Context *des_context[1];

Modified: openldap/trunk/servers/slapd/aclparse.c
===================================================================
--- openldap/trunk/servers/slapd/aclparse.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/aclparse.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* aclparse.c - routines to parse and check acl's */
-/* $OpenLDAP: pkg/ldap/servers/slapd/aclparse.c,v 1.198.2.10 2009/06/27 18:00:32 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/aclparse.c,v 1.198.2.11 2009/07/27 20:19:18 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -2774,7 +2774,7 @@
 		for ( an = a->acl_attrs; an && !BER_BVISNULL( &an->an_name ); an++ ) {
 			if ( ! first ) *ptr++ = ',';
 			if (an->an_oc) {
-				*ptr++ = an->an_oc_exclude ? '!' : '@';
+				*ptr++ = ( an->an_flags & SLAP_AN_OCEXCLUDE ) ? '!' : '@';
 				ptr = lutil_strcopy( ptr, an->an_oc->soc_cname.bv_val );
 
 			} else {

Modified: openldap/trunk/servers/slapd/ad.c
===================================================================
--- openldap/trunk/servers/slapd/ad.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/ad.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* ad.c - routines for dealing with attribute descriptions */
-/* $OpenLDAP: pkg/ldap/servers/slapd/ad.c,v 1.95.2.8 2009/02/17 19:14:41 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/ad.c,v 1.95.2.9 2009/07/27 20:19:18 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -594,29 +594,33 @@
 		 * else if requested description is !objectClass, return
 		 * attributes which the class does not require/allow
 		 */
-		oc = attrs->an_oc;
-		if( oc == NULL && attrs->an_name.bv_val ) {
-			switch( attrs->an_name.bv_val[0] ) {
-			case '@': /* @objectClass */
-			case '+': /* +objectClass (deprecated) */
-			case '!': { /* exclude */
-					struct berval ocname;
-					ocname.bv_len = attrs->an_name.bv_len - 1;
-					ocname.bv_val = &attrs->an_name.bv_val[1];
-					oc = oc_bvfind( &ocname );
-					attrs->an_oc_exclude = 0;
-					if ( oc && attrs->an_name.bv_val[0] == '!' ) {
-						attrs->an_oc_exclude = 1;
-					}
-				} break;
+		if ( !( attrs->an_flags & SLAP_AN_OCINITED )) {
+			if( attrs->an_name.bv_val ) {
+				switch( attrs->an_name.bv_val[0] ) {
+				case '@': /* @objectClass */
+				case '+': /* +objectClass (deprecated) */
+				case '!': { /* exclude */
+						struct berval ocname;
+						ocname.bv_len = attrs->an_name.bv_len - 1;
+						ocname.bv_val = &attrs->an_name.bv_val[1];
+						oc = oc_bvfind( &ocname );
+						if ( oc && attrs->an_name.bv_val[0] == '!' ) {
+							attrs->an_flags |= SLAP_AN_OCEXCLUDE;
+						} else {
+							attrs->an_flags &= ~SLAP_AN_OCEXCLUDE;
+						}
+					} break;
 
-			default: /* old (deprecated) way */
-				oc = oc_bvfind( &attrs->an_name );
+				default: /* old (deprecated) way */
+					oc = oc_bvfind( &attrs->an_name );
+				}
+				attrs->an_oc = oc;
 			}
-			attrs->an_oc = oc;
+			attrs->an_flags |= SLAP_AN_OCINITED;
 		}
+		oc = attrs->an_oc;
 		if( oc != NULL ) {
-			if ( attrs->an_oc_exclude ) {
+			if ( attrs->an_flags & SLAP_AN_OCEXCLUDE ) {
 				if ( oc == slap_schema.si_oc_extensibleObject ) {
 					/* extensibleObject allows the return of anything */
 					return 0;
@@ -932,7 +936,7 @@
 
 		anew->an_desc = NULL;
 		anew->an_oc = NULL;
-		anew->an_oc_exclude = 0;
+		anew->an_flags = 0;
 		ber_str2bv(s, 0, 1, &anew->an_name);
 		slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
 		if ( !anew->an_desc ) {
@@ -959,7 +963,7 @@
 					}
 
 					if ( anew->an_name.bv_val[0] == '!' ) {
-						anew->an_oc_exclude = 1;
+						anew->an_flags |= SLAP_AN_OCEXCLUDE;
 					}
 				} break;
 
@@ -971,6 +975,7 @@
 				}
 			}
 		}
+		anew->an_flags |= SLAP_AN_OCINITED;
 		anew++;
 	}
 

Modified: openldap/trunk/servers/slapd/back-bdb/back-bdb.h
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/back-bdb.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/back-bdb.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* back-bdb.h - bdb back-end header file */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/back-bdb.h,v 1.141.2.21 2009/05/08 16:37:41 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/back-bdb.h,v 1.141.2.23 2009/08/25 22:58:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -125,12 +125,12 @@
 	EntryInfo	*c_lruhead;	/* lru - add accessed entries here */
 	EntryInfo	*c_lrutail;	/* lru - rem lru entries from here */
 	EntryInfo	c_dntree;
-	unsigned	c_maxsize;
-	int		c_cursize;
-	unsigned	c_minfree;
-	unsigned	c_eimax;
-	int		c_eiused;	/* EntryInfo's in use */
-	int		c_leaves;	/* EntryInfo leaf nodes */
+	ID		c_maxsize;
+	ID		c_cursize;
+	ID		c_minfree;
+	ID		c_eimax;
+	ID		c_eiused;	/* EntryInfo's in use */
+	ID		c_leaves;	/* EntryInfo leaf nodes */
 	int		c_purging;
 	DB_TXN	*c_txn;	/* used by lru cleaner */
 	ldap_pvt_thread_rdwr_t c_rwlock;
@@ -199,13 +199,13 @@
 	struct re_s		*bi_txn_cp_task;
 	struct re_s		*bi_index_task;
 
-	int			bi_lock_detect;
+	u_int32_t		bi_lock_detect;
 	long		bi_shm_key;
 
 	ID			bi_lastid;
 	ldap_pvt_thread_mutex_t	bi_lastid_mutex;
-	unsigned	bi_idl_cache_max_size;
-	int		bi_idl_cache_size;
+	ID	bi_idl_cache_max_size;
+	ID		bi_idl_cache_size;
 	Avlnode		*bi_idl_tree;
 	bdb_idl_cache_entry_t	*bi_idl_lru_head;
 	bdb_idl_cache_entry_t	*bi_idl_lru_tail;

Modified: openldap/trunk/servers/slapd/back-bdb/cache.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/cache.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/cache.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* cache.c - routines to maintain an in-core cache of entries */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/cache.c,v 1.120.2.31 2009/06/19 21:55:57 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/cache.c,v 1.120.2.32 2009/07/27 17:38:40 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -689,8 +689,9 @@
 {
 	DB_LOCK		lock, *lockp;
 	EntryInfo *elru, *elnext = NULL;
-	int count, islocked, eimax;
-	int efree = 0, eifree = 0, eicount, ecount;
+	int islocked;
+	ID eicount, ecount;
+	ID count, efree, eifree = 0;
 #ifdef LDAP_DEBUG
 	int iter;
 #endif
@@ -698,24 +699,24 @@
 	/* Wait for the mutex; we're the only one trying to purge. */
 	ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_lru_mutex );
 
+	if ( bdb->bi_cache.c_cursize > bdb->bi_cache.c_maxsize ) {
+		efree = bdb->bi_cache.c_cursize - bdb->bi_cache.c_maxsize;
+		efree += bdb->bi_cache.c_minfree;
+	} else {
+		efree = 0;
+	}
+
 	/* maximum number of EntryInfo leaves to cache. In slapcat
 	 * we always free all leaf nodes.
 	 */
-	if ( slapMode & SLAP_TOOL_READONLY )
-		eimax = 0;
-	else
-		eimax = bdb->bi_cache.c_eimax;
 
-	efree = bdb->bi_cache.c_cursize - bdb->bi_cache.c_maxsize;
-	if ( efree < 1 )
-		efree = 0;
-	else 
-		efree += bdb->bi_cache.c_minfree;
-
-	if ( bdb->bi_cache.c_leaves > eimax ) {
+	if ( slapMode & SLAP_TOOL_READONLY ) {
+		eifree = bdb->bi_cache.c_leaves;
+	} else if ( bdb->bi_cache.c_eimax &&
+		bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
 		eifree = bdb->bi_cache.c_minfree * 10;
-		if ( eifree >= eimax )
-			eifree = eimax / 2;
+		if ( eifree >= bdb->bi_cache.c_leaves )
+			eifree /= 2;
 	}
 
 	if ( !efree && !eifree ) {
@@ -1065,7 +1066,7 @@
 		int purge = 0;
 
 		if ( bdb->bi_cache.c_cursize > bdb->bi_cache.c_maxsize ||
-			bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
+			( bdb->bi_cache.c_eimax && bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax )) {
 			ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_count_mutex );
 			if ( !bdb->bi_cache.c_purging ) {
 				if ( load && !( flag & ID_NOCACHE )) {
@@ -1074,7 +1075,7 @@
 						purge = 1;
 						bdb->bi_cache.c_purging = 1;
 					}
-				} else if ( bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
+				} else if ( bdb->bi_cache.c_eimax && bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
 					purge = 1;
 					bdb->bi_cache.c_purging = 1;
 				}

Modified: openldap/trunk/servers/slapd/back-bdb/config.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/config.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/config.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* config.c - bdb backend configuration file routine */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/config.c,v 1.91.2.16 2009/01/22 00:01:05 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/config.c,v 1.91.2.18 2009/08/25 22:58:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -61,12 +61,12 @@
 			"DESC 'Directory for database content' "
 			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-	{ "cachefree", "size", 2, 2, 0, ARG_UINT|ARG_OFFSET,
+	{ "cachefree", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
 		(void *)offsetof(struct bdb_info, bi_cache.c_minfree),
 		"( OLcfgDbAt:1.11 NAME 'olcDbCacheFree' "
 			"DESC 'Number of extra entries to free when max is reached' "
 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-	{ "cachesize", "size", 2, 2, 0, ARG_UINT|ARG_OFFSET,
+	{ "cachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
 		(void *)offsetof(struct bdb_info, bi_cache.c_maxsize),
 		"( OLcfgDbAt:1.1 NAME 'olcDbCacheSize' "
 			"DESC 'Entry cache size in entries' "
@@ -109,12 +109,12 @@
 		"( OLcfgDbAt:1.5 NAME 'olcDbDirtyRead' "
 		"DESC 'Allow reads of uncommitted data' "
 		"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
-	{ "dncachesize", "size", 2, 2, 0, ARG_UINT|ARG_OFFSET,
+	{ "dncachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
 		(void *)offsetof(struct bdb_info, bi_cache.c_eimax),
 		"( OLcfgDbAt:1.12 NAME 'olcDbDNcacheSize' "
 			"DESC 'DN cache size' "
 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-	{ "idlcachesize", "size", 2, 2, 0, ARG_UINT|ARG_OFFSET,
+	{ "idlcachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
 		(void *)offsetof(struct bdb_info, bi_idl_cache_max_size),
 		"( OLcfgDbAt:1.6 NAME 'olcDbIDLcacheSize' "
 		"DESC 'IDL cache size in IDLs' "
@@ -487,7 +487,7 @@
 			if ( bdb->bi_lock_detect != DB_LOCK_DEFAULT ) {
 				int i;
 				for (i=0; !BER_BVISNULL(&bdb_lockd[i].word); i++) {
-					if ( bdb->bi_lock_detect == bdb_lockd[i].mask ) {
+					if ( bdb->bi_lock_detect == (u_int32_t)bdb_lockd[i].mask ) {
 						value_add_one( &c->rvalue_vals, &bdb_lockd[i].word );
 						rc = 0;
 						break;
@@ -890,7 +890,7 @@
 				c->log, c->argv[1] );
 			return 1;
 		}
-		bdb->bi_lock_detect = rc;
+		bdb->bi_lock_detect = (u_int32_t)rc;
 		break;
 
 	case BDB_SSTACK:

Modified: openldap/trunk/servers/slapd/back-bdb/idl.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/idl.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/idl.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* idl.c - ldap id list handling routines */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/idl.c,v 1.124.2.9 2009/01/22 00:01:05 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/idl.c,v 1.124.2.10 2009/07/27 17:38:41 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -376,7 +376,7 @@
 	}
 	bdb->bi_idl_lru_head = ee;
 
-	if ( ++bdb->bi_idl_cache_size > bdb->bi_idl_cache_max_size ) {
+	if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
 		int i;
 		ee = bdb->bi_idl_lru_tail;
 		for ( i = 0; ee != NULL && i < 10; i++, ee = eprev ) {
@@ -405,6 +405,7 @@
 		assert( bdb->bi_idl_lru_tail != NULL
 			|| bdb->bi_idl_lru_head == NULL );
 	}
+	bdb->bi_idl_cache_size++;
 	ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
 	ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock );
 }

Modified: openldap/trunk/servers/slapd/back-bdb/init.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* init.c - initialize bdb backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/init.c,v 1.247.2.22 2009/06/19 21:53:42 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/init.c,v 1.247.2.23 2009/07/27 17:38:41 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -369,13 +369,10 @@
 	}
 #endif
 
-	/* Default dncache to 2x entrycache */
-	if ( bdb->bi_cache.c_maxsize && !bdb->bi_cache.c_eimax ) {
-		bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize * 2;
-	}
-
-	/* dncache must be >= entrycache */
-	if ( bdb->bi_cache.c_eimax < bdb->bi_cache.c_maxsize ) {
+	/* dncache defaults to 0 == unlimited
+	 * must be >= entrycache
+	 */
+	if ( bdb->bi_cache.c_eimax && bdb->bi_cache.c_eimax < bdb->bi_cache.c_maxsize ) {
 		bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize;
 	}
 

Modified: openldap/trunk/servers/slapd/back-bdb/monitor.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/monitor.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/monitor.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* monitor.c - monitor bdb backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/monitor.c,v 1.19.2.11 2009/01/22 00:01:05 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/monitor.c,v 1.19.2.13 2009/08/17 21:52:54 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -158,17 +158,17 @@
 	a = attr_find( e->e_attrs, ad_olmBDBEntryCache );
 	assert( a != NULL );
 	bv.bv_val = buf;
-	bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_cursize );
+	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_cursize );
 	ber_bvreplace( &a->a_vals[ 0 ], &bv );
 
 	a = attr_find( e->e_attrs, ad_olmBDBDNCache );
 	assert( a != NULL );
-	bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_eiused );
+	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_eiused );
 	ber_bvreplace( &a->a_vals[ 0 ], &bv );
 
 	a = attr_find( e->e_attrs, ad_olmBDBIDLCache );
 	assert( a != NULL );
-	bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_idl_cache_size );
+	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_idl_cache_size );
 	ber_bvreplace( &a->a_vals[ 0 ], &bv );
 	
 #ifdef BDB_MONITOR_IDX
@@ -305,10 +305,6 @@
 {
 	struct bdb_info		*bdb = (struct bdb_info *) be->be_private;
 
-	if ( SLAP_GLUE_SUBORDINATE( be ) ) {
-		return 0;
-	}
-
 	if ( bdb_monitor_initialize() == LDAP_SUCCESS ) {
 		/* monitoring in back-bdb is on by default */
 		SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
@@ -340,10 +336,6 @@
 		return 0;
 	}
 
-	if ( SLAP_GLUE_SUBORDINATE( be ) ) {
-		return 0;
-	}
-
 	mi = backend_info( "monitor" );
 	if ( !mi || !mi->bi_extra ) {
 		SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
@@ -491,10 +483,6 @@
 {
 	struct bdb_info		*bdb = (struct bdb_info *) be->be_private;
 
-	if ( SLAP_GLUE_SUBORDINATE( be ) ) {
-		return 0;
-	}
-
 	if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_ndn ) ) {
 		BackendInfo		*mi = backend_info( "monitor" );
 		monitor_extra_t		*mbe;
@@ -518,18 +506,12 @@
 int
 bdb_monitor_db_destroy( BackendDB *be )
 {
-	if ( SLAP_GLUE_SUBORDINATE( be ) ) {
-		return 0;
-	}
-
 #ifdef BDB_MONITOR_IDX
-	{
-		struct bdb_info		*bdb = (struct bdb_info *) be->be_private;
+	struct bdb_info		*bdb = (struct bdb_info *) be->be_private;
 
-		/* TODO: free tree */
-		ldap_pvt_thread_mutex_destroy( &bdb->bi_idx_mutex );
-		avl_free( bdb->bi_idx, ch_free );
-	}
+	/* TODO: free tree */
+	ldap_pvt_thread_mutex_destroy( &bdb->bi_idx_mutex );
+	avl_free( bdb->bi_idx, ch_free );
 #endif /* BDB_MONITOR_IDX */
 
 	return 0;

Modified: openldap/trunk/servers/slapd/back-bdb/search.c
===================================================================
--- openldap/trunk/servers/slapd/back-bdb/search.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-bdb/search.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* search.c - search operation */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/search.c,v 1.246.2.25 2009/05/13 20:20:38 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/search.c,v 1.246.2.26 2009/08/25 22:58:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2000-2009 The OpenLDAP Foundation.
@@ -326,7 +326,8 @@
 	slap_mask_t	mask;
 	time_t		stoptime;
 	int		manageDSAit;
-	int		tentries = 0, nentries = 0;
+	int		tentries = 0;
+	unsigned	nentries = 0;
 	int		idflag = 0;
 
 	DB_LOCK		lock;

Modified: openldap/trunk/servers/slapd/back-ldap/back-ldap.h
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/back-ldap.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/back-ldap.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* back-ldap.h - ldap backend header file */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/back-ldap.h,v 1.88.2.14 2009/06/11 21:48:11 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/back-ldap.h,v 1.88.2.15 2009/08/26 00:50:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -61,11 +61,11 @@
 	LDAP_BACK_PCONN_LAST
 };
 
-typedef struct ldapconn_t {
-	Connection		*lc_conn;
+typedef struct ldapconn_base_t {
+	Connection		*lcb_conn;
 #define	LDAP_BACK_CONN2PRIV(lc)		((unsigned long)(lc)->lc_conn)
-#define LDAP_BACK_PCONN_ISPRIV(lc)	((void *)(lc)->lc_conn >= (void *)LDAP_BACK_PCONN_FIRST \
-						&& (void *)(lc)->lc_conn < (void *)LDAP_BACK_PCONN_LAST)
+#define LDAP_BACK_PCONN_ISPRIV(lc)	(((void *)(lc)->lc_conn) >= ((void *)LDAP_BACK_PCONN_FIRST) \
+						&& ((void *)(lc)->lc_conn) < ((void *)LDAP_BACK_PCONN_LAST))
 #define LDAP_BACK_PCONN_ISROOTDN(lc)	(LDAP_BACK_PCONN_ISPRIV((lc)) \
 						&& (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_ANON))
 #define LDAP_BACK_PCONN_ISANON(lc)	(LDAP_BACK_PCONN_ISPRIV((lc)) \
@@ -75,8 +75,6 @@
 						&& (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_BIND))
 #define LDAP_BACK_PCONN_ISTLS(lc)	(LDAP_BACK_PCONN_ISPRIV((lc)) \
 						&& (LDAP_BACK_CONN2PRIV((lc)) & LDAP_BACK_PCONN_TLS))
-#define	LDAP_BACK_PCONN_ID(lc)		(LDAP_BACK_PCONN_ISPRIV((lc)) ? \
-						( -1 - (long)(lc)->lc_conn ) : (lc)->lc_conn->c_connid )
 #ifdef HAVE_TLS
 #define	LDAP_BACK_PCONN_ROOTDN_SET(lc, op) \
 	((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? (void *) LDAP_BACK_PCONN_ROOTDN_TLS : (void *) LDAP_BACK_PCONN_ROOTDN))
@@ -96,10 +94,22 @@
 	(BER_BVISEMPTY(&(op)->o_ndn) ? \
 		LDAP_BACK_PCONN_ANON_SET((lc), (op)) : LDAP_BACK_PCONN_ROOTDN_SET((lc), (op)))
 
-	LDAP			*lc_ld;
-	struct berval		lc_cred;
-	struct berval 		lc_bound_ndn;
-	struct berval		lc_local_ndn;
+	struct berval		lcb_local_ndn;
+	unsigned		lcb_refcnt;
+	time_t			lcb_create_time;
+	time_t			lcb_time;
+} ldapconn_base_t;
+
+typedef struct ldapconn_t {
+	ldapconn_base_t		lc_base;
+#define	lc_conn			lc_base.lcb_conn
+#define	lc_local_ndn		lc_base.lcb_local_ndn
+#define	lc_refcnt		lc_base.lcb_refcnt
+#define	lc_create_time		lc_base.lcb_create_time
+#define	lc_time			lc_base.lcb_time
+
+	LDAP_TAILQ_ENTRY(ldapconn_t)	lc_q;
+
 	unsigned		lc_lcflags;
 #define LDAP_BACK_CONN_ISSET_F(fp,f)	(*(fp) & (f))
 #define	LDAP_BACK_CONN_SET_F(fp,f)	(*(fp) |= (f))
@@ -164,12 +174,10 @@
 #define	LDAP_BACK_CONN_CACHED_SET(lc)		LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_CACHED)
 #define	LDAP_BACK_CONN_CACHED_CLEAR(lc)		LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_CACHED)
 
-	unsigned		lc_refcnt;
+	LDAP			*lc_ld;
+	struct berval		lc_cred;
+	struct berval 		lc_bound_ndn;
 	unsigned		lc_flags;
-	time_t			lc_create_time;
-	time_t			lc_time;
-
-	LDAP_TAILQ_ENTRY(ldapconn_t)	lc_q;
 } ldapconn_t;
 
 typedef struct ldap_avl_info_t {
@@ -444,6 +452,7 @@
 	void (*retry_info_destroy)( slap_retry_info_t *ri );
 	int (*retry_info_parse)( char *in, slap_retry_info_t *ri, char *buf, ber_len_t buflen );
 	int (*retry_info_unparse)( slap_retry_info_t *ri, struct berval *bvout );
+	int (*connid2str)( const ldapconn_base_t *lc, char *buf, ber_len_t buflen );
 } ldap_extra_t;
 
 LDAP_END_DECL

Modified: openldap/trunk/servers/slapd/back-ldap/bind.c
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/bind.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/bind.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* bind.c - ldap backend bind function */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/bind.c,v 1.162.2.22 2009/06/11 21:48:11 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/bind.c,v 1.162.2.24 2009/09/01 22:50:21 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -32,6 +32,7 @@
 #define AVL_INTERNAL
 #include "slap.h"
 #include "back-ldap.h"
+#include "lutil.h"
 #undef ldap_debug	/* silence a warning in ldap-int.h */
 #include "../../../libraries/libldap/ldap-int.h"
 
@@ -40,7 +41,46 @@
 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
 
 #if LDAP_BACK_PRINT_CONNTREE > 0
+
+static const struct {
+	slap_mask_t	f;
+	char		c;
+} flagsmap[] = {
+	{ LDAP_BACK_FCONN_ISBOUND,	'B' },
+	{ LDAP_BACK_FCONN_ISANON,	'A' },
+	{ LDAP_BACK_FCONN_ISPRIV,	'P' },
+	{ LDAP_BACK_FCONN_ISTLS,	'T' },
+	{ LDAP_BACK_FCONN_BINDING,	'X' },
+	{ LDAP_BACK_FCONN_TAINTED,	'E' },
+	{ LDAP_BACK_FCONN_ABANDON,	'N' },
+	{ LDAP_BACK_FCONN_ISIDASR,	'S' },
+	{ LDAP_BACK_FCONN_CACHED,	'C' },
+	{ 0,				'\0' }
+};
+
 static void
+ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
+{
+	char buf[ SLAP_TEXT_BUFLEN ];
+	char fbuf[ sizeof("BAPTIENSC") ];
+	int i;
+
+	ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) );
+	for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) {
+		if ( lc->lc_lcflags & flagsmap[i].f ) {
+			fbuf[i] = flagsmap[i].c;
+
+		} else {
+			fbuf[i] = '.';
+		}
+	}
+	fbuf[i] = '\0';
+	
+	fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n",
+		(void *)lc, buf, avlstr, lc->lc_lcflags, fbuf );
+}
+
+static void
 ldap_back_ravl_print( Avlnode *root, int depth )
 {
 	int		i;
@@ -57,13 +97,9 @@
 	}
 
 	lc = root->avl_data;
-	fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
-		(void *)lc,
-		lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
-		(void *)lc->lc_conn,
-		avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );
-	
-	ldap_back_ravl_print( root->avl_left, depth+1 );
+	ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) );
+
+	ldap_back_ravl_print( root->avl_left, depth + 1 );
 }
 
 static char* priv2str[] = {
@@ -91,11 +127,8 @@
 
 		LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
 		{
-			fprintf( stderr, "    [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
-				i,
-				(void *)lc,
-				lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
-				(void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );
+			fprintf( stderr, "    [%d] ", i );
+			ldap_back_conn_print( lc, "" );
 			i++;
 		}
 	}
@@ -303,9 +336,10 @@
 		if ( LDAP_BACK_SINGLECONN( li ) ) {
 			while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
 			{
+				assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
 				Debug( LDAP_DEBUG_TRACE,
-					"=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",
-					LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );
+					"=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
+					lc->lc_conn->c_connid, lc->lc_refcnt, 0 );
 
 				if ( tmplc->lc_refcnt != 0 ) {
 					/* taint it */
@@ -631,7 +665,7 @@
 	LDAP		*ld = NULL;
 #ifdef HAVE_TLS
 	int		is_tls = op->o_conn->c_is_tls;
-	time_t		lc_time = (time_t)(-1);
+	time_t		lctime = (time_t)(-1);
 	slap_bindconf *sb;
 #endif /* HAVE_TLS */
 
@@ -704,7 +738,7 @@
 
 	} else if ( li->li_idle_timeout ) {
 		/* only touch when activity actually took place... */
-		lc_time = op->o_time;
+		lctime = op->o_time;
 	}
 #endif /* HAVE_TLS */
 
@@ -716,8 +750,8 @@
 	} else {
 		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
 	}
-	if ( lc_time != (time_t)(-1) ) {
-		lc->lc_time = lc_time;
+	if ( lctime != (time_t)(-1) ) {
+		lc->lc_time = lctime;
 	}
 #endif /* HAVE_TLS */
 
@@ -750,7 +784,7 @@
 {
 	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
 	ldapconn_t	*lc = NULL,
-			lc_curr = { 0 };
+			lc_curr = {{ 0 }};
 	int		refcnt = 1,
 			lookupconn = !( sendok & LDAP_BACK_BINDING );
 
@@ -2714,3 +2748,84 @@
 
 	return 0;
 }
+
+int
+ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
+{
+	char tbuf[ SLAP_TEXT_BUFLEN ];
+	char *ptr = buf, *end = buf + buflen;
+	int len;
+
+	if ( ptr + sizeof("conn=") > end ) return -1;
+	ptr = lutil_strcopy( ptr, "conn=" );
+
+	len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) );
+	ptr += len;
+	if ( ptr >= end ) return -1;
+
+	if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) {
+		if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1;
+		ptr = lutil_strcopy( ptr, " DN=\"" );
+		ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len );
+		*ptr++ = '"';
+	}
+
+	if ( lc->lcb_create_time != 0 ) {
+		len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time );
+		if ( ptr + sizeof(" created=") + len >= end ) return -1;
+		ptr = lutil_strcopy( ptr, " created=" );
+		ptr = lutil_strcopy( ptr, tbuf );
+	}
+
+	if ( lc->lcb_time != 0 ) {
+		len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time );
+		if ( ptr + sizeof(" modified=") + len >= end ) return -1;
+		ptr = lutil_strcopy( ptr, " modified=" );
+		ptr = lutil_strcopy( ptr, tbuf );
+	}
+
+	len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt );
+	if ( ptr + sizeof(" refcnt=") + len >= end ) return -1;
+	ptr = lutil_strcopy( ptr, " refcnt=" );
+	ptr = lutil_strcopy( ptr, tbuf );
+
+	return ptr - buf;
+}
+
+int
+ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
+{
+	static struct berval conns[] = {
+		BER_BVC("ROOTDN"),
+		BER_BVC("ROOTDN-TLS"),
+		BER_BVC("ANON"),
+		BER_BVC("ANON-TLS"),
+		BER_BVC("BIND"),
+		BER_BVC("BIND-TLS"),
+		BER_BVNULL
+	};
+
+	int len = 0;
+
+	if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) {
+		long cid;
+		struct berval *bv;
+
+		cid = (long)lc->lcb_conn;
+		assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST );
+
+		bv = &conns[ cid ];
+
+		if ( bv->bv_len >= buflen ) {
+			return bv->bv_len + 1;
+		}
+
+		len = bv->bv_len;
+		lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 );
+
+	} else {
+		len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid );
+	}
+
+	return len;
+}

Modified: openldap/trunk/servers/slapd/back-ldap/chain.c
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/chain.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/chain.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* chain.c - chain LDAP operations */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.52.2.10 2009/01/22 00:01:06 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.52.2.11 2009/08/26 00:50:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -2063,7 +2063,6 @@
 chain_initialize( void )
 {
 	int rc;
-	const char *text;
 
 	/* Make sure we don't exceed the bits reserved for userland */
 	config_check_userland( CH_LAST );

Modified: openldap/trunk/servers/slapd/back-ldap/init.c
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* init.c - initialize ldap backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/init.c,v 1.99.2.11 2009/01/30 19:07:40 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/init.c,v 1.99.2.12 2009/08/26 00:50:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -39,7 +39,8 @@
 	slap_idassert_parse_cf,
 	slap_retry_info_destroy,
 	slap_retry_info_parse,
-	slap_retry_info_unparse
+	slap_retry_info_unparse,
+	ldap_back_connid2str
 };
 
 int

Modified: openldap/trunk/servers/slapd/back-ldap/proto-ldap.h
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/proto-ldap.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/proto-ldap.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/proto-ldap.h,v 1.15.2.8 2009/01/22 00:01:06 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/proto-ldap.h,v 1.15.2.9 2009/08/26 00:50:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -63,6 +63,9 @@
 
 extern ldapconn_t * ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc );
 
+extern int ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen );
+extern int ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen );
+
 extern int
 ldap_back_proxy_authz_ctrl(
 		Operation	*op,

Modified: openldap/trunk/servers/slapd/back-ldap/search.c
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/search.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/search.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* search.c - ldap backend search function */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/search.c,v 1.201.2.21 2009/03/06 07:14:56 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/search.c,v 1.201.2.22 2009/08/25 22:58:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -832,7 +832,9 @@
 					LBER_FREE( attr->a_nvals[i].bv_val );
 				LBER_FREE( attr->a_vals[i].bv_val );
 				attr->a_numvals--;
-				if ( i < attr->a_numvals ) {
+
+				assert( i >= 0 );
+				if ( (unsigned)i < attr->a_numvals ) {
 					attr->a_vals[i] = attr->a_vals[attr->a_numvals];
 					if ( attr->a_nvals != attr->a_vals )
 						attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];

Modified: openldap/trunk/servers/slapd/back-ldap/unbind.c
===================================================================
--- openldap/trunk/servers/slapd/back-ldap/unbind.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ldap/unbind.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* unbind.c - ldap backend unbind function */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/unbind.c,v 1.33.2.5 2009/01/22 00:01:06 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/unbind.c,v 1.33.2.6 2009/08/26 00:50:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -53,11 +53,11 @@
 #endif /* LDAP_BACK_PRINT_CONNTREE */
 	while ( ( lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
 	{
+		assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
 		Debug( LDAP_DEBUG_TRACE,
-			"=>ldap_back_conn_destroy: destroying conn %ld "
+			"=>ldap_back_conn_destroy: destroying conn %lu "
 			"refcnt=%d flags=0x%08x\n",
-			LDAP_BACK_PCONN_ID( lc ),
-			lc->lc_refcnt, lc->lc_lcflags );
+			lc->lc_conn->c_connid, lc->lc_refcnt, lc->lc_lcflags );
 
 		if ( lc->lc_refcnt > 0 ) {
 			/* someone else might be accessing the connection;

Modified: openldap/trunk/servers/slapd/back-meta/back-meta.h
===================================================================
--- openldap/trunk/servers/slapd/back-meta/back-meta.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/back-meta.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/back-meta.h,v 1.64.2.13 2009/02/17 19:14:41 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/back-meta.h,v 1.64.2.15 2009/08/26 00:50:20 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -221,14 +221,16 @@
 } metasingleconn_t;
 
 typedef struct metaconn_t {
-	Connection		*mc_conn;
-#define	lc_conn			mc_conn
-	unsigned		mc_refcnt;
+	ldapconn_base_t		lc_base;
+#define	mc_base			lc_base
+#define	mc_conn			mc_base.lcb_conn
+#define	mc_local_ndn		mc_base.lcb_local_ndn
+#define	mc_refcnt		mc_base.lcb_refcnt
+#define	mc_create_time		mc_base.lcb_create_time
+#define	mc_time			mc_base.lcb_time
+	
+	LDAP_TAILQ_ENTRY(metaconn_t)	mc_q;
 
-	time_t			mc_create_time;
-	time_t			mc_time;
-	
-	struct berval          	mc_local_ndn;
 	/* NOTE: msc_mscflags is used to recycle the #define
 	 * in metasingleconn_t */
 	unsigned		msc_mscflags;
@@ -243,8 +245,6 @@
 
 	struct metainfo_t	*mc_info;
 
-	LDAP_TAILQ_ENTRY(metaconn_t)	mc_q;
-
 	/* supersedes the connection stuff */
 	metasingleconn_t	mc_conns[ 1 ];
 	/* NOTE: mc_conns must be last, because
@@ -301,6 +301,14 @@
 #define	META_BACK_TGT_ISSET(mt,f)		( ( (mt)->mt_flags & (f) ) == (f) )
 #define	META_BACK_TGT_ISMASK(mt,m,f)		( ( (mt)->mt_flags & (m) ) == (f) )
 
+#define META_BACK_TGT_SAVECRED(mt)		META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_SAVECRED )
+
+#define META_BACK_TGT_USE_TLS(mt)		META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_USE_TLS )
+#define META_BACK_TGT_PROPAGATE_TLS(mt)		META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_PROPAGATE_TLS )
+#define META_BACK_TGT_TLS_CRITICAL(mt)		META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_TLS_CRITICAL )
+
+#define META_BACK_TGT_CHASE_REFERRALS(mt)	META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_CHASE_REFERRALS )
+
 #define	META_BACK_TGT_T_F(mt)			META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
 #define	META_BACK_TGT_T_F_DISCOVER(mt)		META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_DISCOVER )
 

Modified: openldap/trunk/servers/slapd/back-meta/bind.c
===================================================================
--- openldap/trunk/servers/slapd/back-meta/bind.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/bind.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/bind.c,v 1.95.2.18 2009/01/22 00:01:07 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/bind.c,v 1.95.2.20 2009/08/26 00:50:20 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -223,9 +223,10 @@
 
 				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
 				{
+					assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
 					Debug( LDAP_DEBUG_TRACE,
-						"=>meta_back_bind: destroying conn %ld (refcnt=%u)\n",
-						LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 );
+						"=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
+						mc->mc_conn->c_connid, mc->mc_refcnt, 0 );
 
 					if ( tmpmc->mc_refcnt != 0 ) {
 						/* taint it */
@@ -538,7 +539,7 @@
 	LDAP_BACK_CONN_ISBOUND_SET( msc );
 	mc->mc_authz_target = candidate;
 
-	if ( LDAP_BACK_SAVECRED( mi ) ) {
+	if ( META_BACK_TGT_SAVECRED( mt ) ) {
 		if ( !BER_BVISNULL( &msc->msc_cred ) ) {
 			memset( msc->msc_cred.bv_val, 0,
 				msc->msc_cred.bv_len );
@@ -660,12 +661,16 @@
 		isroot = 1;
 	}
 
-	Debug( LDAP_DEBUG_TRACE,
-		"%s meta_back_dobind: conn=%ld%s\n",
-		op->o_log_prefix,
-		LDAP_BACK_PCONN_ID( mc ),
-		isroot ? " (isroot)" : "" );
+	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+		char buf[STRLENOF("4294967295U") + 1] = { 0 };
+		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
 
+		Debug( LDAP_DEBUG_TRACE,
+			"%s meta_back_dobind: conn=%s%s\n",
+			op->o_log_prefix, buf,
+			isroot ? " (isroot)" : "" );
+	}
+
 	/*
 	 * all the targets are bound as pseudoroot
 	 */
@@ -796,10 +801,15 @@
 	}
 
 done:;
-	Debug( LDAP_DEBUG_TRACE,
-		"%s meta_back_dobind: conn=%ld bound=%d\n",
-		op->o_log_prefix, LDAP_BACK_PCONN_ID( mc ), bound );
+	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+		char buf[STRLENOF("4294967295U") + 1] = { 0 };
+		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
 
+		Debug( LDAP_DEBUG_TRACE,
+			"%s meta_back_dobind: conn=%s bound=%d\n",
+			op->o_log_prefix, buf, bound );
+	}
+
 	if ( bound == 0 ) {
 		meta_back_release_conn( mi, mc );
 
@@ -1539,7 +1549,7 @@
 				LDAP_BACK_CONN_ISBOUND_SET( msc );
 				ber_bvreplace( &msc->msc_bound_ndn, &binddn );
 
-				if ( LDAP_BACK_SAVECRED( mi ) ) {
+				if ( META_BACK_TGT_SAVECRED( mt ) ) {
 					if ( !BER_BVISNULL( &msc->msc_cred ) ) {
 						memset( msc->msc_cred.bv_val, 0,
 							msc->msc_cred.bv_len );

Modified: openldap/trunk/servers/slapd/back-meta/config.c
===================================================================
--- openldap/trunk/servers/slapd/back-meta/config.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/config.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/config.c,v 1.74.2.17 2009/01/22 00:01:07 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/config.c,v 1.74.2.18 2009/08/14 20:54:14 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -640,6 +640,10 @@
 		
 	/* save bind creds for referral rebinds? */
 	} else if ( strcasecmp( argv[ 0 ], "rebind-as-user" ) == 0 ) {
+		unsigned	*flagsp = mi->mi_ntargets ?
+				&mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
+				: &mi->mi_flags;
+
 		if ( argc > 2 ) {
 			Debug( LDAP_DEBUG_ANY,
 	"%s: line %d: \"rebind-as-user {NO|yes}\" takes 1 argument.\n",
@@ -651,16 +655,16 @@
 			Debug( LDAP_DEBUG_ANY,
 	"%s: line %d: deprecated use of \"rebind-as-user {FALSE|true}\" with no arguments.\n",
 			    fname, lineno, 0 );
-			mi->mi_flags |= LDAP_BACK_F_SAVECRED;
+			*flagsp |= LDAP_BACK_F_SAVECRED;
 
 		} else {
 			switch ( check_true_false( argv[ 1 ] ) ) {
 			case 0:
-				mi->mi_flags &= ~LDAP_BACK_F_SAVECRED;
+				*flagsp &= ~LDAP_BACK_F_SAVECRED;
 				break;
 
 			case 1:
-				mi->mi_flags |= LDAP_BACK_F_SAVECRED;
+				*flagsp |= LDAP_BACK_F_SAVECRED;
 				break;
 
 			default:

Modified: openldap/trunk/servers/slapd/back-meta/conn.c
===================================================================
--- openldap/trunk/servers/slapd/back-meta/conn.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/conn.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/conn.c,v 1.86.2.17 2009/01/22 00:01:07 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/conn.c,v 1.86.2.19 2009/08/26 00:50:20 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -418,13 +418,13 @@
 
 	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
 	ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS,
-		LDAP_BACK_CHASE_REFERRALS( mi ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
+		META_BACK_TGT_CHASE_REFERRALS( mt ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
 
 #ifdef HAVE_TLS
 	/* start TLS ("tls [try-]{start|propagate}" statement) */
-	if ( ( LDAP_BACK_USE_TLS( mi )
+	if ( ( META_BACK_TGT_USE_TLS( mt )
 		|| ( op->o_conn->c_is_tls
-			&& LDAP_BACK_PROPAGATE_TLS( mi ) ) )
+			&& META_BACK_TGT_PROPAGATE_TLS( mt ) ) )
 		&& !is_ldaps )
 	{
 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
@@ -526,7 +526,7 @@
 		 * overlay, where the "uri" can be parsed out of a referral */
 		if ( rs->sr_err == LDAP_SERVER_DOWN
 			|| ( rs->sr_err != LDAP_SUCCESS
-				&& LDAP_BACK_TLS_CRITICAL( mi ) ) )
+				&& META_BACK_TGT_TLS_CRITICAL( mt ) ) )
 		{
 
 #ifdef DEBUG_205
@@ -1024,7 +1024,7 @@
 {
 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
 	metaconn_t	*mc = NULL,
-			mc_curr = { 0 };
+			mc_curr = {{ 0 }};
 	int		cached = META_TARGET_NONE,
 			i = META_TARGET_NONE,
 			err = LDAP_SUCCESS,
@@ -1168,8 +1168,14 @@
 					LDAP_BACK_CONN_TAINTED_SET( mc );
 					LDAP_BACK_CONN_CACHED_CLEAR( mc );
 
-					Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired (tainted).\n",
-						op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
+					if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+						char buf[STRLENOF("4294967295U") + 1] = { 0 };
+						mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
+
+						Debug( LDAP_DEBUG_TRACE,
+							"%s meta_back_getconn: mc=%p conn=%s expired (tainted).\n",
+							op->o_log_prefix, (void *)mc, buf );
+					}
 				}
 
 				mc->mc_refcnt++;
@@ -1654,10 +1660,14 @@
 
 			default:
 				LDAP_BACK_CONN_CACHED_CLEAR( mc );
-				Debug( LDAP_DEBUG_ANY,
-					"%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
-					op->o_log_prefix, ncandidates,
-					LDAP_BACK_PCONN_ID( mc ) );
+				if ( LogTest( LDAP_DEBUG_ANY ) ) {
+					char buf[STRLENOF("4294967295U") + 1] = { 0 };
+					mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
+
+					Debug( LDAP_DEBUG_ANY,
+						"%s meta_back_getconn: candidates=%d conn=%s insert failed\n",
+						op->o_log_prefix, ncandidates, buf );
+				}
 	
 				mc->mc_refcnt = 0;	
 				meta_back_conn_free( mc );
@@ -1671,16 +1681,24 @@
 			}
 		}
 
-		Debug( LDAP_DEBUG_TRACE,
-			"%s meta_back_getconn: candidates=%d conn=%ld inserted\n",
-			op->o_log_prefix, ncandidates,
-			LDAP_BACK_PCONN_ID( mc ) );
+		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+			char buf[STRLENOF("4294967295U") + 1] = { 0 };
+			mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
 
+			Debug( LDAP_DEBUG_TRACE,
+				"%s meta_back_getconn: candidates=%d conn=%s inserted\n",
+				op->o_log_prefix, ncandidates, buf );
+		}
+
 	} else {
-		Debug( LDAP_DEBUG_TRACE,
-			"%s meta_back_getconn: candidates=%d conn=%ld fetched\n",
-			op->o_log_prefix, ncandidates,
-			LDAP_BACK_PCONN_ID( mc ) );
+		if ( LogTest( LDAP_DEBUG_TRACE ) ) {
+			char buf[STRLENOF("4294967295U") + 1] = { 0 };
+			mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );
+
+			Debug( LDAP_DEBUG_TRACE,
+				"%s meta_back_getconn: candidates=%d conn=%s fetched\n",
+				op->o_log_prefix, ncandidates, buf );
+		}
 	}
 
 	return mc;

Modified: openldap/trunk/servers/slapd/back-meta/search.c
===================================================================
--- openldap/trunk/servers/slapd/back-meta/search.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/search.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/search.c,v 1.146.2.22 2009/03/05 18:22:15 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/search.c,v 1.146.2.23 2009/08/14 20:54:14 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -199,7 +199,7 @@
 		 * because the connection is not shared until bind is over */
 		if ( !BER_BVISNULL( &binddn ) ) {
 			ber_bvreplace( &msc->msc_bound_ndn, &binddn );
-			if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
+			if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
 				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
 					memset( msc->msc_cred.bv_val, 0,
 						msc->msc_cred.bv_len );

Modified: openldap/trunk/servers/slapd/back-meta/unbind.c
===================================================================
--- openldap/trunk/servers/slapd/back-meta/unbind.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-meta/unbind.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/unbind.c,v 1.30.2.6 2009/01/22 00:01:08 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/unbind.c,v 1.30.2.7 2009/08/26 00:50:20 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -39,7 +39,7 @@
 {
 	metainfo_t	*mi = ( metainfo_t * )be->be_private;
 	metaconn_t	*mc,
-			mc_curr = { 0 };
+			mc_curr = {{ 0 }};
 	int		i;
 
 
@@ -56,11 +56,11 @@
 #endif /* META_BACK_PRINT_CONNTREE */
 	while ( ( mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
 	{
+		assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
 		Debug( LDAP_DEBUG_TRACE,
-			"=>meta_back_conn_destroy: destroying conn %ld "
+			"=>meta_back_conn_destroy: destroying conn %lu "
 			"refcnt=%d flags=0x%08x\n",
-			LDAP_BACK_PCONN_ID( mc ),
-			mc->mc_refcnt, mc->msc_mscflags );
+			mc->mc_conn->c_connid, mc->mc_refcnt, mc->msc_mscflags );
 		
 		if ( mc->mc_refcnt > 0 ) {
 			/* someone else might be accessing the connection;

Modified: openldap/trunk/servers/slapd/back-monitor/back-monitor.h
===================================================================
--- openldap/trunk/servers/slapd/back-monitor/back-monitor.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-monitor/back-monitor.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* back-monitor.h - ldap monitor back-end header file */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/back-monitor.h,v 1.52.2.6 2009/01/22 00:01:08 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/back-monitor.h,v 1.52.2.8 2009/08/25 22:48:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2001-2009 The OpenLDAP Foundation.
@@ -130,6 +130,7 @@
 	AttributeDescription	*mi_ad_monitorIsShadow;
 	AttributeDescription	*mi_ad_monitorUpdateRef;
 	AttributeDescription	*mi_ad_monitorRuntimeConfig;
+	AttributeDescription	*mi_ad_monitorSuperiorDN;
 
 	/*
 	 * Generic description attribute
@@ -288,9 +289,9 @@
 
 	int (*register_subsys)( monitor_subsys_t *ms );
 	int (*register_backend)( BackendInfo *bi );
-	int (*register_database)( BackendDB *be, struct berval *ndn );
+	int (*register_database)( BackendDB *be, struct berval *ndn_out );
 	int (*register_overlay_info)( slap_overinst *on );
-	int (*register_overlay)( BackendDB *be );
+	int (*register_overlay)( BackendDB *be, slap_overinst *on, struct berval *ndn_out );
 	int (*register_entry)( Entry *e, monitor_callback_t *cb,
 		monitor_subsys_t *ms, unsigned long flags );
 	int (*register_entry_parent)( Entry *e, monitor_callback_t *cb,

Modified: openldap/trunk/servers/slapd/back-monitor/database.c
===================================================================
--- openldap/trunk/servers/slapd/back-monitor/database.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-monitor/database.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* database.c - deals with database subsystem */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/database.c,v 1.80.2.13 2009/04/27 22:50:10 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/database.c,v 1.80.2.15 2009/08/25 22:48:09 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2001-2009 The OpenLDAP Foundation.
@@ -100,6 +100,101 @@
 }
 
 static int
+monitor_subsys_overlay_init_one(
+	monitor_info_t		*mi,
+	BackendDB		*be,
+	monitor_subsys_t	*ms,
+	monitor_subsys_t	*ms_overlay,
+	slap_overinst		*on,
+	Entry			*e_database,
+	Entry			**ep_overlay )
+{
+	char			buf[ BACKMONITOR_BUFSIZE ];
+	int			j, o;
+	Entry			*e_overlay;
+	slap_overinst		*on2;
+	slap_overinfo		*oi = NULL;
+	BackendInfo		*bi;
+	monitor_entry_t		*mp_overlay;
+	struct berval		bv;
+
+	assert( overlay_is_over( be ) );
+
+	oi = (slap_overinfo *)be->bd_info->bi_private;
+	bi = oi->oi_orig;
+
+	/* find the overlay number, o */
+	for ( o = 0, on2 = oi->oi_list; on2 && on2 != on; on2 = on2->on_next, o++ )
+		;
+
+	if ( on2 == NULL ) {
+		return -1;
+	}
+
+	/* find the overlay type number, j */
+	for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
+		if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
+			break;
+		}
+	}
+	assert( on2 != NULL );
+
+	bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o );
+	bv.bv_val = buf;
+
+	e_overlay = monitor_entry_stub( &e_database->e_name, &e_database->e_nname, &bv,
+		mi->mi_oc_monitoredObject, mi, NULL, NULL );
+
+	if ( e_overlay == NULL ) {
+		Debug( LDAP_DEBUG_ANY,
+			"monitor_subsys_overlay_init_one: "
+			"unable to create entry "
+			"\"cn=Overlay %d,%s\"\n",
+			o, e_database->e_name.bv_val, 0 );
+		return( -1 );
+	}
+	ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
+	attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL );
+
+	bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s",
+		j, ms_overlay->mss_dn.bv_val );
+	bv.bv_val = buf;
+	attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso,
+		&bv, NULL );
+
+	if ( SLAP_MONITOR( be ) ) {
+		attr_merge( e_overlay, slap_schema.si_ad_monitorContext,
+				be->be_suffix, be->be_nsuffix );
+
+	} else {
+		attr_merge( e_overlay, slap_schema.si_ad_namingContexts,
+				be->be_suffix, NULL );
+	}
+
+	mp_overlay = monitor_entrypriv_create();
+	if ( mp_overlay == NULL ) {
+		return -1;
+	}
+	e_overlay->e_private = ( void * )mp_overlay;
+	mp_overlay->mp_info = ms;
+	mp_overlay->mp_flags = ms->mss_flags | MONITOR_F_SUB;
+	
+	if ( monitor_cache_add( mi, e_overlay ) ) {
+		Debug( LDAP_DEBUG_ANY,
+			"monitor_subsys_overlay_init_one: "
+			"unable to add entry "
+			"\"cn=Overlay %d,%s\"\n",
+			o, e_database->e_name.bv_val, 0 );
+		return -1;
+	}
+
+	*ep_overlay = e_overlay;
+	ep_overlay = &mp_overlay->mp_next;
+
+	return 0;
+}
+
+static int
 monitor_subsys_database_init_one(
 	monitor_info_t		*mi,
 	BackendDB		*be,
@@ -126,17 +221,12 @@
 		bi = oi->oi_orig;
 	}
 
-	/* Subordinates are not exposed as their own naming context */
-	if ( SLAP_GLUE_SUBORDINATE( be ) ) {
-		return 0;
-	}
-
 	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, rdn,
 		mi->mi_oc_monitoredObject, mi, NULL, NULL );
 
 	if ( e == NULL ) {
 		Debug( LDAP_DEBUG_ANY,
-			"monitor_subsys_database_init: "
+			"monitor_subsys_database_init_one: "
 			"unable to create entry \"%s,%s\"\n",
 			rdn->bv_val, ms->mss_dn.bv_val, 0 );
 		return( -1 );
@@ -157,7 +247,7 @@
 	} else {
 		if ( be->be_suffix == NULL ) {
 			Debug( LDAP_DEBUG_ANY,
-				"monitor_subsys_database_init: "
+				"monitor_subsys_database_init_one: "
 				"missing suffix for %s\n",
 				rdnval, 0, 0 );
 		} else {
@@ -166,6 +256,20 @@
 			attr_merge( e_database, slap_schema.si_ad_namingContexts,
 				be->be_suffix, NULL );
 		}
+
+		if ( SLAP_GLUE_SUBORDINATE( be ) ) {
+			BackendDB *sup_be = select_backend( &be->be_nsuffix[ 0 ], 1 );
+			if ( sup_be == NULL ) {
+				Debug( LDAP_DEBUG_ANY,
+					"monitor_subsys_database_init: "
+					"unable to get superior for %s\n",
+					be->be_suffix[ 0 ].bv_val, 0, 0 );
+
+			} else {
+				attr_merge( e, mi->mi_ad_monitorSuperiorDN,
+					sup_be->be_suffix, sup_be->be_nsuffix );
+			}
+		}
 	}
 
 	(void)init_readOnly( mi, e, be->be_restrictops );
@@ -244,7 +348,7 @@
 
 	if ( monitor_cache_add( mi, e ) ) {
 		Debug( LDAP_DEBUG_ANY,
-			"monitor_subsys_database_init: "
+			"monitor_subsys_database_init_one: "
 			"unable to add entry \"%s,%s\"\n",
 			rdn->bv_val, ms->mss_dn.bv_val, 0 );
 		return( -1 );
@@ -256,74 +360,11 @@
 
 	if ( oi != NULL ) {
 		Entry		**ep_overlay = &mp->mp_children;
-		monitor_entry_t	*mp_overlay;
 		slap_overinst	*on = oi->oi_list;
-		int		o;
 
-		for ( o = 0; on; o++, on = on->on_next ) {
-			Entry			*e_overlay;
-			slap_overinst		*on2;
-
-			/* find the overlay number, j */
-			for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
-				if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
-					break;
-				}
-			}
-			assert( on2 != NULL );
-
-			bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o );
-			bv.bv_val = buf;
-
-			e_overlay = monitor_entry_stub( &e->e_name, &e->e_nname, &bv,
-				mi->mi_oc_monitoredObject, mi, NULL, NULL );
-
-			if ( e_overlay == NULL ) {
-				Debug( LDAP_DEBUG_ANY,
-					"monitor_subsys_database_init: "
-					"unable to create entry "
-					"\"cn=Overlay %d,%s,%s\"\n",
-					o, rdn->bv_val, ms->mss_dn.bv_val );
-				return( -1 );
-			}
-			ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
-			attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL );
-
-			bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s",
-				j, ms_overlay->mss_dn.bv_val );
-			bv.bv_val = buf;
-			attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso,
-				&bv, NULL );
-
-			if ( SLAP_MONITOR( be ) ) {
-				attr_merge( e_overlay, slap_schema.si_ad_monitorContext,
-						be->be_suffix, be->be_nsuffix );
-
-			} else {
-				attr_merge( e_overlay, slap_schema.si_ad_namingContexts,
-						be->be_suffix, NULL );
-			}
-
-			mp_overlay = monitor_entrypriv_create();
-			if ( mp_overlay == NULL ) {
-				return -1;
-			}
-			e_overlay->e_private = ( void * )mp_overlay;
-			mp_overlay->mp_info = ms;
-			mp_overlay->mp_flags = ms->mss_flags
-				| MONITOR_F_SUB;
-	
-			if ( monitor_cache_add( mi, e_overlay ) ) {
-				Debug( LDAP_DEBUG_ANY,
-					"monitor_subsys_database_init: "
-					"unable to add entry "
-					"\"cn=Overlay %d,%s,%s\"\n",
-					o, rdn->bv_val, ms->mss_dn.bv_val );
-				return( -1 );
-			}
-
-			*ep_overlay = e_overlay;
-			ep_overlay = &mp_overlay->mp_next;
+		for ( ; on; on = on->on_next ) {
+			monitor_subsys_overlay_init_one( mi, be,
+				ms, ms_overlay, on, e, ep_overlay );
 		}
 	}
 
@@ -333,10 +374,11 @@
 	return 0;
 }
 
-int
-monitor_back_register_database(
+static int
+monitor_back_register_database_and_overlay(
 	BackendDB		*be,
-	struct berval	*ndn )
+	struct slap_overinst	*on,
+	struct berval		*ndn_out )
 {
 	monitor_info_t		*mi;
 	Entry			*e_database, **ep;
@@ -351,7 +393,12 @@
 	assert( be_monitor != NULL );
 
 	if ( !monitor_subsys_is_opened() ) {
-		return monitor_back_register_database_limbo( be, ndn );
+		if ( on ) {
+			return monitor_back_register_overlay_limbo( be, on, ndn_out );
+
+		} else {
+			return monitor_back_register_database_limbo( be, ndn_out );
+		}
 	}
 
 	mi = ( monitor_info_t * )be_monitor->be_private;
@@ -446,14 +493,52 @@
 
 done:;
 	monitor_cache_release( mi, e_database );
-	if ( rc == 0 && ndn && ep && *ep ) {
-		*ndn = (*ep)->e_nname;
+	if ( rc == 0 && ndn_out && ep && *ep ) {
+		if ( on ) {
+			Entry *e_ov;
+			struct berval ov_type;
+
+			ber_str2bv( on->on_bi.bi_type, 0, 0, &ov_type );
+
+			mp = ( monitor_entry_t * ) (*ep)->e_private;
+			for ( e_ov = mp->mp_children; e_ov; ) {
+				Attribute *a = attr_find( e_ov->e_attrs, mi->mi_ad_monitoredInfo );
+
+				if ( a != NULL && bvmatch( &a->a_nvals[ 0 ], &ov_type ) ) {
+					*ndn_out = e_ov->e_nname;
+					break;
+				}
+
+				mp = ( monitor_entry_t * ) e_ov->e_private;
+				e_ov = mp->mp_next;
+			}
+			
+		} else {
+			*ndn_out = (*ep)->e_nname;
+		}
 	}
 
 	return rc;
 }
 
 int
+monitor_back_register_database(
+	BackendDB		*be,
+	struct berval		*ndn_out )
+{
+	return monitor_back_register_database_and_overlay( be, NULL, ndn_out );
+}
+
+int
+monitor_back_register_overlay(
+	BackendDB		*be,
+	struct slap_overinst	*on,
+	struct berval		*ndn_out )
+{
+	return monitor_back_register_database_and_overlay( be, on, ndn_out );
+}
+
+int
 monitor_subsys_database_init(
 	BackendDB		*be,
 	monitor_subsys_t	*ms )

Modified: openldap/trunk/servers/slapd/back-monitor/init.c
===================================================================
--- openldap/trunk/servers/slapd/back-monitor/init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-monitor/init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* init.c - initialize monitor backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/init.c,v 1.125.2.8 2009/01/22 00:01:08 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/init.c,v 1.125.2.10 2009/08/25 22:48:10 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2001-2009 The OpenLDAP Foundation.
@@ -322,13 +322,6 @@
 }
 
 int
-monitor_back_register_overlay(
-	BackendDB		*be )
-{
-	return -1;
-}
-
-int
 monitor_back_register_backend_limbo(
 	BackendInfo		*bi )
 {
@@ -338,7 +331,7 @@
 int
 monitor_back_register_database_limbo(
 	BackendDB		*be,
-	struct berval	*ndn )
+	struct berval		*ndn_out )
 {
 	entry_limbo_t	**elpp, el = { 0 };
 	monitor_info_t 	*mi;
@@ -357,7 +350,7 @@
 	el.el_type = LIMBO_DATABASE;
 
 	el.el_be = be->bd_self;
-	el.el_ndn = ndn;
+	el.el_ndn = ndn_out;
 	
 	for ( elpp = &mi->mi_entry_limbo;
 			*elpp;
@@ -381,9 +374,41 @@
 
 int
 monitor_back_register_overlay_limbo(
-	BackendDB		*be )
+	BackendDB		*be,
+	struct slap_overinst	*on,
+	struct berval		*ndn_out )
 {
-	return -1;
+	entry_limbo_t	**elpp, el = { 0 };
+	monitor_info_t 	*mi;
+
+	if ( be_monitor == NULL ) {
+		Debug( LDAP_DEBUG_ANY,
+			"monitor_back_register_overlay_limbo: "
+			"monitor database not configured.\n",
+			0, 0, 0 );
+		return -1;
+	}
+
+	mi = ( monitor_info_t * )be_monitor->be_private;
+
+
+	el.el_type = LIMBO_OVERLAY;
+
+	el.el_be = be->bd_self;
+	el.el_on = on;
+	el.el_ndn = ndn_out;
+	
+	for ( elpp = &mi->mi_entry_limbo;
+			*elpp;
+			elpp = &(*elpp)->el_next )
+		/* go to last */;
+
+	*elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) );
+
+	el.el_next = NULL;
+	**elpp = el;
+
+	return 0;
 }
 
 int
@@ -1903,6 +1928,15 @@
 			"SINGLE-VALUE "
 			"USAGE dSAOperation )", SLAP_AT_HIDE,
 			offsetof(monitor_info_t, mi_ad_monitorRuntimeConfig) },
+		{ "( 1.3.6.1.4.1.4203.666.1.55.30 "
+			"NAME 'monitorSuperiorDN' "
+			"DESC 'monitor superior DN' "
+			/* "SUP distinguishedName " */
+			"EQUALITY distinguishedNameMatch "
+			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
+			"NO-USER-MODIFICATION "
+			"USAGE dSAOperation )", SLAP_AT_FINAL|SLAP_AT_HIDE,
+			offsetof(monitor_info_t, mi_ad_monitorSuperiorDN) },
 		{ NULL, 0, -1 }
 	};
 
@@ -2356,8 +2390,7 @@
 	 * opens the monitor backend subsystems
 	 */
 	for ( ms = monitor_subsys; ms[ 0 ] != NULL; ms++ ) {
-		if ( ms[ 0 ]->mss_open && ( *ms[ 0 ]->mss_open )( be, ms[ 0 ] ) )
-		{
+		if ( ms[ 0 ]->mss_open && ms[ 0 ]->mss_open( be, ms[ 0 ] ) ) {
 			return( -1 );
 		}
 		ms[ 0 ]->mss_flags |= MONITOR_F_OPENED;
@@ -2425,7 +2458,7 @@
 				break;
 
 			case LIMBO_OVERLAY:
-				rc = monitor_back_register_overlay( el->el_be );
+				rc = monitor_back_register_overlay( el->el_be, el->el_on, el->el_ndn );
 				break;
 
 			default:

Modified: openldap/trunk/servers/slapd/back-monitor/proto-back-monitor.h
===================================================================
--- openldap/trunk/servers/slapd/back-monitor/proto-back-monitor.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-monitor/proto-back-monitor.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/proto-back-monitor.h,v 1.33.2.6 2009/01/22 00:01:08 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-monitor/proto-back-monitor.h,v 1.33.2.7 2009/08/25 22:48:10 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2001-2009 The OpenLDAP Foundation.
@@ -152,20 +152,24 @@
 	slap_overinst		*on ));
 extern int
 monitor_back_register_overlay LDAP_P((
-	BackendDB		*be ));
+	BackendDB		*be,
+	struct slap_overinst	*on,
+	struct berval		*ndn_out ));
 extern int
 monitor_back_register_backend_limbo LDAP_P((
 	BackendInfo		*bi ));
 extern int
 monitor_back_register_database_limbo LDAP_P((
 	BackendDB		*be,
-	struct berval	*ndn ));
+	struct berval		*ndn_out ));
 extern int
 monitor_back_register_overlay_info_limbo LDAP_P((
 	slap_overinst		*on ));
 extern int
 monitor_back_register_overlay_limbo LDAP_P((
-	BackendDB		*be ));
+	BackendDB		*be,
+	struct slap_overinst	*on,
+	struct berval		*ndn_out ));
 extern monitor_subsys_t *
 monitor_back_get_subsys LDAP_P((
 	const char		*name ));

Modified: openldap/trunk/servers/slapd/back-ndb/init.cpp
===================================================================
--- openldap/trunk/servers/slapd/back-ndb/init.cpp	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ndb/init.cpp	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* init.cpp - initialize ndb backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/init.cpp,v 1.4.2.2 2009/01/22 00:01:09 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/init.cpp,v 1.4.2.3 2009/07/22 19:45:56 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
@@ -130,7 +130,7 @@
 		}
 	}
 	for ( i=0; i<ni->ni_nconns; i++ ) {
-		rc = ni->ni_cluster[i]->wait_until_ready( 30, 0 );
+		rc = ni->ni_cluster[i]->wait_until_ready( 30, 30 );
 		if ( rc ) {
 			snprintf( cr->msg, sizeof( cr->msg ),
 				"ndb_db_open: ni_cluster[%d]->wait failed (%d)",

Modified: openldap/trunk/servers/slapd/back-ndb/search.cpp
===================================================================
--- openldap/trunk/servers/slapd/back-ndb/search.cpp	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-ndb/search.cpp	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* search.cpp - tools for slap tools */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/search.cpp,v 1.3.2.3 2009/06/12 18:36:51 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/search.cpp,v 1.3.2.4 2009/08/02 21:14:22 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2008-2009 The OpenLDAP Foundation.
@@ -445,7 +445,7 @@
 
 		dnNormalize( 0, NULL, NULL, &e.e_name, &e.e_nname, op->o_tmpmemctx );
 		{
-#ifdef notdef		/* NDBapi is broken here */
+#if 1	/* NDBapi was broken here but seems to work now */
 			Ndb::Key_part_ptr keys[2];
 			char xbuf[32];
 			keys[0].ptr = &eid;

Modified: openldap/trunk/servers/slapd/back-relay/back-relay.h
===================================================================
--- openldap/trunk/servers/slapd/back-relay/back-relay.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-relay/back-relay.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* back-relay.h - relay backend header file */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/back-relay.h,v 1.6.2.4 2009/01/22 00:01:09 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/back-relay.h,v 1.6.2.5 2009/08/12 23:57:40 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -28,12 +28,24 @@
 
 LDAP_BEGIN_DECL
 
+typedef enum relay_operation_e {
+	relay_op_entry_get = op_last,
+	relay_op_entry_release,
+	relay_op_has_subordinates,
+	relay_op_last
+} relay_operation_t;
+
 typedef struct relay_back_info {
 	BackendDB	*ri_bd;
 	struct berval	ri_realsuffix;
 	int		ri_massage;
 } relay_back_info;
 
+/* Pad relay_back_info if needed to create valid OpExtra key addresses */
+#define	RELAY_INFO_SIZE \
+	(sizeof(relay_back_info) > (size_t) relay_op_last ? \
+	 sizeof(relay_back_info) : (size_t) relay_op_last   )
+
 LDAP_END_DECL
 
 #endif /* SLAPD_RELAY_H */

Modified: openldap/trunk/servers/slapd/back-relay/init.c
===================================================================
--- openldap/trunk/servers/slapd/back-relay/init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-relay/init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* init.c - initialize relay backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/init.c,v 1.19.2.7 2009/02/20 00:26:02 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/init.c,v 1.19.2.8 2009/08/12 23:57:40 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -151,27 +151,18 @@
 	bi->bi_db_destroy = relay_back_db_destroy;
 
 	bi->bi_op_bind = relay_back_op_bind;
-	bi->bi_op_unbind = relay_back_op_unbind;
 	bi->bi_op_search = relay_back_op_search;
 	bi->bi_op_compare = relay_back_op_compare;
 	bi->bi_op_modify = relay_back_op_modify;
 	bi->bi_op_modrdn = relay_back_op_modrdn;
 	bi->bi_op_add = relay_back_op_add;
 	bi->bi_op_delete = relay_back_op_delete;
-	bi->bi_op_abandon = relay_back_op_abandon;
-	bi->bi_op_cancel = relay_back_op_cancel;
 	bi->bi_extended = relay_back_op_extended;
 	bi->bi_entry_release_rw = relay_back_entry_release_rw;
 	bi->bi_entry_get_rw = relay_back_entry_get_rw;
-#if 0	/* see comment in op.c */
-	bi->bi_chk_referrals = relay_back_chk_referrals;
-#endif
 	bi->bi_operational = relay_back_operational;
 	bi->bi_has_subordinates = relay_back_has_subordinates;
 
-	bi->bi_connection_init = relay_back_connection_init;
-	bi->bi_connection_destroy = relay_back_connection_destroy;
-
 	bi->bi_cf_ocs = relayocs;
 
 	return config_register_schema( relaycfg, relayocs );
@@ -184,7 +175,7 @@
 
 	be->be_private = NULL;
 
-	ri = (relay_back_info *)ch_calloc( 1, sizeof( relay_back_info ) );
+	ri = (relay_back_info *) ch_calloc( 1, RELAY_INFO_SIZE );
 	if ( ri == NULL ) {
  		return -1;
  	}
@@ -261,4 +252,3 @@
 SLAP_BACKEND_INIT_MODULE( relay )
 
 #endif /* SLAPD_RELAY == SLAPD_MOD_DYNAMIC */
-

Modified: openldap/trunk/servers/slapd/back-relay/op.c
===================================================================
--- openldap/trunk/servers/slapd/back-relay/op.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-relay/op.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* op.c - relay backend operations */
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/op.c,v 1.15.2.9 2009/06/02 23:08:35 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-relay/op.c,v 1.15.2.11 2009/08/12 23:58:52 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -26,135 +26,192 @@
 #include "slap.h"
 #include "back-relay.h"
 
-#define	RB_ERR_MASK		(0x0000FFFFU)
-#define RB_ERR			(0x10000000U)
-#define RB_UNSUPPORTED_FLAG	(0x20000000U)
-#define RB_REFERRAL		(0x40000000U)
-#define RB_SEND			(0x80000000U)
-#define RB_UNSUPPORTED		(LDAP_UNWILLING_TO_PERFORM|RB_ERR|RB_UNSUPPORTED_FLAG)
-#define	RB_UNSUPPORTED_SEND	(RB_UNSUPPORTED|RB_SEND)
-#define	RB_REFERRAL_SEND	(RB_REFERRAL|RB_SEND)
-#define	RB_ERR_SEND		(RB_ERR|RB_SEND)
-#define	RB_ERR_REFERRAL_SEND	(RB_ERR|RB_REFERRAL|RB_SEND)
+/* Results when no real database (.rf_bd) or operation handler (.rf_op) */
+static const struct relay_fail_modes_s {
+	slap_mask_t	rf_bd, rf_op;
+#define RB_ERR_MASK	0x0000FFFFU /* bitmask for default return value */
+#define RB_BDERR	0x80000000U /* use .rf_bd's default return value */
+#define RB_OPERR	0x40000000U /* set rs->sr_err = .rf_op return value */
+#define RB_REF		0x20000000U /* use default_referral if available */
+#define RB_SEND		0x10000000U /* send result; RB_??ERR is also set */
+#define RB_SENDREF	0/*unused*/ /* like RB_SEND when referral found */
+#define RB_NO_BIND	(RB_OPERR | LDAP_INVALID_CREDENTIALS)
+#define RB_NOT_SUPP	(RB_OPERR | LDAP_UNWILLING_TO_PERFORM)
+#define RB_NO_OBJ	(RB_REF | LDAP_NO_SUCH_OBJECT)
+#define RB_CHK_REF	(RB_REF | RB_SENDREF | LDAP_SUCCESS)
+} relay_fail_modes[relay_op_last] = {
+	/* .rf_bd is unused when zero, otherwise both fields have RB_BDERR */
+#	define RB_OP(b, o)	{ (b) | RB_BD2ERR(b), (o) | RB_BD2ERR(b) }
+#	define RB_BD2ERR(b)	((b) ? RB_BDERR : 0)
+	/* indexed by slap_operation_t: */
+	RB_OP(RB_NO_BIND|RB_SEND, RB_NO_BIND  |RB_SEND), /* Bind           */
+	RB_OP(0,                  LDAP_SUCCESS),         /* Unbind: unused */
+	RB_OP(RB_NO_OBJ |RB_SEND, RB_NOT_SUPP |RB_SEND), /* Search         */
+	RB_OP(RB_NO_OBJ |RB_SEND, SLAP_CB_CONTINUE),     /* Compare        */
+	RB_OP(RB_NO_OBJ |RB_SEND, RB_NOT_SUPP |RB_SEND), /* Modify         */
+	RB_OP(RB_NO_OBJ |RB_SEND, RB_NOT_SUPP |RB_SEND), /* Modrdn         */
+	RB_OP(RB_NO_OBJ |RB_SEND, RB_NOT_SUPP |RB_SEND), /* Add            */
+	RB_OP(RB_NO_OBJ |RB_SEND, RB_NOT_SUPP |RB_SEND), /* Delete         */
+	RB_OP(0,                  LDAP_SUCCESS),         /* Abandon:unused */
+	RB_OP(RB_NO_OBJ,          RB_NOT_SUPP),          /* Extended       */
+	RB_OP(0,                  SLAP_CB_CONTINUE),     /* Cancel: unused */
+	RB_OP(0,                  LDAP_SUCCESS),    /* operational         */
+	RB_OP(RB_CHK_REF,         LDAP_SUCCESS),    /* chk_referrals:unused*/
+	RB_OP(0,                  SLAP_CB_CONTINUE),/* chk_controls:unused */
+	/* additional relay_operation_t indexes from back-relay.h: */
+	RB_OP(0,                  0/*unused*/),     /* entry_get = op_last */
+	RB_OP(0,                  0/*unused*/),     /* entry_release       */
+	RB_OP(0,                  0/*unused*/),     /* has_subordinates    */
+};
 
-static int
-relay_back_swap_bd( Operation *op, SlapReply *rs )
+/*
+ * Callbacks: Caller changed op->o_bd from Relay to underlying
+ * BackendDB.  sc_response sets it to Relay BackendDB, sc_cleanup puts
+ * back underlying BackendDB.  Caller will restore Relay BackendDB.
+ */
+
+typedef struct relay_callback {
+	slap_callback rcb_sc;
+	BackendDB *rcb_bd;
+} relay_callback;
+
+int
+relay_back_cleanup_cb( Operation *op, SlapReply *rs )
 {
-	slap_callback	*cb = op->o_callback;
-	BackendDB	*be = op->o_bd;
+	op->o_bd = ((relay_callback *) op->o_callback)->rcb_bd;
+	return SLAP_CB_CONTINUE;
+}
 
-	op->o_bd = cb->sc_private;
-	cb->sc_private = be;
+int
+relay_back_response_cb( Operation *op, SlapReply *rs )
+{
+	relay_callback	*rcb = (relay_callback *) op->o_callback;
 
+	rcb->rcb_sc.sc_cleanup = relay_back_cleanup_cb;
+	rcb->rcb_bd = op->o_bd;
+	op->o_bd = op->o_callback->sc_private;
 	return SLAP_CB_CONTINUE;
 }
 
-#define relay_back_add_cb( cb, op ) \
-	{						\
-		(cb)->sc_next = (op)->o_callback;	\
-		(cb)->sc_response = relay_back_swap_bd;	\
-		(cb)->sc_cleanup = relay_back_swap_bd;	\
-		(cb)->sc_private = (op)->o_bd;		\
-		(op)->o_callback = (cb);		\
+#define relay_back_add_cb( rcb, op, bd )			\
+	{							\
+		(rcb)->rcb_sc.sc_next = (op)->o_callback;	\
+		(rcb)->rcb_sc.sc_response = relay_back_response_cb; \
+		(rcb)->rcb_sc.sc_cleanup = 0;			\
+		(rcb)->rcb_sc.sc_private = (op)->o_bd;		\
+		(op)->o_callback = (slap_callback *) (rcb);	\
 	}
 
 /*
- * selects the backend if not enforced at config;
- * in case of failure, behaves based on err:
- *	-1			don't send result
- *	LDAP_SUCCESS		don't send result; may send referral if dosend
- *	any valid error 	send as error result if dosend
+ * Select the backend database with the operation's DN.  On failure,
+ * set/send results depending on operation type <which>'s fail_modes.
  */
 static BackendDB *
-relay_back_select_backend( Operation *op, SlapReply *rs, slap_mask_t fail_mode )
+relay_back_select_backend( Operation *op, SlapReply *rs, int which )
 {
-	relay_back_info		*ri = (relay_back_info *)op->o_bd->be_private;
-	BackendDB		*bd = ri->ri_bd;
-	int			rc = ( fail_mode & RB_ERR_MASK );
+	OpExtra		*oex;
+	char		*key = (char *) op->o_bd->be_private;
+	BackendDB	*bd  = ((relay_back_info *) key)->ri_bd;
+	slap_mask_t	fail_mode = relay_fail_modes[which].rf_bd;
+	int		useDN = 0, rc = ( fail_mode & RB_ERR_MASK );
 
 	if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) {
+		useDN = 1;
 		bd = select_backend( &op->o_req_ndn, 1 );
-		if ( bd->be_private == op->o_bd->be_private ) {
-			Debug( LDAP_DEBUG_ANY,
-				"%s: back-relay for DN=\"%s\" would call self.\n",
-				op->o_log_prefix, op->o_req_dn.bv_val, 0 );
-			if ( fail_mode & RB_ERR ) {
-				rs->sr_err = rc;
-				if ( fail_mode & RB_SEND ) {
-					send_ldap_result( op, rs );
-				}
-			}
+	}
 
-			return NULL;
+	if ( bd != NULL ) {
+		key += which; /* <relay, op type> key from RELAY_WRAP_OP() */
+		LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+			if ( oex->oe_key == key )
+				break;
 		}
-	}
+		if ( oex == NULL ) {
+			return bd;
+		}
 
-	if ( bd == NULL ) {
-		if ( ( fail_mode & RB_REFERRAL )
-			&& ( fail_mode & RB_SEND )
-			&& !BER_BVISNULL( &op->o_req_ndn )
-			&& default_referral )
-		{
-			rs->sr_err = LDAP_REFERRAL;
+		Debug( LDAP_DEBUG_ANY,
+			"%s: back-relay for DN=\"%s\" would call self.\n",
+			op->o_log_prefix, op->o_req_dn.bv_val, 0 );
 
-			/* if we set sr_err to LDAP_REFERRAL,
-			 * we must provide one */
-			rs->sr_ref = referral_rewrite(
-				default_referral,
-				NULL, &op->o_req_dn,
-				LDAP_SCOPE_DEFAULT );
-			if ( !rs->sr_ref ) {
-				rs->sr_ref = default_referral;
-			}
+	} else if ( useDN && ( fail_mode & RB_REF ) && default_referral ) {
+		rc = LDAP_REFERRAL;
 
-			send_ldap_result( op, rs );
-
-			if ( rs->sr_ref != default_referral ) {
-				ber_bvarray_free( rs->sr_ref );
-			}
-
-			return NULL;
+		/* if we set sr_err to LDAP_REFERRAL, we must provide one */
+		rs->sr_ref = referral_rewrite(
+			default_referral, NULL, &op->o_req_dn,
+			op->o_tag == LDAP_REQ_SEARCH ?
+			op->ors_scope : LDAP_SCOPE_DEFAULT );
+		if ( rs->sr_ref != NULL ) {
+			rs->sr_flags |= REP_REF_MUSTBEFREED;
+		} else {
+			rs->sr_ref = default_referral;
 		}
 
-		/* NOTE: err is LDAP_INVALID_CREDENTIALS for bind,
-		 * LDAP_NO_SUCH_OBJECT for other operations.
-		 * noSuchObject cannot be returned by bind */
+		if ( fail_mode & RB_SENDREF )
+			fail_mode = (RB_BDERR | RB_SEND);
+	}
+
+	if ( fail_mode & RB_BDERR ) {
 		rs->sr_err = rc;
 		if ( fail_mode & RB_SEND ) {
 			send_ldap_result( op, rs );
 		}
 	}
 
-	return bd;
+	return NULL;
 }
 
+/*
+ * Forward <act> on <op> to database <bd>, with <relay, op type>-specific
+ * key in op->o_extra so relay_back_select_backend() can catch recursion.
+ */
+#define RELAY_WRAP_OP( op, bd, which, act ) { \
+	OpExtraDB wrap_oex; \
+	BackendDB *const wrap_bd = (op)->o_bd; \
+	wrap_oex.oe_db = wrap_bd; \
+	wrap_oex.oe.oe_key = (char *) wrap_bd->be_private + (which); \
+	LDAP_SLIST_INSERT_HEAD( &(op)->o_extra, &wrap_oex.oe, oe_next ); \
+	(op)->o_bd = (bd); \
+	act; \
+	(op)->o_bd = wrap_bd; \
+	LDAP_SLIST_REMOVE( &(op)->o_extra, &wrap_oex.oe, OpExtra, oe_next ); \
+}
+
+/*
+ * Forward backend function #<which> on <op> to operation DN's database
+ * like RELAY_WRAP_OP, after setting up callbacks. If no database or no
+ * backend function, set/send results depending on <which>'s fail_modes.
+ */
 static int
-relay_back_op(
-	Operation	*op,
-	SlapReply	*rs,
-	BackendDB	*bd,
-	BI_op_func	*func,
-	slap_mask_t	fail_mode )
+relay_back_op( Operation *op, SlapReply *rs, int which )
 {
-	int			rc = ( fail_mode & RB_ERR_MASK );
+	BackendDB	*bd;
+	BI_op_bind	*func;
+	slap_mask_t	fail_mode = relay_fail_modes[which].rf_op;
+	int		rc = ( fail_mode & RB_ERR_MASK );
 
-	if ( func ) {
-		BackendDB	*be = op->o_bd;
-		slap_callback	cb;
+	bd = relay_back_select_backend( op, rs, which );
+	if ( bd == NULL ) {
+		if ( fail_mode & RB_BDERR )
+			return rs->sr_err;	/* sr_err was set above */
 
-		relay_back_add_cb( &cb, op );
+	} else if ( (func = (&bd->be_bind)[which]) != 0 ) {
+		relay_callback	rcb;
 
-		op->o_bd = bd;
-		rc = func( op, rs );
-		op->o_bd = be;
+		relay_back_add_cb( &rcb, op, bd );
 
-		if ( op->o_callback == &cb ) {
+		RELAY_WRAP_OP( op, bd, which, {
+			rc = func( op, rs );
+		});
+
+		if ( op->o_callback == (slap_callback *) &rcb ) {
 			op->o_callback = op->o_callback->sc_next;
 		}
 
-	} else if ( fail_mode & RB_ERR ) {
+	} else if ( fail_mode & RB_OPERR ) {
 		rs->sr_err = rc;
-		if ( fail_mode & RB_UNSUPPORTED_FLAG ) {
+		if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
 			rs->sr_text = "operation not supported within naming context";
 		}
 
@@ -166,11 +223,10 @@
 	return rc;
 }
 
+
 int
 relay_back_op_bind( Operation *op, SlapReply *rs )
 {
-	BackendDB	*bd;
-
 	/* allow rootdn as a means to auth without the need to actually
  	 * contact the proxied DSA */
 	switch ( be_rootdn_bind( op, rs ) ) {
@@ -181,227 +237,64 @@
 		return rs->sr_err;
 	}
 
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_bind,
-		( LDAP_INVALID_CREDENTIALS | RB_ERR_SEND ) );
+	return relay_back_op( op, rs, op_bind );
 }
 
-int
-relay_back_op_unbind( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
+#define RELAY_DEFOP(func, which) \
+	int func( Operation *op, SlapReply *rs ) \
+	{ return relay_back_op( op, rs, which ); }
 
-	bd = relay_back_select_backend( op, rs, 0 );
-	if ( bd != NULL ) {
-		(void)relay_back_op( op, rs, bd, bd->be_unbind, 0 );
-	}
+RELAY_DEFOP( relay_back_op_search,		op_search )
+RELAY_DEFOP( relay_back_op_compare,		op_compare )
+RELAY_DEFOP( relay_back_op_modify,		op_modify )
+RELAY_DEFOP( relay_back_op_modrdn,		op_modrdn )
+RELAY_DEFOP( relay_back_op_add,			op_add )
+RELAY_DEFOP( relay_back_op_delete,		op_delete )
+RELAY_DEFOP( relay_back_op_extended,	op_extended )
+RELAY_DEFOP( relay_back_operational,	op_aux_operational )
 
-	return 0;
-}
+/* Abandon, Cancel, Unbind and some DN-less calls like be_connection_init
+ * need no extra handling:  slapd already calls them for all databases.
+ */
 
-int
-relay_back_op_search( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
 
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_search,
-		RB_UNSUPPORTED_SEND );
-}
-
 int
-relay_back_op_compare( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_compare,
-		( SLAP_CB_CONTINUE | RB_ERR ) );
-}
-
-int
-relay_back_op_modify( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_modify,
-		RB_UNSUPPORTED_SEND );
-}
-
-int
-relay_back_op_modrdn( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_modrdn,
-		RB_UNSUPPORTED_SEND );
-}
-
-int
-relay_back_op_add( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_add,
-		RB_UNSUPPORTED_SEND );
-}
-
-int
-relay_back_op_delete( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR_REFERRAL_SEND ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_delete,
-		RB_UNSUPPORTED_SEND );
-}
-
-int
-relay_back_op_abandon( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs, 0 );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_abandon, 0 );
-}
-
-int
-relay_back_op_cancel( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-	int			rc;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_CANNOT_CANCEL | RB_ERR ) );
-	if ( bd == NULL ) {
-		if ( op->o_cancel == SLAP_CANCEL_REQ ) {
-			op->o_cancel = LDAP_CANNOT_CANCEL;
-		}
-		return rs->sr_err;
-	}
-
-	rc = relay_back_op( op, rs, bd, bd->be_cancel,
-		( LDAP_CANNOT_CANCEL | RB_ERR ) );
-	if ( rc == LDAP_CANNOT_CANCEL && op->o_cancel == SLAP_CANCEL_REQ )
-	{
-		op->o_cancel = LDAP_CANNOT_CANCEL;
-	}
-
-	return rc;
-}
-
-int
-relay_back_op_extended( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_NO_SUCH_OBJECT | RB_ERR | RB_REFERRAL ) );
-	if ( bd == NULL ) {
-		return rs->sr_err;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_extended,
-		RB_UNSUPPORTED );
-}
-
-int
 relay_back_entry_release_rw( Operation *op, Entry *e, int rw )
 {
-	relay_back_info		*ri = (relay_back_info *)op->o_bd->be_private;
 	BackendDB		*bd;
-	int			rc = 1;
+	int			rc = LDAP_UNWILLING_TO_PERFORM;
 
-	bd = ri->ri_bd;
-	if ( bd == NULL) {
-		bd = select_backend( &op->o_req_ndn, 1 );
-		if ( bd == NULL ) {
-			return 1;
-		}
+	bd = relay_back_select_backend( op, NULL, relay_op_entry_release );
+	if ( bd && bd->be_release ) {
+		RELAY_WRAP_OP( op, bd, relay_op_entry_release, {
+			rc = bd->be_release( op, e, rw );
+		});
+	} else if ( e->e_private == NULL ) {
+		entry_free( e );
+		rc = LDAP_SUCCESS;
 	}
 
-	if ( bd->be_release ) {
-		BackendDB	*be = op->o_bd;
-
-		op->o_bd = bd;
-		rc = bd->be_release( op, e, rw );
-		op->o_bd = be;
-	}
-
 	return rc;
-
 }
 
 int
 relay_back_entry_get_rw( Operation *op, struct berval *ndn,
 	ObjectClass *oc, AttributeDescription *at, int rw, Entry **e )
 {
-	relay_back_info		*ri = (relay_back_info *)op->o_bd->be_private;
 	BackendDB		*bd;
-	int			rc = 1;
+	int			rc = LDAP_NO_SUCH_OBJECT;
 
-	bd = ri->ri_bd;
-	if ( bd == NULL) {
-		bd = select_backend( &op->o_req_ndn, 1 );
-		if ( bd == NULL ) {
-			return 1;
-		}
+	bd = relay_back_select_backend( op, NULL, relay_op_entry_get );
+	if ( bd && bd->be_fetch ) {
+		RELAY_WRAP_OP( op, bd, relay_op_entry_get, {
+			rc = bd->be_fetch( op, ndn, oc, at, rw, e );
+		});
 	}
 
-	if ( bd->be_fetch ) {
-		BackendDB	*be = op->o_bd;
-
-		op->o_bd = bd;
-		rc = bd->be_fetch( op, ndn, oc, at, rw, e );
-		op->o_bd = be;
-	}
-
 	return rc;
-
 }
 
+#if 0 /* Give the RB_SENDREF flag a nonzero value if implementing this */
 /*
  * NOTE: even the existence of this function is questionable: we cannot
  * pass the bi_chk_referrals() call thru the rwm overlay because there
@@ -409,110 +302,26 @@
  * is passing the target database a DN that likely does not belong to its
  * naming context... mmmh.
  */
-int
-relay_back_chk_referrals( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
+RELAY_DEFOP( relay_back_chk_referrals, op_aux_chk_referrals )
+#endif /*0*/
 
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_SUCCESS | RB_ERR_REFERRAL_SEND ) );
-	/* FIXME: this test only works if there are no overlays, so
-	 * it is nearly useless; if made stricter, no nested back-relays
-	 * can be instantiated... too bad. */
-	if ( bd == NULL || bd == op->o_bd ) {
-		return 0;
-	}
-
-	/* no nested back-relays... */
-	if ( overlay_is_over( bd ) ) {
-		slap_overinfo	*oi = (slap_overinfo *)bd->bd_info->bi_private;
-
-		if ( oi->oi_orig == op->o_bd->bd_info ) {
-			return 0;
-		}
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_chk_referrals, LDAP_SUCCESS );
-}
-
 int
-relay_back_operational( Operation *op, SlapReply *rs )
-{
-	BackendDB		*bd;
-
-	bd = relay_back_select_backend( op, rs,
-		( LDAP_SUCCESS | RB_ERR ) );
-	/* FIXME: this test only works if there are no overlays, so
-	 * it is nearly useless; if made stricter, no nested back-relays
-	 * can be instantiated... too bad. */
-	if ( bd == NULL || bd == op->o_bd ) {
-		return 0;
-	}
-
-	return relay_back_op( op, rs, bd, bd->be_operational, 0 );
-}
-
-int
 relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs )
 {
-	SlapReply		rs = { 0 };
 	BackendDB		*bd;
 	int			rc = LDAP_OTHER;
 
-	bd = relay_back_select_backend( op, &rs, LDAP_OTHER );
-	/* FIXME: this test only works if there are no overlays, so
-	 * it is nearly useless; if made stricter, no nested back-relays
-	 * can be instantiated... too bad. */
-	if ( bd == NULL || bd == op->o_bd ) {
-		return LDAP_OTHER;
+	bd = relay_back_select_backend( op, NULL, relay_op_has_subordinates );
+	if ( bd && bd->be_has_subordinates ) {
+		RELAY_WRAP_OP( op, bd, relay_op_has_subordinates, {
+			rc = bd->be_has_subordinates( op, e, hasSubs );
+		});
 	}
 
-	if ( bd->be_has_subordinates ) {
-		BackendDB	*be = op->o_bd;
-
-		op->o_bd = bd;
-		rc = bd->be_has_subordinates( op, e, hasSubs );
-		op->o_bd = be;
-	}
-
 	return rc;
 }
 
-int
-relay_back_connection_init( BackendDB *bd, Connection *c )
-{
-	relay_back_info		*ri = (relay_back_info *)bd->be_private;
 
-	bd = ri->ri_bd;
-	if ( bd == NULL ) {
-		return 0;
-	}
-
-	if ( bd->be_connection_init ) {
-		return bd->be_connection_init( bd, c );
-	}
-
-	return 0;
-}
-
-int
-relay_back_connection_destroy( BackendDB *bd, Connection *c )
-{
-	relay_back_info		*ri = (relay_back_info *)bd->be_private;
-
-	bd = ri->ri_bd;
-	if ( bd == NULL ) {
-		return 0;
-	}
-
-	if ( bd->be_connection_destroy ) {
-		return bd->be_connection_destroy( bd, c );
-	}
-
-	return 0;
-
-}
-
 /*
  * FIXME: must implement tools as well
  */

Modified: openldap/trunk/servers/slapd/back-sql/entry-id.c
===================================================================
--- openldap/trunk/servers/slapd/back-sql/entry-id.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-sql/entry-id.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/entry-id.c,v 1.67.2.8 2009/02/17 19:14:41 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/entry-id.c,v 1.67.2.10 2009/08/14 21:04:55 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -934,15 +934,7 @@
 	memset( bsi->bsi_e, 0, sizeof( Entry ) );
 
 	if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
-		Entry	*e;
-
-		e = entry_dup( bi->sql_baseObject );
-		if ( e == NULL ) {
-			return LDAP_NO_MEMORY;
-		}
-			
-		*bsi->bsi_e = *e;
-		free( e );
+		(void)entry_dup2( bsi->bsi_e, bi->sql_baseObject );
 		goto done;
 	}
 

Modified: openldap/trunk/servers/slapd/back-sql/search.c
===================================================================
--- openldap/trunk/servers/slapd/back-sql/search.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/back-sql/search.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/search.c,v 1.117.2.11 2009/06/02 22:28:46 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/search.c,v 1.117.2.12 2009/08/13 00:28:18 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1999-2009 The OpenLDAP Foundation.
@@ -721,6 +721,16 @@
 		goto done;
 	}
 
+	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
+		backsql_strfcat_x( &bsi->bsi_flt_where,
+			bsi->bsi_op->o_tmpmemctx,
+			"l",
+			(ber_len_t)STRLENOF( "1=0" ), "1=0" );
+		done = 1;
+		rc = 1;
+		goto done;
+	}
+
 	switch( f->f_choice ) {
 	case LDAP_FILTER_OR:
 		rc = backsql_process_filter_list( bsi, f->f_or, 
@@ -1196,6 +1206,14 @@
 				&at->bam_join_where );
 	}
 
+	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
+		backsql_strfcat_x( &bsi->bsi_flt_where,
+			bsi->bsi_op->o_tmpmemctx,
+			"l",
+			(ber_len_t)STRLENOF( "1=0" ), "1=0" );
+		return 1;
+	}
+
 	switch ( f->f_choice ) {
 	case LDAP_FILTER_EQUALITY:
 		filter_value = &f->f_av_value;

Modified: openldap/trunk/servers/slapd/backend.c
===================================================================
--- openldap/trunk/servers/slapd/backend.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/backend.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* backend.c - routines for dealing with back-end databases */
-/* $OpenLDAP: pkg/ldap/servers/slapd/backend.c,v 1.362.2.27 2009/05/18 17:51:55 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/backend.c,v 1.362.2.28 2009/08/25 23:10:31 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -226,9 +226,22 @@
 			(void)backend_set_controls( be );
 
 		} else {
+			char *type = be->bd_info->bi_type;
+			char *suffix = "(null)";
+
+			if ( overlay_is_over( be ) ) {
+				slap_overinfo	*oi = (slap_overinfo *)be->bd_info->bi_private;
+				type = oi->oi_orig->bi_type;
+			}
+
+			if ( be->be_suffix != NULL && !BER_BVISNULL( &be->be_suffix[0] ) ) {
+				suffix = be->be_suffix[0].bv_val;
+			}
+
 			Debug( LDAP_DEBUG_ANY,
-				"backend_startup_one: bi_db_open failed! (%d)\n",
-				rc, 0, 0 );
+				"backend_startup_one (type=%s, suffix=\"%s\"): "
+				"bi_db_open failed! (%d)\n",
+				type, suffix, rc );
 		}
 	}
 

Modified: openldap/trunk/servers/slapd/backover.c
===================================================================
--- openldap/trunk/servers/slapd/backover.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/backover.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* backover.c - backend overlay routines */
-/* $OpenLDAP: pkg/ldap/servers/slapd/backover.c,v 1.71.2.19 2009/02/20 00:26:01 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/backover.c,v 1.71.2.20 2009/08/25 21:36:51 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -699,7 +699,7 @@
 	slap_overinfo *oi;
 	slap_overinst *on;
 	BackendDB *be = op->o_bd, db;
-	slap_callback cb = {NULL, over_back_response, NULL, NULL};
+	slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc;
 	int rc = SLAP_CB_CONTINUE;
 
 	/* FIXME: used to happen for instance during abandon
@@ -719,9 +719,14 @@
 	op->o_callback = &cb;
 
 	rc = overlay_op_walk( op, rs, which, oi, on );
+	for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
+		if ( *sc == &cb ) {
+			*sc = cb.sc_next;
+			break;
+		}
+	}
 
 	op->o_bd = be;
-	op->o_callback = cb.sc_next;
 	return rc;
 }
 

Modified: openldap/trunk/servers/slapd/bconfig.c
===================================================================
--- openldap/trunk/servers/slapd/bconfig.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/bconfig.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* bconfig.c - the config backend */
-/* $OpenLDAP: pkg/ldap/servers/slapd/bconfig.c,v 1.202.2.68 2009/06/08 18:24:59 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/bconfig.c,v 1.202.2.74 2009/08/25 22:44:24 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2005-2009 The OpenLDAP Foundation.
@@ -120,6 +120,9 @@
 static ConfigDriver config_overlay;
 static ConfigDriver config_subordinate; 
 static ConfigDriver config_suffix; 
+#ifdef LDAP_TCP_BUFFER
+static ConfigDriver config_tcp_buffer; 
+#endif /* LDAP_TCP_BUFFER */
 static ConfigDriver config_rootdn;
 static ConfigDriver config_rootpw;
 static ConfigDriver config_restrict;
@@ -261,6 +264,7 @@
  * OLcfgOv{Oc|At}:18			-> memberof
  * OLcfgOv{Oc|At}:19			-> collect
  * OLcfgOv{Oc|At}:20			-> retcode
+ * OLcfgOv{Oc|At}:21			-> sssvlv
  */
 
 /* alphabetical ordering */
@@ -373,10 +377,10 @@
 	{ "include", "file", 2, 2, 0, ARG_MAGIC,
 		&config_include, "( OLcfgGlAt:19 NAME 'olcInclude' "
 			"SUP labeledURI )", NULL, NULL },
-	{ "index_substr_if_minlen", "min", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
+	{ "index_substr_if_minlen", "min", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
 		&config_generic, "( OLcfgGlAt:20 NAME 'olcIndexSubstrIfMinLen' "
 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-	{ "index_substr_if_maxlen", "max", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
+	{ "index_substr_if_maxlen", "max", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
 		&config_generic, "( OLcfgGlAt:21 NAME 'olcIndexSubstrIfMaxLen' "
 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
 	{ "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
@@ -603,6 +607,15 @@
 		&syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
 			"EQUALITY caseIgnoreMatch "
 			"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
+	{ "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
+#ifndef LDAP_TCP_BUFFER
+		ARG_IGNORED, NULL,
+#else /* LDAP_TCP_BUFFER */
+		ARG_MAGIC, &config_tcp_buffer,
+#endif /* LDAP_TCP_BUFFER */
+			"( OLcfgGlAt:90 NAME 'olcTCPBuffer' "
+			"DESC 'Custom TCP buffer size' "
+			"SYNTAX OMsDirectoryString )", NULL, NULL },
 	{ "threads", "count", 2, 2, 0,
 #ifdef NO_THREADS
 		ARG_IGNORED, NULL,
@@ -771,6 +784,7 @@
 		 "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
 		 "olcSecurity $ olcServerID $ olcSizeLimit $ "
 		 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
+		 "olcTCPBuffer $ "
 		 "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
 		 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
 		 "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
@@ -1080,10 +1094,10 @@
 			c->value_int = (SLAP_DBMONITORING(c->be) != 0);
 			break;
 		case CFG_SSTR_IF_MAX:
-			c->value_int = index_substr_if_maxlen;
+			c->value_uint = index_substr_if_maxlen;
 			break;
 		case CFG_SSTR_IF_MIN:
-			c->value_int = index_substr_if_minlen;
+			c->value_uint = index_substr_if_minlen;
 			break;
 		case CFG_IX_INTLEN:
 			c->value_int = index_intlen;
@@ -1823,66 +1837,13 @@
 				*sip = si;
 
 				if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
-					Listener **l = slapd_get_listeners();
-					int i, isMe = 0;
-
-					/* Try a straight compare with Listener strings */
-					for ( i=0; l && l[i]; i++ ) {
-						if ( !strcasecmp( c->argv[2], l[i]->sl_url.bv_val )) {
-							isMe = 1;
-							break;
-						}
-					}
-
-					/* If hostname is empty, or is localhost, or matches
-					 * our hostname, this serverID refers to this host.
-					 * Compare it against listeners and ports.
-					 */
-					if ( !isMe && ( !lud->lud_host || !lud->lud_host[0] ||
-						!strncasecmp("localhost", lud->lud_host,
-							STRLENOF("localhost")) ||
-						!strcasecmp( global_host, lud->lud_host ))) {
-
-						for ( i=0; l && l[i]; i++ ) {
-							LDAPURLDesc *lu2;
-							ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
-							do {
-								if ( strcasecmp( lud->lud_scheme,
-									lu2->lud_scheme ))
-									break;
-								if ( lud->lud_port != lu2->lud_port )
-									break;
-								/* Listener on ANY address */
-								if ( !lu2->lud_host || !lu2->lud_host[0] ) {
-									isMe = 1;
-									break;
-								}
-								/* URL on ANY address */
-								if ( !lud->lud_host || !lud->lud_host[0] ) {
-									isMe = 1;
-									break;
-								}
-								/* Listener has specific host, must
-								 * match it
-								 */
-								if ( !strcasecmp( lud->lud_host,
-									lu2->lud_host )) {
-									isMe = 1;
-									break;
-								}
-							} while(0);
-							ldap_free_urldesc( lu2 );
-							if ( isMe ) {
-								break;
-							}
-						}
-					}
-					if ( isMe ) {
+					Listener *l = config_check_my_url( c->argv[2], lud );
+					if ( l ) {
 						slap_serverID = si->si_num;
 						Debug( LDAP_DEBUG_CONFIG,
 							"%s: SID=%d (listener=%s)\n",
 							c->log, slap_serverID,
-							l[i]->sl_url.bv_val );
+							l->sl_url.bv_val );
 					}
 				}
 				if ( c->argc > 2 )
@@ -1911,7 +1872,7 @@
 			break;
 
 		case CFG_MIRRORMODE:
-			if(!SLAP_SHADOW(c->be)) {
+			if(c->value_int && !SLAP_SHADOW(c->be)) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow",
 					c->argv[0] );
 				Debug(LDAP_DEBUG_ANY, "%s: %s\n",
@@ -1939,23 +1900,23 @@
 			break;
 
 		case CFG_SSTR_IF_MAX:
-			if (c->value_int < index_substr_if_minlen) {
+			if (c->value_uint < index_substr_if_minlen) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
 				Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
 					c->log, c->cr_msg, c->value_int );
 				return(1);
 			}
-			index_substr_if_maxlen = c->value_int;
+			index_substr_if_maxlen = c->value_uint;
 			break;
 
 		case CFG_SSTR_IF_MIN:
-			if (c->value_int > index_substr_if_maxlen) {
+			if (c->value_uint > index_substr_if_maxlen) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
 				Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
 					c->log, c->cr_msg, c->value_int );
 				return(1);
 			}
-			index_substr_if_minlen = c->value_int;
+			index_substr_if_minlen = c->value_uint;
 			break;
 
 #ifdef SLAPD_MODULES
@@ -2324,7 +2285,7 @@
 config_subordinate(ConfigArgs *c)
 {
 	int rc = 1;
-	int advertise;
+	int advertise = 0;
 
 	switch( c->op ) {
 	case SLAP_CONFIG_EMIT:
@@ -2349,14 +2310,372 @@
 		break;
 	case LDAP_MOD_ADD:
 	case SLAP_CONFIG_ADD:
-		advertise = ( c->argc == 2 && !strcasecmp( c->argv[1], "advertise" ));
+		if ( c->be->be_nsuffix == NULL ) {
+			/* log error */
+			snprintf( c->cr_msg, sizeof( c->cr_msg),
+				"subordinate configuration needs a suffix" );
+			Debug( LDAP_DEBUG_ANY,
+				"%s: %s.\n",
+				c->log, c->cr_msg, 0 );
+			rc = 1;
+			break;
+		}
+
+		if ( c->argc == 2 ) {
+			if ( strcasecmp( c->argv[1], "advertise" ) == 0 ) {
+				advertise = 1;
+
+			} else if ( strcasecmp( c->argv[1], "TRUE" ) != 0 ) {
+				/* log error */
+				snprintf( c->cr_msg, sizeof( c->cr_msg),
+					"subordinate must be \"TRUE\" or \"advertise\"" );
+				Debug( LDAP_DEBUG_ANY,
+					"%s: suffix \"%s\": %s.\n",
+					c->log, c->be->be_suffix[0].bv_val, c->cr_msg );
+				rc = 1;
+				break;
+			}
+		}
+
 		rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c ));
 		break;
 	}
+
 	return rc;
 }
 
+/*
+ * [listener=<listener>] [{read|write}=]<size>
+ */
+
+#ifdef LDAP_TCP_BUFFER
+static BerVarray tcp_buffer;
+int tcp_buffer_num;
+
+#define SLAP_TCP_RMEM (0x1U)
+#define SLAP_TCP_WMEM (0x2U)
+
 static int
+tcp_buffer_parse( struct berval *val, int argc, char **argv,
+		int *size, int *rw, Listener **l )
+{
+	int i, rc = LDAP_SUCCESS;
+	LDAPURLDesc *lud = NULL;
+	char *ptr;
+
+	if ( val != NULL && argv == NULL ) {
+		char *s = val->bv_val;
+
+		argv = ldap_str2charray( s, " \t" );
+		if ( argv == NULL ) {
+			return LDAP_OTHER;
+		}
+	}
+
+	i = 0;
+	if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) )
+		== 0 )
+	{
+		char *url = argv[ i ] + STRLENOF( "listener=" );
+		
+		if ( ldap_url_parse( url, &lud ) ) {
+			rc = LDAP_INVALID_SYNTAX;
+			goto done;
+		}
+
+		*l = config_check_my_url( url, lud );
+		if ( *l == NULL ) {
+			rc = LDAP_NO_SUCH_ATTRIBUTE;
+			goto done;
+		}
+
+		i++;
+	}
+
+	ptr = argv[ i ];
+	if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) {
+		*rw |= SLAP_TCP_RMEM;
+		ptr += STRLENOF( "read=" );
+
+	} else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) {
+		*rw |= SLAP_TCP_WMEM;
+		ptr += STRLENOF( "write=" );
+
+	} else {
+		*rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
+	}
+
+	/* accept any base */
+	if ( lutil_atoix( size, ptr, 0 ) ) {
+		rc = LDAP_INVALID_SYNTAX;
+		goto done;
+	}
+
+done:;
+	if ( val != NULL && argv != NULL ) {
+		ldap_charray_free( argv );
+	}
+
+	if ( lud != NULL ) {
+		ldap_free_urldesc( lud );
+	}
+
+	return rc;
+}
+
+static int
+tcp_buffer_delete_one( struct berval *val )
+{
+	int rc = 0;
+	int size = -1, rw = 0;
+	Listener *l = NULL;
+
+	rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
+	if ( rc != 0 ) {
+		return rc;
+	}
+
+	if ( l != NULL ) {
+		int i;
+		Listener **ll = slapd_get_listeners();
+
+		for ( i = 0; ll[ i ] != NULL; i++ ) {
+			if ( ll[ i ] == l ) break;
+		}
+
+		if ( ll[ i ] == NULL ) {
+			return LDAP_NO_SUCH_ATTRIBUTE;
+		}
+
+		if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
+		if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
+
+		for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
+			if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1;
+			if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1;
+		}
+
+	} else {
+		/* NOTE: this affects listeners without a specific setting,
+		 * does not reset all listeners.  If a listener without
+		 * specific settings was assigned a buffer because of
+		 * a global setting, it will not be reset.  In any case,
+		 * buffer changes will only take place at restart. */
+		if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
+		if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
+	}
+
+	return rc;
+}
+
+static int
+tcp_buffer_delete( BerVarray vals )
+{
+	int i;
+
+	for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
+		tcp_buffer_delete_one( &vals[ i ] );
+	}
+
+	return 0;
+}
+
+static int
+tcp_buffer_unparse( int idx, int size, int rw, Listener *l, struct berval *val )
+{
+	char buf[sizeof("2147483648")], *ptr;
+
+	/* unparse for later use */
+	val->bv_len = snprintf( buf, sizeof( buf ), "%d", size );
+	if ( l != NULL ) {
+		val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len;
+	}
+
+	if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
+		if ( rw & SLAP_TCP_RMEM ) {
+			val->bv_len += STRLENOF( "read=" );
+		} else if ( rw & SLAP_TCP_WMEM ) {
+			val->bv_len += STRLENOF( "write=" );
+		}
+	}
+
+	val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
+
+	ptr = val->bv_val;
+
+	if ( l != NULL ) {
+		ptr = lutil_strcopy( ptr, "listener=" );
+		ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
+		*ptr++ = ' ';
+	}
+
+	if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
+		if ( rw & SLAP_TCP_RMEM ) {
+			ptr = lutil_strcopy( ptr, "read=" );
+		} else if ( rw & SLAP_TCP_WMEM ) {
+			ptr = lutil_strcopy( ptr, "write=" );
+		}
+	}
+
+	ptr = lutil_strcopy( ptr, buf );
+	*ptr = '\0';
+
+	assert( val->bv_val + val->bv_len == ptr );
+
+	return LDAP_SUCCESS;
+}
+
+static int
+tcp_buffer_add_one( int argc, char **argv, int idx )
+{
+	int rc = 0;
+	int size = -1, rw = 0;
+	Listener *l = NULL;
+
+	struct berval val;
+
+	/* parse */
+	rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
+	if ( rc != 0 ) {
+		return rc;
+	}
+
+	/* unparse for later use */
+	rc = tcp_buffer_unparse( idx, size, rw, l, &val );
+	if ( rc != LDAP_SUCCESS ) {
+		return rc;
+	}
+
+	/* use parsed values */
+	if ( l != NULL ) {
+		int i;
+		Listener **ll = slapd_get_listeners();
+
+		for ( i = 0; ll[ i ] != NULL; i++ ) {
+			if ( ll[ i ] == l ) break;
+		}
+
+		if ( ll[ i ] == NULL ) {
+			return LDAP_NO_SUCH_ATTRIBUTE;
+		}
+
+		/* buffer only applies to TCP listeners;
+		 * we do not do any check here, and delegate them
+		 * to setsockopt(2) */
+		if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
+		if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
+
+		for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
+			if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size;
+			if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size;
+		}
+
+	} else {
+		/* NOTE: this affects listeners without a specific setting,
+		 * does not set all listeners */
+		if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
+		if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
+	}
+
+	tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) );
+	/* append */
+	idx = tcp_buffer_num;
+	tcp_buffer[ idx ] = val;
+
+	tcp_buffer_num++;
+	BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] );
+
+	return rc;
+}
+
+static int
+config_tcp_buffer( ConfigArgs *c )
+{
+	if ( c->op == SLAP_CONFIG_EMIT ) {
+		if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) {
+			return 1;
+		}
+		value_add( &c->rvalue_vals, tcp_buffer );
+		value_add( &c->rvalue_nvals, tcp_buffer );
+		
+	} else if ( c->op == LDAP_MOD_DELETE ) {
+		if ( !c->line  ) {
+			tcp_buffer_delete( tcp_buffer );
+			ber_bvarray_free( tcp_buffer );
+			tcp_buffer = NULL;
+			tcp_buffer_num = 0;
+
+		} else {
+			int rc = 0;
+			int size = -1, rw = 0;
+			Listener *l = NULL;
+
+			struct berval val = BER_BVNULL;
+
+			int i;
+
+			if ( tcp_buffer_num == 0 ) {
+				return 1;
+			}
+
+			/* parse */
+			rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l );
+			if ( rc != 0 ) {
+				return 1;
+			}
+
+			/* unparse for later use */
+			rc = tcp_buffer_unparse( tcp_buffer_num, size, rw, l, &val );
+			if ( rc != LDAP_SUCCESS ) {
+				return 1;
+			}
+
+			for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) {
+				if ( bvmatch( &tcp_buffer[ i ], &val ) ) {
+					break;
+				}
+			}
+
+			if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) {
+				/* not found */
+				rc = 1;
+				goto done;
+			}
+
+			tcp_buffer_delete_one( &tcp_buffer[ i ] );
+			ber_memfree( tcp_buffer[ i ].bv_val );
+			for ( ; i < tcp_buffer_num; i++ ) {
+				tcp_buffer[ i ] = tcp_buffer[ i + 1 ];
+			}
+			tcp_buffer_num--;
+
+done:;
+			if ( !BER_BVISNULL( &val ) ) {
+				SLAP_FREE( val.bv_val );
+			}
+	
+		}
+
+	} else {
+		int rc;
+		int idx;
+
+		rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ], idx );
+		if ( rc ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"<%s> unable to add value #%d",
+				c->argv[0], idx );
+			Debug( LDAP_DEBUG_ANY, "%s: %s\n",
+				c->log, c->cr_msg, 0 );
+			return 1;
+		}
+	}
+
+	return 0;
+}
+#endif /* LDAP_TCP_BUFFER */
+
+static int
 config_suffix(ConfigArgs *c)
 {
 	Backend *tbe;
@@ -3112,7 +3431,7 @@
 }
 
 int
-config_shadow( ConfigArgs *c, int flag )
+config_shadow( ConfigArgs *c, slap_mask_t flag )
 {
 	char	*notallowed = NULL;
 
@@ -3131,7 +3450,8 @@
 	if ( SLAP_SHADOW(c->be) ) {
 		/* if already shadow, only check consistency */
 		if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
-			Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%x.\n", c->log, flag, 0 );
+			Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n",
+				c->log, flag, 0 );
 			return 1;
 		}
 

Modified: openldap/trunk/servers/slapd/config.c
===================================================================
--- openldap/trunk/servers/slapd/config.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/config.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* config.c - configuration file handling routines */
-/* $OpenLDAP: pkg/ldap/servers/slapd/config.c,v 1.441.2.24 2009/06/02 23:41:32 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/config.c,v 1.441.2.26 2009/08/02 21:26:43 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -128,6 +128,7 @@
 	int rc, arg_user, arg_type, arg_syn, iarg;
 	unsigned uiarg;
 	long larg;
+	unsigned long ularg;
 	ber_len_t barg;
 	
 	if(Conf->arg_type == ARG_IGNORED) {
@@ -260,6 +261,16 @@
 					return(ARG_BAD_CONF);
 				}
 				break;
+			case ARG_ULONG:
+				if ( lutil_atoulx( &ularg, c->argv[1], 0 ) != 0 ) {
+					snprintf( c->cr_msg, sizeof( c->cr_msg ),
+						"<%s> unable to parse \"%s\" as unsigned long",
+						c->argv[0], c->argv[1] );
+					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
+						c->log, c->cr_msg, 0);
+					return(ARG_BAD_CONF);
+				}
+				break;
 			case ARG_BER_LEN_T: {
 				unsigned long	l;
 				if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
@@ -308,6 +319,7 @@
 			case ARG_INT:		c->value_int = iarg;		break;
 			case ARG_UINT:		c->value_uint = uiarg;		break;
 			case ARG_LONG:		c->value_long = larg;		break;
+			case ARG_ULONG:		c->value_ulong = ularg;		break;
 			case ARG_BER_LEN_T:	c->value_ber_t = barg;		break;
 		}
 	}
@@ -359,6 +371,7 @@
 			case ARG_INT: 		*(int*)ptr = c->value_int;			break;
 			case ARG_UINT: 		*(unsigned*)ptr = c->value_uint;			break;
 			case ARG_LONG:  	*(long*)ptr = c->value_long;			break;
+			case ARG_ULONG:  	*(unsigned long*)ptr = c->value_ulong;			break;
 			case ARG_BER_LEN_T: 	*(ber_len_t*)ptr = c->value_ber_t;			break;
 			case ARG_STRING: {
 				char *cc = *(char**)ptr;
@@ -449,6 +462,7 @@
 		case ARG_INT:	c->value_int = *(int *)ptr; break;
 		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
 		case ARG_LONG:	c->value_long = *(long *)ptr; break;
+		case ARG_ULONG:	c->value_ulong = *(unsigned long *)ptr; break;
 		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
 		case ARG_STRING:
 			if ( *(char **)ptr )
@@ -467,6 +481,7 @@
 		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
 		case ARG_UINT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%u", c->value_uint); break;
 		case ARG_LONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_long); break;
+		case ARG_ULONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%lu", c->value_ulong); break;
 		case ARG_BER_LEN_T: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_ber_t); break;
 		case ARG_ON_OFF: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%s",
 			c->value_int ? "TRUE" : "FALSE"); break;
@@ -2111,3 +2126,66 @@
 	}
 	return rc;
 }
+
+/* See if the given URL (in plain and parsed form) matches
+ * any of the server's listener addresses. Return matching
+ * Listener or NULL for no match.
+ */
+Listener *config_check_my_url( const char *url, LDAPURLDesc *lud )
+{
+	Listener **l = slapd_get_listeners();
+	int i, isMe;
+
+	/* Try a straight compare with Listener strings */
+	for ( i=0; l && l[i]; i++ ) {
+		if ( !strcasecmp( url, l[i]->sl_url.bv_val )) {
+			return l[i];
+		}
+	}
+
+	isMe = 0;
+	/* If hostname is empty, or is localhost, or matches
+	 * our hostname, this url refers to this host.
+	 * Compare it against listeners and ports.
+	 */
+	if ( !lud->lud_host || !lud->lud_host[0] ||
+		!strncasecmp("localhost", lud->lud_host,
+			STRLENOF("localhost")) ||
+		!strcasecmp( global_host, lud->lud_host )) {
+
+		for ( i=0; l && l[i]; i++ ) {
+			LDAPURLDesc *lu2;
+			ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
+			do {
+				if ( strcasecmp( lud->lud_scheme,
+					lu2->lud_scheme ))
+					break;
+				if ( lud->lud_port != lu2->lud_port )
+					break;
+				/* Listener on ANY address */
+				if ( !lu2->lud_host || !lu2->lud_host[0] ) {
+					isMe = 1;
+					break;
+				}
+				/* URL on ANY address */
+				if ( !lud->lud_host || !lud->lud_host[0] ) {
+					isMe = 1;
+					break;
+				}
+				/* Listener has specific host, must
+				 * match it
+				 */
+				if ( !strcasecmp( lud->lud_host,
+					lu2->lud_host )) {
+					isMe = 1;
+					break;
+				}
+			} while(0);
+			ldap_free_urldesc( lu2 );
+			if ( isMe ) {
+				return l[i];
+			}
+		}
+	}
+	return NULL;
+}

Modified: openldap/trunk/servers/slapd/config.h
===================================================================
--- openldap/trunk/servers/slapd/config.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/config.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* config.h - configuration abstraction structure */
-/* $OpenLDAP: pkg/ldap/servers/slapd/config.h,v 1.34.2.15 2009/06/02 23:41:33 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/config.h,v 1.34.2.19 2009/08/25 22:44:25 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -59,6 +59,7 @@
 #define ARG_DN		0x00007000
 #define ARG_UINT	0x00008000
 #define ARG_ATDESC	0x00009000
+#define ARG_ULONG	0x0000a000
 
 #define ARGS_SYNTAX	0xffff0000
 #define ARG_IGNORED	0x00080000
@@ -134,6 +135,7 @@
 		int v_int;
 		unsigned v_uint;
 		long v_long;
+		unsigned long v_ulong;
 		ber_len_t v_ber_t;
 		char *v_string;
 		struct berval v_bv;
@@ -167,6 +169,7 @@
 #define value_int values.v_int
 #define value_uint values.v_uint
 #define value_long values.v_long
+#define value_ulong values.v_ulong
 #define value_ber_t values.v_ber_t
 #define value_string values.v_string
 #define value_bv values.v_bv
@@ -193,7 +196,8 @@
 Entry * config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
 	ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra );
 
-int config_shadow( ConfigArgs *c, int flag );
+Listener *config_check_my_url(const char *url, LDAPURLDesc *lud);
+int config_shadow( ConfigArgs *c, slap_mask_t flag );
 #define	config_slurp_shadow(c)	config_shadow((c), SLAP_DBFLAG_SLURP_SHADOW)
 #define	config_sync_shadow(c)	config_shadow((c), SLAP_DBFLAG_SYNC_SHADOW)
 
@@ -203,10 +207,10 @@
 
 #define	SLAP_X_ORDERED_FMT	"{%d}"
 
-extern slap_verbmasks *slap_ldap_response_code;
+LDAP_SLAPD_V (slap_verbmasks *) slap_ldap_response_code;
 extern int slap_ldap_response_code_register( struct berval *bv, int err );
 
-extern ConfigTable olcDatabaseDummy[];
+LDAP_SLAPD_V (ConfigTable) olcDatabaseDummy[];
 
 LDAP_END_DECL
 

Modified: openldap/trunk/servers/slapd/connection.c
===================================================================
--- openldap/trunk/servers/slapd/connection.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/connection.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/connection.c,v 1.358.2.31 2009/06/28 19:41:27 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/connection.c,v 1.358.2.34 2009/08/28 22:39:45 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -242,14 +242,15 @@
 			continue;
 		}
 
-		if( difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
+		if( global_idletimeout && 
+			difftime( c->c_activitytime+global_idletimeout, now) < 0 ) {
 			/* close it */
 			connection_closing( c, "idletimeout" );
 			connection_close( c );
 			i++;
 			continue;
 		}
-		if ( c->c_writewaiter ) {
+		if ( c->c_writewaiter && global_writetimeout ) {
 			writers = 1;
 			if( difftime( c->c_activitytime+global_writetimeout, now) < 0 ) {
 				/* close it */
@@ -260,7 +261,7 @@
 		}
 	}
 	connection_done( c );
-	if ( !writers )
+	if ( old && !writers )
 		slapd_clr_writetime( old );
 
 	return i;
@@ -752,6 +753,32 @@
 	}
 }
 
+static void
+connection_wake_writers( Connection *c )
+{
+	/* wake write blocked operations */
+	ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+	if ( c->c_writers > 0 ) {
+		c->c_writers = -c->c_writers;
+		ldap_pvt_thread_cond_broadcast( &c->c_write1_cv );
+		ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
+		if ( c->c_writewaiter ) {
+			ldap_pvt_thread_mutex_lock( &c->c_write2_mutex );
+			ldap_pvt_thread_cond_signal( &c->c_write2_cv );
+			slapd_clr_write( c->c_sd, 1 );
+			ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex );
+		}
+		ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+		while ( c->c_writers ) {
+			ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex );
+		}
+		ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
+	} else {
+		ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
+		slapd_clr_write( c->c_sd, 1 );
+	}
+}
+
 void connection_closing( Connection *c, const char *why )
 {
 	assert( connections != NULL );
@@ -776,26 +803,7 @@
 		connection_abandon( c );
 
 		/* wake write blocked operations */
-		ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
-		if ( c->c_writers > 0 ) {
-			c->c_writers = -c->c_writers;
-			ldap_pvt_thread_cond_broadcast( &c->c_write1_cv );
-			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
-			if ( c->c_writewaiter ) {
-				ldap_pvt_thread_mutex_lock( &c->c_write2_mutex );
-				ldap_pvt_thread_cond_signal( &c->c_write2_cv );
-				slapd_clr_write( c->c_sd, 1 );
-				ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex );
-			}
-			ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
-			while ( c->c_writers ) {
-				ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex );
-			}
-			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
-		} else {
-			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
-			slapd_clr_write( c->c_sd, 1 );
-		}
+		connection_wake_writers( c );
 
 	} else if( why == NULL && c->c_close_reason == conn_lost_str ) {
 		/* Client closed connection after doing Unbind. */
@@ -1269,6 +1277,11 @@
 	if ( rc )
 		return rc;
 
+	/* Don't let blocked writers block a pause request */
+	if ( connections[s].c_writewaiter &&
+		ldap_pvt_thread_pool_pausing( &connection_pool ))
+		connection_wake_writers( &connections[s] );
+
 	rc = ldap_pvt_thread_pool_submit( &connection_pool,
 		connection_read_thread, (void *)(long)s );
 

Modified: openldap/trunk/servers/slapd/controls.c
===================================================================
--- openldap/trunk/servers/slapd/controls.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/controls.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/controls.c,v 1.174.2.19 2009/04/29 01:55:17 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/controls.c,v 1.174.2.20 2009/07/27 20:19:18 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -1414,7 +1414,7 @@
 
 		an[i].an_desc = NULL;
 		an[i].an_oc = NULL;
-		an[i].an_oc_exclude = 0;
+		an[i].an_flags = 0;
 		rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
 		if ( rc == LDAP_SUCCESS ) {
 			an[i].an_name = an[i].an_desc->ad_cname;

Modified: openldap/trunk/servers/slapd/daemon.c
===================================================================
--- openldap/trunk/servers/slapd/daemon.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/daemon.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/daemon.c,v 1.380.2.30 2009/07/06 22:25:50 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/daemon.c,v 1.380.2.31 2009/08/25 22:44:25 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -73,6 +73,11 @@
 slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
 struct runqueue_s slapd_rq;
 
+#ifdef LDAP_TCP_BUFFER
+int slapd_tcp_rmem;
+int slapd_tcp_wmem;
+#endif /* LDAP_TCP_BUFFER */
+
 Listener **slap_listeners = NULL;
 
 #ifndef SLAPD_LISTEN_BACKLOG
@@ -1315,6 +1320,11 @@
 	}
 #endif /* HAVE_TLS */
 
+#ifdef LDAP_TCP_BUFFER
+	l.sl_tcp_rmem = 0;
+	l.sl_tcp_wmem = 0;
+#endif /* LDAP_TCP_BUFFER */
+
 	port = (unsigned short) lud->lud_port;
 
 	tmp = ldap_pvt_url_scheme2proto(lud->lud_scheme);
@@ -2081,6 +2091,131 @@
 			continue;
 #endif /* LDAP_CONNECTIONLESS */
 
+		/* FIXME: TCP-only! */
+#ifdef LDAP_TCP_BUFFER
+		if ( 1 ) {
+			int origsize, size, realsize, rc;
+			socklen_t optlen;
+			char buf[ SLAP_TEXT_BUFLEN ];
+
+			size = 0;
+			if ( slap_listeners[l]->sl_tcp_rmem > 0 ) {
+				size = slap_listeners[l]->sl_tcp_rmem;
+			} else if ( slapd_tcp_rmem > 0 ) {
+				size = slapd_tcp_rmem;
+			}
+
+			if ( size > 0 ) {
+				optlen = sizeof( origsize );
+				rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_RCVBUF,
+					(void *)&origsize,
+					&optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+						err, sock_errstr(err), 0 );
+				}
+
+				optlen = sizeof( size );
+				rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_RCVBUF,
+					(const void *)&size,
+					optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: setsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+						err, sock_errstr(err), 0 );
+				}
+
+				optlen = sizeof( realsize );
+				rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_RCVBUF,
+					(void *)&realsize,
+					&optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: getsockopt(SO_RCVBUF) failed errno=%d (%s)\n",
+						err, sock_errstr(err), 0 );
+				}
+
+				snprintf( buf, sizeof( buf ),
+					"url=%s (#%d) RCVBUF original size=%d requested size=%d real size=%d", 
+					slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
+				Debug( LDAP_DEBUG_ANY,
+					"slapd_daemon_task: %s\n",
+					buf, 0, 0 );
+			}
+
+			size = 0;
+			if ( slap_listeners[l]->sl_tcp_wmem > 0 ) {
+				size = slap_listeners[l]->sl_tcp_wmem;
+			} else if ( slapd_tcp_wmem > 0 ) {
+				size = slapd_tcp_wmem;
+			}
+
+			if ( size > 0 ) {
+				optlen = sizeof( origsize );
+				rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_SNDBUF,
+					(void *)&origsize,
+					&optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
+						err, sock_errstr(err), 0 );
+				}
+
+				optlen = sizeof( size );
+				rc = setsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_SNDBUF,
+					(const void *)&size,
+					optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: setsockopt(SO_SNDBUF) failed errno=%d (%s)",
+						err, sock_errstr(err), 0 );
+				}
+
+				optlen = sizeof( realsize );
+				rc = getsockopt( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ),
+					SOL_SOCKET,
+					SO_SNDBUF,
+					(void *)&realsize,
+					&optlen );
+
+				if ( rc ) {
+					int err = sock_errno();
+					Debug( LDAP_DEBUG_ANY,
+						"slapd_daemon_task: getsockopt(SO_SNDBUF) failed errno=%d (%s)\n",
+						err, sock_errstr(err), 0 );
+				}
+
+				snprintf( buf, sizeof( buf ),
+					"url=%s (#%d) SNDBUF original size=%d requested size=%d real size=%d", 
+					slap_listeners[l]->sl_url.bv_val, l, origsize, size, realsize );
+				Debug( LDAP_DEBUG_ANY,
+					"slapd_daemon_task: %s\n",
+					buf, 0, 0 );
+			}
+		}
+#endif /* LDAP_TCP_BUFFER */
+
 		if ( listen( SLAP_FD2SOCK( slap_listeners[l]->sl_sd ), SLAPD_LISTEN_BACKLOG ) == -1 ) {
 			int err = sock_errno();
 

Modified: openldap/trunk/servers/slapd/dn.c
===================================================================
--- openldap/trunk/servers/slapd/dn.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/dn.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* dn.c - routines for dealing with distinguished names */
-/* $OpenLDAP: pkg/ldap/servers/slapd/dn.c,v 1.182.2.12 2009/04/28 00:52:05 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/dn.c,v 1.182.2.13 2009/08/12 23:38:56 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -1197,7 +1197,71 @@
 	return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
 }
 
+/*
+ * In place; assumes:
+ * - ndn is normalized
+ * - nbase is normalized
+ * - dnIsSuffix( ndn, nbase ) == TRUE
+ * - LDAP_SCOPE_DEFAULT == LDAP_SCOPE_SUBTREE
+ */
 int
+dnIsWithinScope( struct berval *ndn, struct berval *nbase, int scope )
+{
+	assert( ndn != NULL );
+	assert( nbase != NULL );
+	assert( !BER_BVISNULL( ndn ) );
+	assert( !BER_BVISNULL( nbase ) );
+
+	switch ( scope ) {
+	case LDAP_SCOPE_DEFAULT:
+	case LDAP_SCOPE_SUBTREE:
+		break;
+
+	case LDAP_SCOPE_BASE:
+		if ( ndn->bv_len != nbase->bv_len ) {
+			return 0;
+		}
+		break;
+
+	case LDAP_SCOPE_ONELEVEL: {
+		struct berval pndn;
+		dnParent( ndn, &pndn );
+		if ( pndn.bv_len != nbase->bv_len ) {
+			return 0;
+		}
+		} break;
+
+	case LDAP_SCOPE_SUBORDINATE:
+		if ( ndn->bv_len == nbase->bv_len ) {
+			return 0;
+		}
+		break;
+
+	/* unknown scope */
+	default:
+		return -1;
+	}
+
+	return 1;
+}
+
+/*
+ * In place; assumes:
+ * - ndn is normalized
+ * - nbase is normalized
+ * - LDAP_SCOPE_DEFAULT == LDAP_SCOPE_SUBTREE
+ */
+int
+dnIsSuffixScope( struct berval *ndn, struct berval *nbase, int scope )
+{
+	if ( !dnIsSuffix( ndn, nbase ) ) {
+		return 0;
+	}
+
+	return dnIsWithinScope( ndn, nbase, scope );
+}
+
+int
 dnIsOneLevelRDN( struct berval *rdn )
 {
 	ber_len_t	len = rdn->bv_len;

Modified: openldap/trunk/servers/slapd/entry.c
===================================================================
--- openldap/trunk/servers/slapd/entry.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/entry.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* entry.c - routines for dealing with entries */
-/* $OpenLDAP: pkg/ldap/servers/slapd/entry.c,v 1.148.2.10 2009/05/01 19:37:13 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/entry.c,v 1.148.2.12 2009/08/14 21:04:55 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -936,21 +936,29 @@
 	return 0;
 }
 
-Entry *entry_dup( Entry *e )
+Entry *
+entry_dup2( Entry *dest, Entry *source )
 {
-	Entry *ret;
+	assert( dest != NULL );
+	assert( source != NULL );
 
-	ret = entry_alloc();
+	assert( dest->e_private == NULL );
 
-	ret->e_id = e->e_id;
-	ber_dupbv( &ret->e_name, &e->e_name );
-	ber_dupbv( &ret->e_nname, &e->e_nname );
-	ret->e_attrs = attrs_dup( e->e_attrs );
-	ret->e_ocflags = e->e_ocflags;
+	dest->e_id = source->e_id;
+	ber_dupbv( &dest->e_name, &source->e_name );
+	ber_dupbv( &dest->e_nname, &source->e_nname );
+	dest->e_attrs = attrs_dup( source->e_attrs );
+	dest->e_ocflags = source->e_ocflags;
 
-	return ret;
+	return dest;
 }
 
+Entry *
+entry_dup( Entry *e )
+{
+	return entry_dup2( entry_alloc(), e );
+}
+
 #if 1
 /* Duplicates an entry using a single malloc. Saves CPU time, increases
  * heap usage because a single large malloc is harder to satisfy than

Modified: openldap/trunk/servers/slapd/filter.c
===================================================================
--- openldap/trunk/servers/slapd/filter.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/filter.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* filter.c - routines for parsing and dealing with filters */
-/* $OpenLDAP: pkg/ldap/servers/slapd/filter.c,v 1.134.2.16 2009/01/22 00:01:01 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/filter.c,v 1.134.2.17 2009/08/13 00:48:32 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -348,7 +348,7 @@
 {
 	ber_tag_t	tag;
 	ber_len_t	len;
-	ber_tag_t	rc;
+	int	rc;
 	struct berval desc, value, nvalue;
 	char		*last;
 	SubstringsAssertion ssa;
@@ -385,17 +385,15 @@
 
 	rc = LDAP_PROTOCOL_ERROR;
 
+	/* If there is no substring matching rule, there's nothing
+	 * we can do with this filter. But we continue to parse it
+	 * for logging purposes.
+	 */
 	if ( ssa.sa_desc->ad_type->sat_substr == NULL ) {
-		for ( tag = ber_first_element( ber, &len, &last );
-			tag != LBER_DEFAULT;
-			tag = ber_next_element( ber, &len, last ) )
-		{
-			/* eat all */
-			rc = ber_scanf( ber, "x" );
-		}
-
-		rc = LDAP_INVALID_SYNTAX;
-		goto return_error;
+		f->f_choice |= SLAPD_FILTER_UNDEFINED;
+		Debug( LDAP_DEBUG_FILTER,
+		"get_ssa: no substring matching rule for attributeType %s\n",
+			desc.bv_val, 0, 0 );
 	}
 
 	for ( tag = ber_first_element( ber, &len, &last );
@@ -457,7 +455,13 @@
 		rc = asserted_value_validate_normalize(
 			ssa.sa_desc, ssa.sa_desc->ad_type->sat_equality,
 			usage, &value, &nvalue, text, op->o_tmpmemctx );
-		if( rc != LDAP_SUCCESS ) goto return_error;
+		if( rc != LDAP_SUCCESS ) {
+			f->f_choice |= SLAPD_FILTER_UNDEFINED;
+			Debug( LDAP_DEBUG_FILTER,
+			"get_ssa: illegal value for attributeType %s (%d) %s\n",
+				desc.bv_val, rc, *text );
+			ber_dupbv_x( &nvalue, &value, op->o_tmpmemctx );
+		}
 
 		switch ( tag ) {
 		case LDAP_SUBSTRING_INITIAL:

Modified: openldap/trunk/servers/slapd/modify.c
===================================================================
--- openldap/trunk/servers/slapd/modify.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/modify.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/modify.c,v 1.276.2.12 2009/03/05 18:16:29 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/modify.c,v 1.276.2.13 2009/08/13 00:45:33 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -690,7 +690,7 @@
 #define	SWAP(a,b,tmp)	tmp=(a);(a)=(b);(b)=tmp
 #define	COMP(a,b)	match=0; rc = ordered_value_match( &match, \
 						ad, mr, SLAP_MR_EQUALITY \
-								| SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX \
+								| SLAP_MR_VALUE_OF_ASSERTION_SYNTAX \
 								| SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \
 								| SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \
 								&(a), &(b), text );

Modified: openldap/trunk/servers/slapd/overlays/Makefile.in
===================================================================
--- openldap/trunk/servers/slapd/overlays/Makefile.in	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/Makefile.in	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 # Makefile.in for overlays
-# $OpenLDAP: pkg/ldap/servers/slapd/overlays/Makefile.in,v 1.41.2.8 2009/01/22 00:01:12 kurt Exp $
+# $OpenLDAP: pkg/ldap/servers/slapd/overlays/Makefile.in,v 1.41.2.9 2009/07/22 20:02:22 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 2003-2009 The OpenLDAP Foundation.
@@ -29,6 +29,7 @@
 	retcode.c \
 	rwm.c rwmconf.c rwmdn.c rwmmap.c \
 	seqmod.c \
+	sssvlv.c \
 	syncprov.c \
 	translucent.c \
 	unique.c \
@@ -109,6 +110,9 @@
 seqmod.la : seqmod.lo
 	$(LTLINK_MOD) -module -o $@ seqmod.lo version.lo $(LINK_LIBS)
 
+sssvlv.la : sssvlv.lo
+	$(LTLINK_MOD) -module -o $@ sssvlv.lo version.lo $(LINK_LIBS)
+
 syncprov.la : syncprov.lo
 	$(LTLINK_MOD) -module -o $@ syncprov.lo version.lo $(LINK_LIBS)
 

Modified: openldap/trunk/servers/slapd/overlays/dds.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/dds.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/dds.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/dds.c,v 1.7.2.12 2009/06/11 18:21:52 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/dds.c,v 1.7.2.13 2009/08/13 00:47:41 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2005-2009 The OpenLDAP Foundation.
@@ -581,7 +581,8 @@
 			}
 
 		} else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) {
-			unsigned long	ttl;
+			unsigned long	uttl;
+			time_t		ttl;
 			int		rc;
 
 			switch ( mod->sml_op ) {
@@ -628,7 +629,8 @@
 					goto done;
 				}
 
-				rc = lutil_atoul( &ttl, mod->sml_values[ 0 ].bv_val );
+				rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val );
+				ttl = (time_t)uttl;
 				assert( rc == 0 );
 				if ( ttl > DDS_RF2589_MAX_TTL ) {
 					rs->sr_err = LDAP_PROTOCOL_ERROR;
@@ -645,7 +647,7 @@
 					goto done;
 				}
 
-				entryTtl = (time_t)ttl;
+				entryTtl = ttl;
 				bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len;
 				AC_MEMCPY( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len );
 				bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
@@ -1120,26 +1122,24 @@
 			BerElementBuffer	berbuf;
 			BerElement		*ber = (BerElement *)&berbuf;
 
-			if ( rs->sr_err == LDAP_SUCCESS ) {
-				ber_init_w_nullc( ber, LBER_USE_DER );
+			ber_init_w_nullc( ber, LBER_USE_DER );
 
-				rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl );
+			rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl );
 
-				if ( rc < 0 ) {
-					rs->sr_err = LDAP_OTHER;
-					rs->sr_text = "internal error";
+			if ( rc < 0 ) {
+				rs->sr_err = LDAP_OTHER;
+				rs->sr_text = "internal error";
 
-				} else {
-					(void)ber_flatten( ber, &rs->sr_rspdata );
-					rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val );
+			} else {
+				(void)ber_flatten( ber, &rs->sr_rspdata );
+				rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val );
 
-					Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO,
-						"%s REFRESH dn=\"%s\" TTL=%ld\n",
-						op->o_log_prefix, op->o_req_ndn.bv_val, ttl );
-				}
+				Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO,
+					"%s REFRESH dn=\"%s\" TTL=%ld\n",
+					op->o_log_prefix, op->o_req_ndn.bv_val, ttl );
+			}
 
-				ber_free_buf( ber );
-			}
+			ber_free_buf( ber );
 		}
 
 		return rs->sr_err;
@@ -1390,7 +1390,7 @@
 
 		if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"DDS invalid dds-max-ttl=%ld; must be between %d and %d",
+				"DDS invalid dds-max-ttl=%lu; must be between %d and %d",
 				t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL );
 			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
 				"%s: %s.\n", c->log, c->cr_msg );
@@ -1410,9 +1410,9 @@
 			return 1;
 		}
 
-		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
+		if ( t > DDS_RF2589_MAX_TTL ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"DDS invalid dds-min-ttl=%ld",
+				"DDS invalid dds-min-ttl=%lu",
 				t );
 			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
 				"%s: %s.\n", c->log, c->cr_msg );
@@ -1437,9 +1437,9 @@
 			return 1;
 		}
 
-		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
+		if ( t > DDS_RF2589_MAX_TTL ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"DDS invalid dds-default-ttl=%ld",
+				"DDS invalid dds-default-ttl=%lu",
 				t );
 			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
 				"%s: %s.\n", c->log, c->cr_msg );
@@ -1466,7 +1466,7 @@
 
 		if ( t <= 0 ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"DDS invalid dds-interval=%ld",
+				"DDS invalid dds-interval=%lu",
 				t );
 			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
 				"%s: %s.\n", c->log, c->cr_msg );
@@ -1501,9 +1501,9 @@
 			return 1;
 		}
 
-		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
+		if ( t > DDS_RF2589_MAX_TTL ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
-				"DDS invalid dds-tolerance=%ld",
+				"DDS invalid dds-tolerance=%lu",
 				t );
 			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
 				"%s: %s.\n", c->log, c->cr_msg );

Modified: openldap/trunk/servers/slapd/overlays/dynlist.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/dynlist.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/dynlist.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* dynlist.c - dynamic list overlay */
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/dynlist.c,v 1.20.2.27 2009/03/05 23:00:00 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/dynlist.c,v 1.20.2.28 2009/08/25 23:13:42 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -957,7 +957,7 @@
 		ObjectClass		*oc;
 		AttributeDescription	*ad = NULL,
 					*member_ad = NULL;
-		dynlist_map_t		*dlm = NULL;
+		dynlist_map_t		*dlm = NULL, *dlml = NULL;
 		const char		*text;
 
 		if ( argc < 3 ) {
@@ -997,7 +997,6 @@
 			AttributeDescription *member_ad = NULL;
 			AttributeDescription *mapped_ad = NULL;
 			dynlist_map_t *dlmp;
-			dynlist_map_t *dlml;
 
 
 			/*
@@ -1032,7 +1031,6 @@
 			dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
 			if ( dlm == NULL ) {
 				dlm = dlmp;
-				dlml = NULL;
 			}
 			dlmp->dlm_member_ad = member_ad;
 			dlmp->dlm_mapped_ad = mapped_ad;
@@ -1406,7 +1404,7 @@
 		struct berval		nbase = BER_BVNULL;
 		Filter			*filter = NULL;
 		struct berval		uri = BER_BVNULL;
-		dynlist_map_t           *dlm = NULL;
+		dynlist_map_t           *dlm = NULL, *dlml = NULL;
 		const char		*text;
 
 		oc = oc_find( c->argv[ 1 ] );
@@ -1534,7 +1532,6 @@
 			AttributeDescription *member_ad = NULL;
 			AttributeDescription *mapped_ad = NULL;
 			dynlist_map_t *dlmp;
-			dynlist_map_t *dlml;
 
 
 			/*
@@ -1572,7 +1569,6 @@
 			dlmp = (dynlist_map_t *)ch_calloc( 1, sizeof( dynlist_map_t ) );
 			if ( dlm == NULL ) {
 				dlm = dlmp;
-				dlml = NULL;
 			}
 			dlmp->dlm_member_ad = member_ad;
 			dlmp->dlm_mapped_ad = mapped_ad;

Modified: openldap/trunk/servers/slapd/overlays/pcache.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/pcache.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/pcache.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,9 +1,9 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/pcache.c,v 1.88.2.34 2009/06/16 19:13:09 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/pcache.c,v 1.88.2.40 2009/08/25 21:24:47 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
  * Portions Copyright 2003 IBM Corporation.
- * Portions Copyright 2003 Symas Corporation.
+ * Portions Copyright 2003-2009 Symas Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 #include "ldap_rq.h"
 #include "avl.h"
 
+#include "../back-monitor/back-monitor.h"
+
 #include "config.h"
 
 #ifdef LDAP_DEVEL
@@ -46,6 +48,11 @@
  * Extended Operation that allows to remove a query from the cache
  */
 #define PCACHE_EXOP_QUERY_DELETE	"1.3.6.1.4.1.4203.666.11.9.6.1"
+
+/*
+ * Monitoring
+ */
+#define PCACHE_MONITOR
 #endif
 
 /* query cache structs */
@@ -74,7 +81,12 @@
 	struct berval			q_uuid;		/* query identifier */
 	int						q_sizelimit;
 	struct query_template_s		*qtemp;	/* template of the query */
-	time_t						expiry_time;	/* time till the query is considered valid */
+	time_t						expiry_time;	/* time till the query is considered invalid */
+	time_t						refresh_time;	/* time till the query is refreshed */
+	time_t						bindref_time;	/* time till the bind is refreshed */
+	unsigned long			answerable_cnt; /* how many times it was answerable */
+	int						refcnt;	/* references since last refresh */
+	ldap_pvt_thread_mutex_t		answerable_cnt_mutex;
 	struct cached_query_s  		*next;  	/* next query in the template */
 	struct cached_query_s  		*prev;  	/* previous query in the template */
 	struct cached_query_s		*lru_up;	/* previous query in the LRU list */
@@ -85,7 +97,7 @@
 /*
  * URL representation:
  *
- * ldap:///<base>??<scope>?<filter>?x-uuid=<uid>,x-template=<template>,x-attrset=<attrset>,x-expiry=<expiry>
+ * ldap:///<base>??<scope>?<filter>?x-uuid=<uid>,x-template=<template>,x-attrset=<attrset>,x-expiry=<expiry>,x-refresh=<refresh>
  *
  * <base> ::= CachedQuery.qbase->base
  * <scope> ::= CachedQuery.scope
@@ -93,9 +105,12 @@
  * <uuid> ::= CachedQuery.q_uuid
  * <attrset> ::= CachedQuery.qtemp->attr_set_index
  * <expiry> ::= CachedQuery.expiry_time
+ * <refresh> ::= CachedQuery.refresh_time
  *
  * quick hack: parse URI, call add_query() and then fix
  * CachedQuery.expiry_time and CachedQuery.q_uuid
+ *
+ * NOTE: if the <attrset> changes, all stored URLs will be invalidated.
  */
 
 /*
@@ -124,12 +139,21 @@
 	CachedQuery* 	query_last;     /* oldest query cached for the template */
 	ldap_pvt_thread_rdwr_t t_rwlock; /* Rd/wr lock for accessing queries in the template */
 	struct berval	querystr;	/* Filter string corresponding to the QT */
+	struct berval	bindbase;	/* base DN for Bind request */
+	struct berval	bindfilterstr;	/* Filter string for Bind request */
+	struct berval	bindftemp;	/* bind filter template */
+	Filter		*bindfilter;
+	AttributeDescription **bindfattrs;	/* attrs to substitute in ftemp */
 
+	int			bindnattrs;		/* number of bindfattrs */
+	int			bindscope;
 	int 		attr_set_index; /* determines the projected attributes */
 	int 		no_of_queries;  /* Total number of queries in the template */
 	time_t		ttl;		/* TTL for the queries of this template */
 	time_t		negttl;		/* TTL for negative results */
 	time_t		limitttl;	/* TTL for sizelimit exceeding results */
+	time_t		ttr;	/* time to refresh */
+	time_t		bindttr;	/* TTR for cached binds */
 	struct attr_set t_attrs;	/* filter attrs + attr_set */
 } QueryTemplate;
 
@@ -193,54 +217,122 @@
 #define PCACHE_RESPONSE_CB_HEAD	0
 #define PCACHE_RESPONSE_CB_TAIL	1
 	char	defer_db_open;			/* defer open for online add */
+	char	cache_binds;			/* cache binds or just passthru */
 
 	time_t	cc_period;		/* interval between successive consistency checks (sec) */
+#define PCACHE_CC_PAUSED	1
+#define PCACHE_CC_OFFLINE	2
 	int 	cc_paused;
 	void	*cc_arg;
 
 	ldap_pvt_thread_mutex_t		cache_mutex;
 
 	query_manager*   qm;	/* query cache managed by the cache manager */
+
+#ifdef PCACHE_MONITOR
+	void		*monitor_cb;
+	struct berval	monitor_ndn;
+#endif /* PCACHE_MONITOR */
 } cache_manager;
 
+#ifdef PCACHE_MONITOR
+static int pcache_monitor_db_init( BackendDB *be );
+static int pcache_monitor_db_open( BackendDB *be );
+static int pcache_monitor_db_close( BackendDB *be );
+static int pcache_monitor_db_destroy( BackendDB *be );
+#endif /* PCACHE_MONITOR */
+
 static int pcache_debug;
 
 #ifdef PCACHE_CONTROL_PRIVDB
 static int privDB_cid;
 #endif /* PCACHE_CONTROL_PRIVDB */
 
-static AttributeDescription *ad_queryId, *ad_cachedQueryURL;
+static AttributeDescription	*ad_queryId, *ad_cachedQueryURL;
+
+#ifdef PCACHE_MONITOR
+static AttributeDescription	*ad_numQueries, *ad_numEntries;
+static ObjectClass		*oc_olmPCache;
+#endif /* PCACHE_MONITOR */
+
 static struct {
+	char			*name;
+	char			*oid;
+}		s_oid[] = {
+	{ "PCacheOID",			"1.3.6.1.4.1.4203.666.11.9.1" },
+	{ "PCacheAttributes",		"PCacheOID:1" },
+	{ "PCacheObjectClasses",	"PCacheOID:2" },
+
+	{ NULL }
+};
+
+static struct {
 	char	*desc;
 	AttributeDescription **adp;
-} as[] = {
-	{ "( 1.3.6.1.4.1.4203.666.11.9.1.1 "
-		"NAME 'queryId' "
+} s_ad[] = {
+	{ "( PCacheAttributes:1 "
+		"NAME 'pcacheQueryID' "
 		"DESC 'ID of query the entry belongs to, formatted as a UUID' "
 		"EQUALITY octetStringMatch "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} "
 		"NO-USER-MODIFICATION "
 		"USAGE directoryOperation )",
 		&ad_queryId },
-	{ "( 1.3.6.1.4.1.4203.666.11.9.1.2 "
-		"NAME 'cachedQueryURL' "
+	{ "( PCacheAttributes:2 "
+		"NAME 'pcacheQueryURL' "
 		"DESC 'URI describing a cached query' "
 		"EQUALITY caseExactMatch "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
 		"NO-USER-MODIFICATION "
 		"USAGE directoryOperation )",
 		&ad_cachedQueryURL },
+#ifdef PCACHE_MONITOR
+	{ "( PCacheAttributes:3 "
+		"NAME 'pcacheNumQueries' "
+		"DESC 'Number of cached queries' "
+		"EQUALITY integerMatch "
+		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+		"NO-USER-MODIFICATION "
+		"USAGE directoryOperation )",
+		&ad_numQueries },
+	{ "( PCacheAttributes:4 "
+		"NAME 'pcacheNumEntries' "
+		"DESC 'Number of cached entries' "
+		"EQUALITY integerMatch "
+		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+		"NO-USER-MODIFICATION "
+		"USAGE directoryOperation )",
+		&ad_numEntries },
+#endif /* PCACHE_MONITOR */
+
 	{ NULL }
 };
 
+static struct {
+	char		*desc;
+	ObjectClass	**ocp;
+}		s_oc[] = {
+#ifdef PCACHE_MONITOR
+	/* augments an existing object, so it must be AUXILIARY */
+	{ "( PCacheObjectClasses:1 "
+		"NAME ( 'olmPCache' ) "
+		"SUP top AUXILIARY "
+		"MAY ( "
+			"pcacheQueryURL "
+			"$ pcacheNumQueries "
+			"$ pcacheNumEntries "
+			" ) )",
+		&oc_olmPCache },
+#endif /* PCACHE_MONITOR */
+
+	{ NULL }
+};
+
 static int
 filter2template(
 	Operation		*op,
 	Filter			*f,
-	struct			berval *fstr,
-	AttributeName**		filter_attrs,
-	int*			filter_cnt,
-	int*			filter_got_oc );
+	struct			berval *fstr );
 
 static CachedQuery *
 add_query(
@@ -261,22 +353,37 @@
  * Turn a cached query into its URL representation
  */
 static int
-query2url( Operation *op, CachedQuery *q, struct berval *urlbv )
+query2url( Operation *op, CachedQuery *q, struct berval *urlbv, int dolock )
 {
 	struct berval	bv_scope,
 			bv_filter;
 	char		attrset_buf[ LDAP_PVT_INTTYPE_CHARS( unsigned long ) ],
 			expiry_buf[ LDAP_PVT_INTTYPE_CHARS( unsigned long ) ],
+			refresh_buf[ LDAP_PVT_INTTYPE_CHARS( unsigned long ) ],
+			answerable_buf[ LDAP_PVT_INTTYPE_CHARS( unsigned long ) ],
 			*ptr;
 	ber_len_t	attrset_len,
-			expiry_len;
+			expiry_len,
+			refresh_len,
+			answerable_len;
 
+	if ( dolock ) {
+		ldap_pvt_thread_rdwr_rlock( &q->rwlock );
+	}
+
 	ldap_pvt_scope2bv( q->scope, &bv_scope );
 	filter2bv_x( op, q->filter, &bv_filter );
 	attrset_len = sprintf( attrset_buf,
 		"%lu", (unsigned long)q->qtemp->attr_set_index );
 	expiry_len = sprintf( expiry_buf,
 		"%lu", (unsigned long)q->expiry_time );
+	answerable_len = snprintf( answerable_buf, sizeof( answerable_buf ),
+		"%lu", q->answerable_cnt );
+	if ( q->refresh_time )
+		refresh_len = sprintf( refresh_buf,
+			"%lu", (unsigned long)q->refresh_time );
+	else
+		refresh_len = 0;
 
 	urlbv->bv_len = STRLENOF( "ldap:///" )
 		+ q->qbase->base.bv_len
@@ -289,7 +396,13 @@
 		+ STRLENOF( ",x-attrset=" )
 		+ attrset_len
 		+ STRLENOF( ",x-expiry=" )
-		+ expiry_len;
+		+ expiry_len
+		+ STRLENOF( ",x-answerable=" )
+		+ answerable_len;
+	if ( refresh_len )
+		urlbv->bv_len += STRLENOF( ",x-refresh=" )
+		+ refresh_len;
+
 	ptr = urlbv->bv_val = ber_memalloc_x( urlbv->bv_len + 1, op->o_tmpmemctx );
 	ptr = lutil_strcopy( ptr, "ldap:///" );
 	ptr = lutil_strcopy( ptr, q->qbase->base.bv_val );
@@ -303,12 +416,173 @@
 	ptr = lutil_strcopy( ptr, attrset_buf );
 	ptr = lutil_strcopy( ptr, ",x-expiry=" );
 	ptr = lutil_strcopy( ptr, expiry_buf );
+	ptr = lutil_strcopy( ptr, ",x-answerable=" );
+	ptr = lutil_strcopy( ptr, answerable_buf );
+	if ( refresh_len ) {
+		ptr = lutil_strcopy( ptr, ",x-refresh=" );
+		ptr = lutil_strcopy( ptr, refresh_buf );
+	}
 
 	ber_memfree_x( bv_filter.bv_val, op->o_tmpmemctx );
 
+	if ( dolock ) {
+		ldap_pvt_thread_rdwr_runlock( &q->rwlock );
+	}
+
 	return 0;
 }
 
+/* Find and record the empty filter clauses */
+
+static int
+ftemp_attrs( struct berval *ftemp, struct berval *template,
+	AttributeDescription ***ret, const char **text )
+{
+	int i;
+	int attr_cnt=0;
+	struct berval bv;
+	char *p1, *p2, *t1;
+	AttributeDescription *ad;
+	AttributeDescription **descs = NULL;
+	char *temp2;
+
+	temp2 = ch_malloc( ftemp->bv_len );
+	p1 = ftemp->bv_val;
+	t1 = temp2;
+
+	*ret = NULL;
+
+	for (;;) {
+		while ( *p1 == '(' || *p1 == '&' || *p1 == '|' || *p1 == ')' )
+			*t1++ = *p1++;
+
+		p2 = strchr( p1, '=' );
+		if ( !p2 )
+			break;
+		i = p2 - p1;
+		AC_MEMCPY( t1, p1, i );
+		t1 += i;
+		*t1++ = '=';
+
+		if ( p2[-1] == '<' || p2[-1] == '>' ) p2--;
+		bv.bv_val = p1;
+		bv.bv_len = p2 - p1;
+		ad = NULL;
+		i = slap_bv2ad( &bv, &ad, text );
+		if ( i ) {
+			ch_free( descs );
+			return -1;
+		}
+		if ( *p2 == '<' || *p2 == '>' ) p2++;
+		if ( p2[1] != ')' ) {
+			p2++;
+			while ( *p2 != ')' ) p2++;
+			p1 = p2;
+			continue;
+		}
+
+		descs = (AttributeDescription **)ch_realloc(descs,
+				(attr_cnt + 2)*sizeof(AttributeDescription *));
+
+		descs[attr_cnt++] = ad;
+
+		p1 = p2+1;
+	}
+	*t1 = '\0';
+	descs[attr_cnt] = NULL;
+	*ret = descs;
+	template->bv_val = temp2;
+	template->bv_len = t1 - temp2;
+	return attr_cnt;
+}
+
+static int
+template_attrs( char *template, struct attr_set *set, AttributeName **ret,
+	const char **text )
+{
+	int got_oc = 0;
+	int alluser = 0;
+	int allop = 0;
+	int i;
+	int attr_cnt;
+	int t_cnt = 0;
+	struct berval bv;
+	char *p1, *p2;
+	AttributeDescription *ad;
+	AttributeName *attrs;
+
+	p1 = template;
+
+	*ret = NULL;
+
+	attrs = ch_calloc( set->count + 1, sizeof(AttributeName) );
+	for ( i=0; i < set->count; i++ )
+		attrs[i] = set->attrs[i];
+	attr_cnt = i;
+	alluser = an_find( attrs, slap_bv_all_user_attrs );
+	allop = an_find( attrs, slap_bv_all_operational_attrs );
+
+	for (;;) {
+		while ( *p1 == '(' || *p1 == '&' || *p1 == '|' || *p1 == ')' ) p1++;
+		p2 = strchr( p1, '=' );
+		if ( !p2 )
+			break;
+		if ( p2[-1] == '<' || p2[-1] == '>' ) p2--;
+		bv.bv_val = p1;
+		bv.bv_len = p2 - p1;
+		ad = NULL;
+		i = slap_bv2ad( &bv, &ad, text );
+		if ( i ) {
+			ch_free( attrs );
+			return -1;
+		}
+		t_cnt++;
+
+		if ( ad == slap_schema.si_ad_objectClass )
+			got_oc = 1;
+
+		if ( is_at_operational(ad->ad_type)) {
+			if ( allop ) {
+				goto bottom;
+			}
+		} else if ( alluser ) {
+			goto bottom;
+		}
+		if ( !ad_inlist( ad, attrs )) {
+			attrs = (AttributeName *)ch_realloc(attrs,
+					(attr_cnt + 2)*sizeof(AttributeName));
+
+			attrs[attr_cnt].an_desc = ad;
+			attrs[attr_cnt].an_name = ad->ad_cname;
+			attrs[attr_cnt].an_oc = NULL;
+			attrs[attr_cnt].an_flags = 0;
+			BER_BVZERO( &attrs[attr_cnt+1].an_name );
+			attr_cnt++;
+		}
+
+bottom:
+		p1 = p2+2;
+	}
+	if ( !t_cnt ) {
+		*text = "couldn't parse template";
+		return -1;
+	}
+	if ( !got_oc && !( set->flags & PC_GOT_OC )) {
+		attrs = (AttributeName *)ch_realloc(attrs,
+				(attr_cnt + 2)*sizeof(AttributeName));
+
+		ad = slap_schema.si_ad_objectClass;
+		attrs[attr_cnt].an_desc = ad;
+		attrs[attr_cnt].an_name = ad->ad_cname;
+		attrs[attr_cnt].an_oc = NULL;
+		attrs[attr_cnt].an_flags = 0;
+		BER_BVZERO( &attrs[attr_cnt+1].an_name );
+		attr_cnt++;
+	}
+	*ret = attrs;
+	return attr_cnt;
+}
+
 /*
  * Turn an URL representing a formerly cached query into a cached query,
  * and try to cache it
@@ -328,10 +602,16 @@
 			uuid;
 	int		attrset;
 	time_t		expiry_time;
+	time_t		refresh_time;
+	unsigned long	answerable_cnt;
 	int		i,
-			got_uuid = 0,
-			got_attrset = 0,
-			got_expiry = 0,
+			got = 0,
+#define GOT_UUID	0x1U
+#define GOT_ATTRSET	0x2U
+#define GOT_EXPIRY	0x4U
+#define GOT_ANSWERABLE	0x8U
+#define GOT_REFRESH	0x10U
+#define GOT_ALL		(GOT_UUID|GOT_ATTRSET|GOT_EXPIRY|GOT_ANSWERABLE)
 			rc = 0;
 
 	rc = ldap_url_parse( url, &lud );
@@ -389,51 +669,86 @@
 			struct berval	tmpUUID;
 			Syntax		*syn_UUID = slap_schema.si_ad_entryUUID->ad_type->sat_syntax;
 
+			if ( got & GOT_UUID ) {
+				rc = 1;
+				goto error;
+			}
+
 			ber_str2bv( &lud->lud_exts[ i ][ STRLENOF( "x-uuid=" ) ], 0, 0, &tmpUUID );
 			rc = syn_UUID->ssyn_pretty( syn_UUID, &tmpUUID, &uuid, NULL );
 			if ( rc != LDAP_SUCCESS ) {
 				goto error;
 			}
-			got_uuid = 1;
+			got |= GOT_UUID;
 
 		} else if ( strncmp( lud->lud_exts[ i ], "x-attrset=", STRLENOF( "x-attrset=" ) ) == 0 ) {
+			if ( got & GOT_ATTRSET ) {
+				rc = 1;
+				goto error;
+			}
+
 			rc = lutil_atoi( &attrset, &lud->lud_exts[ i ][ STRLENOF( "x-attrset=" ) ] );
 			if ( rc ) {
 				goto error;
 			}
-			got_attrset = 1;
+			got |= GOT_ATTRSET;
 
 		} else if ( strncmp( lud->lud_exts[ i ], "x-expiry=", STRLENOF( "x-expiry=" ) ) == 0 ) {
 			unsigned long l;
 
+			if ( got & GOT_EXPIRY ) {
+				rc = 1;
+				goto error;
+			}
+
 			rc = lutil_atoul( &l, &lud->lud_exts[ i ][ STRLENOF( "x-expiry=" ) ] );
 			if ( rc ) {
 				goto error;
 			}
 			expiry_time = (time_t)l;
-			got_expiry = 1;
+			got |= GOT_EXPIRY;
 
+		} else if ( strncmp( lud->lud_exts[ i ], "x-answerable=", STRLENOF( "x-answerable=" ) ) == 0 ) {
+			if ( got & GOT_ANSWERABLE ) {
+				rc = 1;
+				goto error;
+			}
+
+			rc = lutil_atoul( &answerable_cnt, &lud->lud_exts[ i ][ STRLENOF( "x-answerable=" ) ] );
+			if ( rc ) {
+				goto error;
+			}
+			got |= GOT_ANSWERABLE;
+
+		} else if ( strncmp( lud->lud_exts[ i ], "x-refresh=", STRLENOF( "x-refresh=" ) ) == 0 ) {
+			unsigned long l;
+
+			if ( got & GOT_REFRESH ) {
+				rc = 1;
+				goto error;
+			}
+
+			rc = lutil_atoul( &l, &lud->lud_exts[ i ][ STRLENOF( "x-refresh=" ) ] );
+			if ( rc ) {
+				goto error;
+			}
+			refresh_time = (time_t)l;
+			got |= GOT_REFRESH;
+
 		} else {
 			rc = -1;
 			goto error;
 		}
 	}
 
-	if ( !got_uuid ) {
+	if ( got != GOT_ALL ) {
 		rc = 1;
 		goto error;
 	}
 
-	if ( !got_attrset ) {
-		rc = 1;
-		goto error;
-	}
+	if ( !(got & GOT_REFRESH ))
+		refresh_time = 0;
 
-	if ( !got_expiry ) {
-		rc = 1;
-		goto error;
-	}
-
 	/* ignore expired queries */
 	if ( expiry_time <= slap_get_time()) {
 		Operation	op2 = *op;
@@ -456,7 +771,7 @@
 
 		tempstr.bv_val = ch_malloc( strlen( lud->lud_filter ) + 1 );
 		tempstr.bv_len = 0;
-		if ( filter2template( op, query.filter, &tempstr, NULL, NULL, NULL ) ) {
+		if ( filter2template( op, query.filter, &tempstr ) ) {
 			ch_free( tempstr.bv_val );
 			rc = -1;
 			goto error;
@@ -479,7 +794,10 @@
 		cq = add_query( op, qm, &query, qt, PC_POSITIVE, 0 );
 		if ( cq != NULL ) {
 			cq->expiry_time = expiry_time;
+			cq->refresh_time = refresh_time;
 			cq->q_uuid = uuid;
+			cq->answerable_cnt = answerable_cnt;
+			cq->refcnt = 0;
 
 			/* it's now into cq->filter */
 			BER_BVZERO( &uuid );
@@ -1175,6 +1493,7 @@
 {
 	free(qc->q_uuid.bv_val);
 	filter_free(qc->filter);
+	ldap_pvt_thread_mutex_destroy(&qc->answerable_cnt_mutex);
 	ldap_pvt_thread_rdwr_destroy( &qc->rwlock );
 	memset(qc, 0, sizeof(*qc));
 	free(qc);
@@ -1195,15 +1514,19 @@
 	Qbase *qbase, qb;
 	Filter *first;
 	int rc;
-	time_t ttl = 0;;
+	time_t ttl = 0, ttr = 0;
+	time_t now;
 
 	new_cached_query->qtemp = templ;
 	BER_BVZERO( &new_cached_query->q_uuid );
 	new_cached_query->q_sizelimit = 0;
 
+	now = slap_get_time();
 	switch ( why ) {
 	case PC_POSITIVE:
 		ttl = templ->ttl;
+		if ( templ->ttr )
+			ttr = now + templ->ttr;
 		break;
 
 	case PC_NEGATIVE:
@@ -1218,7 +1541,13 @@
 		assert( 0 );
 		break;
 	}
-	new_cached_query->expiry_time = slap_get_time() + ttl;
+	new_cached_query->expiry_time = now + ttl;
+	new_cached_query->refresh_time = ttr;
+
+	new_cached_query->answerable_cnt = 0;
+	new_cached_query->refcnt = 1;
+	ldap_pvt_thread_mutex_init(&new_cached_query->answerable_cnt_mutex);
+
 	new_cached_query->lru_up = NULL;
 	new_cached_query->lru_down = NULL;
 	Debug( pcache_debug, "Added query expires at %ld (%s)\n",
@@ -1413,7 +1742,7 @@
 	struct berval	*query_uuid )
 {
 	struct query_info	*qi, *qnext;
-	char			filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
+	char			filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
 	AttributeAssertion	ava = ATTRIBUTEASSERTION_INIT;
 	Filter			filter = {LDAP_FILTER_EQUALITY};
 	SlapReply 		sreply = {REP_RESULT};
@@ -1440,6 +1769,7 @@
 	op->ors_deref = LDAP_DEREF_NEVER;
 	op->ors_slimit = SLAP_NO_LIMIT;
 	op->ors_tlimit = SLAP_NO_LIMIT;
+	op->ors_limit = NULL;
 	op->ors_filter = &filter;
 	op->ors_filterstr.bv_val = filter_str;
 	op->ors_filterstr.bv_len = strlen(filter_str);
@@ -1504,10 +1834,7 @@
 filter2template(
 	Operation		*op,
 	Filter			*f,
-	struct			berval *fstr,
-	AttributeName**		filter_attrs,
-	int*			filter_cnt,
-	int*			filter_got_oc )
+	struct			berval *fstr )
 {
 	AttributeDescription *ad;
 	int len, ret;
@@ -1580,8 +1907,7 @@
 		fstr->bv_len++;
 
 		for ( f = f->f_list; f != NULL; f = f->f_next ) {
-			rc = filter2template( op, f, fstr, filter_attrs, filter_cnt,
-				filter_got_oc );
+			rc = filter2template( op, f, fstr );
 			if ( rc ) break;
 		}
 		fstr->bv_val[fstr->bv_len++] = ')';
@@ -1598,23 +1924,24 @@
 		return -1;
 	}
 
-	if ( filter_attrs != NULL ) {
-		*filter_attrs = (AttributeName *)op->o_tmprealloc(*filter_attrs,
-				(*filter_cnt + 2)*sizeof(AttributeName), op->o_tmpmemctx);
-
-		(*filter_attrs)[*filter_cnt].an_desc = ad;
-		(*filter_attrs)[*filter_cnt].an_name = ad->ad_cname;
-		(*filter_attrs)[*filter_cnt].an_oc = NULL;
-		(*filter_attrs)[*filter_cnt].an_oc_exclude = 0;
-		BER_BVZERO( &(*filter_attrs)[*filter_cnt+1].an_name );
-		(*filter_cnt)++;
-		if ( ad == slap_schema.si_ad_objectClass )
-			*filter_got_oc = 1;
-	}
-
 	return 0;
 }
 
+#define	BI_HASHED	0x01
+#define	BI_DIDCB	0x02
+#define	BI_LOOKUP	0x04
+
+struct search_info;
+
+typedef struct bindinfo {
+	cache_manager *bi_cm;
+	CachedQuery *bi_cq;
+	QueryTemplate *bi_templ;
+	struct search_info *bi_si;
+	int bi_flags;
+	slap_callback bi_cb;
+} bindinfo;
+
 struct search_info {
 	slap_overinst *on;
 	Query query;
@@ -1628,6 +1955,7 @@
 	int slimit_exceeded;
 	pc_caching_reason_t caching_reason;
 	Entry *head, *tail;
+	bindinfo *pbi;
 };
 
 static void
@@ -1746,6 +2074,7 @@
 	op->ors_filter = &f;
 	op->ors_slimit = 1;
 	op->ors_tlimit = SLAP_NO_LIMIT;
+	op->ors_limit = NULL;
 	attrs[ 0 ].an_desc = ad_queryId;
 	attrs[ 0 ].an_name = ad_queryId->ad_cname;
 	op->ors_attrs = attrs;
@@ -1836,7 +2165,7 @@
 	slap_callback		sc = { 0 };
 	SlapReply		rs = { REP_RESULT };
 	Filter			f = { 0 };
-	char			filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
+	char			filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
 	AttributeAssertion	ava = ATTRIBUTEASSERTION_INIT;
 	AttributeName		attrs[ 2 ] = {{{ 0 }}};
 	int			rc;
@@ -1874,6 +2203,7 @@
 	op->ors_filter = &f;
 	op->ors_slimit = 1;
 	op->ors_tlimit = SLAP_NO_LIMIT;
+	op->ors_limit = NULL;
 	attrs[ 0 ].an_desc = ad_queryId;
 	attrs[ 0 ].an_name = ad_queryId->ad_cname;
 	op->ors_attrs = attrs;
@@ -2039,7 +2369,8 @@
 			op->ors_attrs = si->save_attrs;
 		}
 		if ( (op->o_abandon || rs->sr_err == SLAPD_ABANDON) && 
-				si->caching_reason == PC_IGNORE ) {
+				si->caching_reason == PC_IGNORE )
+		{
 			filter_free( si->query.filter );
 			if ( si->count ) {
 				/* duplicate query, free it */
@@ -2060,6 +2391,8 @@
 				switch ( si->caching_reason ) {
 				case PC_POSITIVE:
 					cache_entries( op, rs, &qc->q_uuid );
+					if ( si->pbi )
+						si->pbi->bi_cq = qc;
 					break;
 
 				case PC_SIZELIMIT:
@@ -2083,9 +2416,9 @@
 				/* If the consistency checker suspended itself,
 				 * wake it back up
 				 */
-				if ( cm->cc_paused ) {
+				if ( cm->cc_paused == PCACHE_CC_PAUSED ) {
 					ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
-					if ( cm->cc_paused ) {
+					if ( cm->cc_paused == PCACHE_CC_PAUSED ) {
 						cm->cc_paused = 0;
 						ldap_pvt_runqueue_resched( &slapd_rq, cm->cc_arg, 0 );
 					}
@@ -2155,68 +2488,6 @@
 	return SLAP_CB_CONTINUE;
 }
 
-static int
-add_filter_attrs(
-	Operation *op,
-	AttributeName** new_attrs,
-	struct attr_set *attrs,
-	AttributeName* filter_attrs,
-	int fattr_cnt,
-	int fattr_got_oc)
-{
-	int alluser = 0;
-	int allop = 0;
-	int i, j;
-	int count;
-	int addoc = 0;
-
-	/* duplicate attrs */
-	count = attrs->count + fattr_cnt;
-	if ( !fattr_got_oc && !(attrs->flags & PC_GOT_OC)) {
-		addoc = 1;
-		count++;
-	}
-
-	*new_attrs = (AttributeName*)ch_calloc( count + 1,
-		sizeof(AttributeName) );
-	for (i=0; i<attrs->count; i++) {
-		(*new_attrs)[i].an_name = attrs->attrs[i].an_name;
-		(*new_attrs)[i].an_desc = attrs->attrs[i].an_desc;
-	}
-	BER_BVZERO( &(*new_attrs)[i].an_name );
-	alluser = an_find( *new_attrs, slap_bv_all_user_attrs );
-	allop = an_find( *new_attrs, slap_bv_all_operational_attrs );
-
-	j = i;
-	for ( i=0; i<fattr_cnt; i++ ) {
-		if ( an_find(*new_attrs, &filter_attrs[i].an_name ) ) {
-			continue;
-		}
-		if ( is_at_operational(filter_attrs[i].an_desc->ad_type) ) {
-			if ( allop ) {
-				continue;
-			}
-		} else if ( alluser ) {
-			continue;
-		}
-		(*new_attrs)[j].an_name = filter_attrs[i].an_name;
-		(*new_attrs)[j].an_desc = filter_attrs[i].an_desc;
-		(*new_attrs)[j].an_oc = NULL;
-		(*new_attrs)[j].an_oc_exclude = 0;
-		j++;
-	}
-	if ( addoc ) {
-		(*new_attrs)[j].an_name = slap_schema.si_ad_objectClass->ad_cname;
-		(*new_attrs)[j].an_desc = slap_schema.si_ad_objectClass;
-		(*new_attrs)[j].an_oc = NULL;
-		(*new_attrs)[j].an_oc_exclude = 0;
-		j++;
-	}
-	BER_BVZERO( &(*new_attrs)[j].an_name );
-
-	return j;
-}
-
 /* NOTE: this is a quick workaround to let pcache minimally interact
  * with pagedResults.  A more articulated solutions would be to
  * perform the remote query without control and cache all results,
@@ -2253,6 +2524,175 @@
 	return rs->sr_err;
 }
 
+static int
+pc_setpw( Operation *op, struct berval *pwd, cache_manager *cm )
+{
+	struct berval vals[2];
+
+	{
+		const char *text = NULL;
+		BER_BVZERO( &vals[0] );
+		slap_passwd_hash( pwd, &vals[0], &text );
+		if ( BER_BVISEMPTY( &vals[0] )) {
+			Debug( pcache_debug, "pc_setpw: hash failed %s\n",
+				text, 0, 0 );
+			return LDAP_OTHER;
+		}
+	}
+
+	BER_BVZERO( &vals[1] );
+
+	{
+		Modifications mod;
+		SlapReply sr = { REP_RESULT };
+		slap_callback cb = { 0, slap_null_cb, 0, 0 };
+		int rc;
+
+		mod.sml_op = LDAP_MOD_REPLACE;
+		mod.sml_flags = 0;
+		mod.sml_desc = slap_schema.si_ad_userPassword;
+		mod.sml_type = mod.sml_desc->ad_cname;
+		mod.sml_values = vals;
+		mod.sml_nvalues = NULL;
+		mod.sml_numvals = 1;
+		mod.sml_next = NULL;
+
+		op->o_tag = LDAP_REQ_MODIFY;
+		op->orm_modlist = &mod;
+		op->o_bd = &cm->db;
+		op->o_dn = op->o_bd->be_rootdn;
+		op->o_ndn = op->o_bd->be_rootndn;
+		op->o_callback = &cb;
+		Debug( pcache_debug, "pc_setpw: CACHING BIND for %s\n",
+			op->o_req_dn.bv_val, 0, 0 );
+		rc = op->o_bd->be_modify( op, &sr );
+		ch_free( vals[0].bv_val );
+		return rc;
+	}
+}
+
+typedef struct bindcacheinfo {
+	slap_overinst *on;
+	CachedQuery *qc;
+} bindcacheinfo;
+
+static int
+pc_bind_save( Operation *op, SlapReply *rs )
+{
+	if ( rs->sr_err == LDAP_SUCCESS ) {
+		bindcacheinfo *bci = op->o_callback->sc_private;
+		slap_overinst *on = bci->on;
+		cache_manager *cm = on->on_bi.bi_private;
+
+		Operation op2 = *op;
+		if ( pc_setpw( &op2, &op->orb_cred, cm ) == LDAP_SUCCESS )
+			bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr;
+	}
+	return SLAP_CB_CONTINUE;
+}
+
+static Filter *
+pc_bind_attrs( Operation *op, Entry *e, QueryTemplate *temp,
+	struct berval *fbv )
+{
+	int i, len = 0;
+	struct berval *vals, pres = BER_BVC("*");
+	char *p1, *p2, *t1;
+	Attribute *a;
+
+	vals = op->o_tmpalloc( temp->bindnattrs * sizeof( struct berval ),
+		op->o_tmpmemctx );
+
+	for ( i=0; i<temp->bindnattrs; i++ ) {
+		a = attr_find( e->e_attrs, temp->bindfattrs[i] );
+		if ( a && a->a_vals ) {
+			vals[i] = a->a_vals[0];
+			len += a->a_vals[0].bv_len;
+		} else {
+			vals[i] = pres;
+		}
+	}
+	fbv->bv_len = len + temp->bindftemp.bv_len;
+	fbv->bv_val = op->o_tmpalloc( fbv->bv_len + 1, op->o_tmpmemctx );
+
+	p1 = temp->bindftemp.bv_val;
+	p2 = fbv->bv_val;
+	i = 0;
+	while ( *p1 ) {
+		*p2++ = *p1;
+		if ( p1[0] == '=' && p1[1] == ')' ) {
+			AC_MEMCPY( p2, vals[i].bv_val, vals[i].bv_len );
+			p2 += vals[i].bv_len;
+			i++;
+		}
+		p1++;
+	}
+	*p2 = '\0';
+	op->o_tmpfree( vals, op->o_tmpmemctx );
+	return str2filter_x( op, fbv->bv_val );
+}
+
+/* Check if the requested entry is from the cache and has a valid
+ * ttr and password hash
+ */
+static int
+pc_bind_search( Operation *op, SlapReply *rs )
+{
+	if ( rs->sr_type == REP_SEARCH ) {
+		bindinfo *pbi = op->o_callback->sc_private;
+
+		/* We only care if this is an already cached result and we're
+		 * below the refresh time, or we're offline.
+		 */
+		if ( pbi->bi_cq ) {
+			if (( pbi->bi_cm->cc_paused & PCACHE_CC_OFFLINE ) ||
+				op->o_time < pbi->bi_cq->bindref_time ) {
+				Attribute *a;
+
+				/* See if a recognized password is hashed here */
+				a = attr_find( rs->sr_entry->e_attrs,
+					slap_schema.si_ad_userPassword );
+				if ( a && a->a_vals[0].bv_val[0] == '{' &&
+					lutil_passwd_scheme( a->a_vals[0].bv_val ))
+					pbi->bi_flags |= BI_HASHED;
+			} else {
+				Debug( pcache_debug, "pc_bind_search: cache is stale, "
+					"reftime: %ld, current time: %ld\n",
+					pbi->bi_cq->bindref_time, op->o_time, 0 );
+			}
+		} else if ( pbi->bi_si ) {
+			/* This search result is going into the cache */
+			struct berval fbv;
+			Filter *f;
+
+			filter_free( pbi->bi_si->query.filter );
+			f = pc_bind_attrs( op, rs->sr_entry, pbi->bi_templ, &fbv );
+			op->o_tmpfree( fbv.bv_val, op->o_tmpmemctx );
+			pbi->bi_si->query.filter = filter_dup( f, NULL );
+			filter_free_x( op, f, 1 );
+		}
+	}
+	return 0;
+}
+
+/* We always want pc_bind_search to run after the search handlers */
+static int
+pc_bind_resp( Operation *op, SlapReply *rs )
+{
+	bindinfo *pbi = op->o_callback->sc_private;
+	if ( !( pbi->bi_flags & BI_DIDCB )) {
+		slap_callback *sc = op->o_callback;
+		while ( sc && sc->sc_response != pcache_response )
+			sc = sc->sc_next;
+		if ( !sc )
+			sc = op->o_callback;
+		pbi->bi_cb.sc_next = sc->sc_next;
+		sc->sc_next = &pbi->bi_cb;
+		pbi->bi_flags |= BI_DIDCB;
+	}
+	return SLAP_CB_CONTINUE;
+}
+
 #ifdef PCACHE_CONTROL_PRIVDB
 static int
 pcache_op_privdb(
@@ -2304,6 +2744,8 @@
 			if ( type == SLAP_OP_BIND && rc == LDAP_SUCCESS ) {
 				op->o_conn->c_authz_cookie = cm->db.be_private;
 			}
+
+			return rs->sr_err;
 		}
 	}
 
@@ -2319,6 +2761,117 @@
 #endif /* PCACHE_CONTROL_PRIVDB */
 
 static int
+pcache_op_bind(
+	Operation		*op,
+	SlapReply		*rs )
+{
+	slap_overinst 	*on = (slap_overinst *)op->o_bd->bd_info;
+	cache_manager 	*cm = on->on_bi.bi_private;
+	QueryTemplate *temp;
+	Entry *e;
+	slap_callback	cb = { 0 }, *sc;
+	bindinfo bi;
+	bindcacheinfo *bci;
+	Operation op2;
+	int rc;
+
+#ifdef PCACHE_CONTROL_PRIVDB
+	if ( op->o_ctrlflag[ privDB_cid ] == SLAP_CONTROL_CRITICAL )
+		return pcache_op_privdb( op, rs );
+#endif /* PCACHE_CONTROL_PRIVDB */
+
+	/* Skip if we're not configured for Binds, or cache DB isn't open yet */
+	if ( !cm->cache_binds || cm->defer_db_open )
+		return SLAP_CB_CONTINUE;
+
+	/* First find a matching template with Bind info */
+	for ( temp=cm->qm->templates; temp; temp=temp->qmnext ) {
+		if ( temp->bindttr && dnIsSuffix( &op->o_req_ndn, &temp->bindbase ))
+			break;
+	}
+	/* Didn't find a suitable template, just passthru */
+	if ( !temp )
+		return SLAP_CB_CONTINUE;
+
+	/* See if the entry is already locally cached. If so, we can
+	 * populate the query filter to retrieve the cached query. We
+	 * need to check the bindrefresh time in the query.
+	 */
+	op2 = *op;
+	op2.o_dn = op->o_bd->be_rootdn;
+	op2.o_ndn = op->o_bd->be_rootndn;
+	bi.bi_flags = 0;
+
+	op2.o_bd = &cm->db;
+	e = NULL;
+	rc = be_entry_get_rw( &op2, &op->o_req_ndn, NULL, NULL, 0, &e );
+	if ( rc == LDAP_SUCCESS && e ) {
+		bi.bi_flags |= BI_LOOKUP;
+		op2.ors_filter = pc_bind_attrs( op, e, temp, &op2.ors_filterstr );
+		be_entry_release_r( &op2, e );
+	} else {
+		op2.ors_filter = temp->bindfilter;
+		op2.ors_filterstr = temp->bindfilterstr;
+	}
+
+	op2.o_bd = op->o_bd;
+	op2.o_tag = LDAP_REQ_SEARCH;
+	op2.ors_scope = LDAP_SCOPE_BASE;
+	op2.ors_deref = LDAP_DEREF_NEVER;
+	op2.ors_slimit = 1;
+	op2.ors_tlimit = SLAP_NO_LIMIT;
+	op2.ors_limit = NULL;
+	op2.ors_attrs = cm->qm->attr_sets[temp->attr_set_index].attrs;
+	op2.ors_attrsonly = 0;
+
+	/* We want to invoke search at the same level of the stack
+	 * as we're already at...
+	 */
+	bi.bi_cm = cm;
+	bi.bi_templ = temp;
+	bi.bi_cq = NULL;
+	bi.bi_si = NULL;
+
+	bi.bi_cb.sc_response = pc_bind_search;
+	bi.bi_cb.sc_cleanup = NULL;
+	bi.bi_cb.sc_private = &bi;
+	cb.sc_private = &bi;
+	cb.sc_response = pc_bind_resp;
+	op2.o_callback = &cb;
+	overlay_op_walk( &op2, rs, op_search, on->on_info, on );
+
+	/* OK, just bind locally */
+	if ( bi.bi_flags & BI_HASHED ) {
+		BackendDB *be = op->o_bd;
+		op->o_bd = &cm->db;
+
+		Debug( pcache_debug, "pcache_op_bind: CACHED BIND for %s\n",
+			op->o_req_dn.bv_val, 0, 0 );
+
+		if ( op->o_bd->be_bind( op, rs ) == LDAP_SUCCESS ) {
+			op->o_conn->c_authz_cookie = cm->db.be_private;
+		}
+		op->o_bd = be;
+		return rs->sr_err;
+	}
+
+	/* We have a cached query to work with */
+	if ( bi.bi_cq ) {
+		sc = op->o_tmpalloc( sizeof(slap_callback) + sizeof(bindcacheinfo),
+			op->o_tmpmemctx );
+		sc->sc_response = pc_bind_save;
+		sc->sc_cleanup = NULL;
+		sc->sc_private = sc+1;
+		bci = sc->sc_private;
+		sc->sc_next = op->o_callback;
+		op->o_callback = sc;
+		bci->on = on;
+		bci->qc = bi.bi_cq;
+	}
+	return SLAP_CB_CONTINUE;
+}
+
+static int
 pcache_op_search(
 	Operation	*op,
 	SlapReply	*rs )
@@ -2329,16 +2882,13 @@
 
 	int i = -1;
 
-	AttributeName	*filter_attrs = NULL;
-
 	Query		query;
 	QueryTemplate	*qtemp = NULL;
+	bindinfo *pbi = NULL;
 
 	int 		attr_set = -1;
 	CachedQuery 	*answerable = NULL;
 	int 		cacheable = 0;
-	int		fattr_cnt=0;
-	int		fattr_got_oc = 0;
 
 	struct berval	tempstr;
 
@@ -2358,71 +2908,108 @@
 	/* pickup runtime ACL changes */
 	cm->db.be_acl = op->o_bd->be_acl;
 
-	tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1, op->o_tmpmemctx );
-	tempstr.bv_len = 0;
-	if ( filter2template( op, op->ors_filter, &tempstr, &filter_attrs,
-		&fattr_cnt, &fattr_got_oc )) {
-		op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
-		return SLAP_CB_CONTINUE;
+	{
+		/* See if we're processing a Bind request */
+		slap_callback *cb = op->o_callback;
+
+		for ( ; cb; cb=cb->sc_next ) {
+			if ( cb->sc_response == pc_bind_resp ) {
+				pbi = cb->sc_private;
+				break;
+			}
+		}
 	}
 
-	Debug( pcache_debug, "query template of incoming query = %s\n",
-					tempstr.bv_val, 0, 0 );
-
 	/* FIXME: cannot cache/answer requests with pagedResults control */
 
-	/* find attr set */
-	attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets);
-
 	query.filter = op->ors_filter;
-	query.base = op->o_req_ndn;
-	query.scope = op->ors_scope;
 
-	/* check for query containment */
-	if (attr_set > -1) {
-		QueryTemplate *qt = qm->attr_sets[attr_set].templates;
-		for (; qt; qt = qt->qtnext ) {
-			/* find if template i can potentially answer tempstr */
-			if (qt->querystr.bv_len != tempstr.bv_len ||
-				strcasecmp( qt->querystr.bv_val, tempstr.bv_val ))
-				continue;
-			cacheable = 1;
-			qtemp = qt;
-			Debug( pcache_debug, "Entering QC, querystr = %s\n",
-			 		op->ors_filterstr.bv_val, 0, 0 );
-			answerable = (*(qm->qcfunc))(op, qm, &query, qt);
+	if ( pbi ) {
+		query.base = pbi->bi_templ->bindbase;
+		query.scope = pbi->bi_templ->bindscope;
+		attr_set = pbi->bi_templ->attr_set_index;
+		cacheable = 1;
+		qtemp = pbi->bi_templ;
+		if ( pbi->bi_flags & BI_LOOKUP )
+			answerable = qm->qcfunc(op, qm, &query, qtemp);
 
-			if (answerable)
-				break;
+	} else {
+		tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1,
+			op->o_tmpmemctx );
+		tempstr.bv_len = 0;
+		if ( filter2template( op, op->ors_filter, &tempstr ))
+		{
+			op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
+			return SLAP_CB_CONTINUE;
 		}
+
+		Debug( pcache_debug, "query template of incoming query = %s\n",
+						tempstr.bv_val, 0, 0 );
+
+		/* find attr set */
+		attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets);
+
+		query.base = op->o_req_ndn;
+		query.scope = op->ors_scope;
+
+		/* check for query containment */
+		if (attr_set > -1) {
+			QueryTemplate *qt = qm->attr_sets[attr_set].templates;
+			for (; qt; qt = qt->qtnext ) {
+				/* find if template i can potentially answer tempstr */
+				if ( ber_bvstrcasecmp( &qt->querystr, &tempstr ) != 0 )
+					continue;
+				cacheable = 1;
+				qtemp = qt;
+				Debug( pcache_debug, "Entering QC, querystr = %s\n",
+						op->ors_filterstr.bv_val, 0, 0 );
+				answerable = qm->qcfunc(op, qm, &query, qt);
+
+				/* if != NULL, rlocks qtemp->t_rwlock */
+				if (answerable)
+					break;
+			}
+		}
+		op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
 	}
-	op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
 
 	if (answerable) {
 		BackendDB	*save_bd = op->o_bd;
-		slap_callback	*save_cb = op->o_callback;
 
-		Debug( pcache_debug, "QUERY ANSWERABLE\n", 0, 0, 0 );
-		op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
+		ldap_pvt_thread_mutex_lock( &answerable->answerable_cnt_mutex );
+		answerable->answerable_cnt++;
+		/* we only care about refcnts if we're refreshing */
+		if ( answerable->refresh_time )
+			answerable->refcnt++;
+		Debug( pcache_debug, "QUERY ANSWERABLE (answered %lu times)\n",
+			answerable->answerable_cnt, 0, 0 );
+		ldap_pvt_thread_mutex_unlock( &answerable->answerable_cnt_mutex );
+
 		ldap_pvt_thread_rdwr_rlock(&answerable->rwlock);
 		if ( BER_BVISNULL( &answerable->q_uuid )) {
 			/* No entries cached, just an empty result set */
 			i = rs->sr_err = 0;
 			send_ldap_result( op, rs );
 		} else {
+			/* Let Bind know we used a cached query */
+			if ( pbi )
+				pbi->bi_cq = answerable;
+
 			op->o_bd = &cm->db;
+#if 0
 			if ( cm->response_cb == PCACHE_RESPONSE_CB_TAIL ) {
 				/* The cached entry was already processed by any
 				 * other overlays, so don't let it get processed again.
 				 */
 				op->o_callback = NULL;
 			}
+#endif
 			i = cm->db.bd_info->bi_op_search( op, rs );
 		}
 		ldap_pvt_thread_rdwr_runlock(&answerable->rwlock);
+		/* locked by qtemp->qcfunc (query_containment) */
 		ldap_pvt_thread_rdwr_runlock(&qtemp->t_rwlock);
 		op->o_bd = save_bd;
-		op->o_callback = save_cb;
 		return i;
 	}
 
@@ -2443,14 +3030,6 @@
 
 		Debug( pcache_debug, "QUERY CACHEABLE\n", 0, 0, 0 );
 		query.filter = filter_dup(op->ors_filter, NULL);
-		ldap_pvt_thread_rdwr_wlock(&qtemp->t_rwlock);
-		if ( !qtemp->t_attrs.count ) {
-			qtemp->t_attrs.count = add_filter_attrs(op,
-				&qtemp->t_attrs.attrs,
-				&qm->attr_sets[attr_set],
-				filter_attrs, fattr_cnt, fattr_got_oc);
-		}
-		ldap_pvt_thread_rdwr_wunlock(&qtemp->t_rwlock);
 
 		cb = op->o_tmpalloc( sizeof(*cb) + sizeof(*si), op->o_tmpmemctx );
 		cb->sc_response = pcache_response;
@@ -2474,6 +3053,9 @@
 		si->tail = NULL;
 		si->swap_saved_attrs = 1;
 		si->save_attrs = op->ors_attrs;
+		si->pbi = pbi;
+		if ( pbi )
+			pbi->bi_si = si;
 
 		op->ors_attrs = qtemp->t_attrs.attrs;
 
@@ -2497,8 +3079,6 @@
 					0, 0, 0);
 	}
 
-	op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
-
 	return SLAP_CB_CONTINUE;
 }
 
@@ -2520,7 +3100,7 @@
 		count = 1;
 		attrs = slap_anlist_all_user_attributes;
 
-	} else if ( count == 1 && strcmp( attrs[0].an_name.bv_val, LDAP_NO_ATTRS ) == 0 ) {
+	} else if ( count == 1 && bvmatch( &attrs[0].an_name, slap_bv_no_attrs ) ) {
 		count = 0;
 		attrs = NULL;
 	}
@@ -2559,6 +3139,253 @@
 	return i;
 }
 
+/* Refresh a cached query:
+ * 1: Replay the query on the remote DB and merge each entry into
+ * the local DB. Remember the DNs of each remote entry.
+ * 2: Search the local DB for all entries matching this queryID.
+ * Delete any entry whose DN is not in the list from (1).
+ */
+typedef struct dnlist {
+	struct dnlist *next;
+	struct berval dn;
+	char delete;
+} dnlist;
+
+typedef struct refresh_info {
+	dnlist *ri_dns;
+	dnlist *ri_tail;
+	dnlist *ri_dels;
+	BackendDB *ri_be;
+	CachedQuery *ri_q;
+} refresh_info;
+
+static dnlist *dnl_alloc( Operation *op, struct berval *bvdn )
+{
+	dnlist *dn = op->o_tmpalloc( sizeof(dnlist) + bvdn->bv_len + 1,
+			op->o_tmpmemctx );
+	dn->dn.bv_len = bvdn->bv_len;
+	dn->dn.bv_val = (char *)(dn+1);
+	AC_MEMCPY( dn->dn.bv_val, bvdn->bv_val, dn->dn.bv_len );
+	dn->dn.bv_val[dn->dn.bv_len] = '\0';
+	return dn;
+}
+
+static int
+refresh_merge( Operation *op, SlapReply *rs )
+{
+	if ( rs->sr_type == REP_SEARCH ) {
+		refresh_info *ri = op->o_callback->sc_private;
+		BackendDB *be = op->o_bd;
+		Entry *e;
+		dnlist *dnl;
+		slap_callback *ocb;
+		int rc;
+
+		ocb = op->o_callback;
+		/* Find local entry, merge */
+		op->o_bd = ri->ri_be;
+		rc = be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &e );
+		if ( rc != LDAP_SUCCESS || e == NULL ) {
+			/* No local entry, just add it. FIXME: we are not checking
+			 * the cache entry limit here
+			 */
+			 merge_entry( op, rs->sr_entry, &ri->ri_q->q_uuid );
+		} else {
+			/* Entry exists, update it */
+			Entry ne;
+			Attribute *a, **b;
+			Modifications *modlist, *mods = NULL;
+			const char* 	text = NULL;
+			char			textbuf[SLAP_TEXT_BUFLEN];
+			size_t			textlen = sizeof(textbuf);
+			slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
+
+			ne = *e;
+			b = &ne.e_attrs;
+			/* Get a copy of only the attrs we requested */
+			for ( a=e->e_attrs; a; a=a->a_next ) {
+				if ( ad_inlist( a->a_desc, rs->sr_attrs )) {
+					*b = attr_alloc( a->a_desc );
+					*(*b) = *a;
+					/* The actual values still belong to e */
+					(*b)->a_flags |= SLAP_ATTR_DONT_FREE_VALS |
+						SLAP_ATTR_DONT_FREE_DATA;
+					b = &((*b)->a_next);
+				}
+			}
+			*b = NULL;
+			slap_entry2mods( rs->sr_entry, &modlist, &text, textbuf, textlen );
+			syncrepl_diff_entry( op, ne.e_attrs, rs->sr_entry->e_attrs,
+				&mods, &modlist, 0 );
+			be_entry_release_r( op, e );
+			attrs_free( ne.e_attrs );
+			slap_mods_free( modlist, 1 );
+			/* mods is NULL if there are no changes */
+			if ( mods ) {
+				struct berval dn = op->o_req_dn;
+				struct berval ndn = op->o_req_ndn;
+				op->o_tag = LDAP_REQ_MODIFY;
+				op->orm_modlist = mods;
+				op->o_req_dn = rs->sr_entry->e_name;
+				op->o_req_ndn = rs->sr_entry->e_nname;
+				op->o_callback = &cb;
+				op->o_bd->be_modify( op, rs );
+				slap_mods_free( mods, 1 );
+				op->o_req_dn = dn;
+				op->o_req_ndn = ndn;
+			}
+		}
+
+		/* Add DN to list */
+		dnl = dnl_alloc( op, &rs->sr_entry->e_nname );
+		dnl->next = NULL;
+		if ( ri->ri_tail ) {
+			ri->ri_tail->next = dnl;
+		} else {
+			ri->ri_dns = dnl;
+		}
+		ri->ri_tail = dnl;
+		op->o_callback = ocb;
+	}
+	return 0;
+}
+
+static int
+refresh_purge( Operation *op, SlapReply *rs )
+{
+	if ( rs->sr_type == REP_SEARCH ) {
+		refresh_info *ri = op->o_callback->sc_private;
+		dnlist **dn;
+		int del = 1;
+
+		/* Did the entry exist on the remote? */
+		for ( dn=&ri->ri_dns; *dn; dn = &(*dn)->next ) {
+			if ( dn_match( &(*dn)->dn, &rs->sr_entry->e_nname )) {
+				dnlist *dnext = (*dn)->next;
+				op->o_tmpfree( *dn, op->o_tmpmemctx );
+				*dn = dnext;
+				del = 0;
+				break;
+			}
+		}
+		/* No, so put it on the list to delete */
+		if ( del ) {
+			Attribute *a;
+			dnlist *dnl = dnl_alloc( op, &rs->sr_entry->e_nname );
+			dnl->next = ri->ri_dels;
+			ri->ri_dels = dnl;
+			a = attr_find( rs->sr_entry->e_attrs, ad_queryId );
+			/* If ours is the only queryId, delete entry */
+			dnl->delete = ( a->a_numvals == 1 );
+		}
+	}
+	return 0;
+}
+
+static int
+refresh_query( Operation *op, SlapReply *rs, CachedQuery *query,
+	slap_overinst *on )
+{
+	slap_callback cb = { 0 };
+	refresh_info ri = { 0 };
+	char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
+	AttributeAssertion	ava = ATTRIBUTEASSERTION_INIT;
+	Filter filter = {LDAP_FILTER_EQUALITY};
+	AttributeName attrs[ 2 ] = {{{ 0 }}};
+	dnlist *dn;
+	int rc;
+
+	ldap_pvt_thread_mutex_lock( &query->answerable_cnt_mutex );
+	query->refcnt = 0;
+	ldap_pvt_thread_mutex_unlock( &query->answerable_cnt_mutex );
+
+	cb.sc_response = refresh_merge;
+	cb.sc_private = &ri;
+
+	/* cache DB */
+	ri.ri_be = op->o_bd;
+	ri.ri_q = query;
+
+	op->o_tag = LDAP_REQ_SEARCH;
+	op->o_protocol = LDAP_VERSION3;
+	op->o_callback = &cb;
+	op->o_do_not_cache = 1;
+
+	op->o_req_dn = query->qbase->base;
+	op->o_req_ndn = query->qbase->base;
+	op->ors_scope = query->scope;
+	op->ors_slimit = SLAP_NO_LIMIT;
+	op->ors_tlimit = SLAP_NO_LIMIT;
+	op->ors_limit = NULL;
+	op->ors_filter = query->filter;
+	filter2bv_x( op, query->filter, &op->ors_filterstr );
+	op->ors_attrs = query->qtemp->t_attrs.attrs;
+	op->ors_attrsonly = 0;
+
+	op->o_bd = on->on_info->oi_origdb;
+	rc = op->o_bd->be_search( op, rs );
+	if ( rc ) {
+		op->o_bd = ri.ri_be;
+		goto leave;
+	}
+
+	/* Get the DNs of all entries matching this query */
+	cb.sc_response = refresh_purge;
+
+	op->o_bd = ri.ri_be;
+	op->o_req_dn = op->o_bd->be_suffix[0];
+	op->o_req_ndn = op->o_bd->be_nsuffix[0];
+	op->ors_scope = LDAP_SCOPE_SUBTREE;
+	op->ors_deref = LDAP_DEREF_NEVER;
+	op->ors_filterstr.bv_len = snprintf(filter_str, sizeof(filter_str),
+		"(%s=%s)", ad_queryId->ad_cname.bv_val, query->q_uuid.bv_val);
+	filter.f_ava = &ava;
+	filter.f_av_desc = ad_queryId;
+	filter.f_av_value = query->q_uuid;
+	attrs[ 0 ].an_desc = ad_queryId;
+	attrs[ 0 ].an_name = ad_queryId->ad_cname;
+	op->ors_attrs = attrs;
+	op->ors_attrsonly = 0;
+	rs->sr_entry = NULL;
+	rs->sr_nentries = 0;
+	rc = op->o_bd->be_search( op, rs );
+	if ( rc ) goto leave;
+
+	while (( dn = ri.ri_dels )) {
+		op->o_req_dn = dn->dn;
+		op->o_req_ndn = dn->dn;
+		if ( dn->delete ) {
+			op->o_tag = LDAP_REQ_DELETE;
+			op->o_bd->be_delete( op, rs );
+		} else {
+			Modifications mod;
+			struct berval vals[2];
+
+			vals[0] = query->q_uuid;
+			BER_BVZERO( &vals[1] );
+			mod.sml_op = LDAP_MOD_DELETE;
+			mod.sml_flags = 0;
+			mod.sml_desc = ad_queryId;
+			mod.sml_type = ad_queryId->ad_cname;
+			mod.sml_values = vals;
+			mod.sml_nvalues = NULL;
+			mod.sml_numvals = 1;
+			mod.sml_next = NULL;
+
+			op->o_tag = LDAP_REQ_MODIFY;
+			op->orm_modlist = &mod;
+			op->o_bd->be_modify( op, rs );
+		}
+		ri.ri_dels = dn->next;
+		op->o_tmpfree( dn, op->o_tmpmemctx );
+	}
+
+leave:
+	/* reset our local heap, we're done with it */
+	slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, op->o_threadctx, 1 );
+	return rc;
+}
+
 static void*
 consistency_check(
 	void *ctx,
@@ -2573,10 +3400,16 @@
 	Operation *op;
 
 	SlapReply rs = {REP_RESULT};
-	CachedQuery* query;
-	int return_val, pause = 1;
-	QueryTemplate* templ;
+	CachedQuery *query, *qprev;
+	int return_val, pause = PCACHE_CC_PAUSED;
+	QueryTemplate *templ;
 
+	/* Don't expire anything when we're offline */
+	if ( cm->cc_paused & PCACHE_CC_OFFLINE ) {
+		pause = PCACHE_CC_OFFLINE;
+		goto leave;
+	}
+
 	connection_fake_init( &conn, &opbuf, ctx );
 	op = &opbuf.ob_op;
 
@@ -2587,56 +3420,94 @@
 	cm->cc_arg = arg;
 
 	for (templ = qm->templates; templ; templ=templ->qmnext) {
-		query = templ->query_last;
-		if ( query ) pause = 0;
+		time_t ttl;
+		if ( !templ->query_last ) continue;
+		pause = 0;
 		op->o_time = slap_get_time();
-		while (query && (query->expiry_time < op->o_time)) {
-			int rem = 0;
-			Debug( pcache_debug, "Lock CR index = %p\n",
-					(void *) templ, 0, 0 );
-			ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
-			if ( query == templ->query_last ) {
-				rem = 1;
-				remove_from_template(query, templ);
-				Debug( pcache_debug, "TEMPLATE %p QUERIES-- %d\n",
-						(void *) templ, templ->no_of_queries, 0 );
-				Debug( pcache_debug, "Unlock CR index = %p\n",
+		if ( !templ->ttr ) {
+			ttl = templ->ttl;
+			if ( templ->negttl && templ->negttl < ttl )
+				ttl = templ->negttl;
+			if ( templ->limitttl && templ->limitttl < ttl )
+				ttl = templ->limitttl;
+			/* The oldest timestamp that needs expiration checking */
+			ttl += op->o_time;
+		}
+
+		for ( query=templ->query_last; query; query=qprev ) {
+			qprev = query->prev;
+			if ( query->refresh_time && query->refresh_time < op->o_time ) {
+				/* A refresh will extend the expiry if the query has been
+				 * referenced, but not if it's unreferenced. If the
+				 * expiration has been hit, then skip the refresh since
+				 * we're just going to discard the result anyway.
+				 */
+				if ( query->refcnt )
+					query->expiry_time = op->o_time + templ->ttl;
+				if ( query->expiry_time > op->o_time ) {
+					refresh_query( op, &rs, query, on );
+					continue;
+				}
+			}
+
+			if (query->expiry_time < op->o_time) {
+				int rem = 0;
+				Debug( pcache_debug, "Lock CR index = %p\n",
 						(void *) templ, 0, 0 );
+				ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
+				if ( query == templ->query_last ) {
+					rem = 1;
+					remove_from_template(query, templ);
+					Debug( pcache_debug, "TEMPLATE %p QUERIES-- %d\n",
+							(void *) templ, templ->no_of_queries, 0 );
+					Debug( pcache_debug, "Unlock CR index = %p\n",
+							(void *) templ, 0, 0 );
+				}
+				ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
+				if ( !rem ) {
+					continue;
+				}
+				ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
+				remove_query(qm, query);
+				ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
+				if ( BER_BVISNULL( &query->q_uuid ))
+					return_val = 0;
+				else
+					return_val = remove_query_data(op, &rs, &query->q_uuid);
+				Debug( pcache_debug, "STALE QUERY REMOVED, SIZE=%d\n",
+							return_val, 0, 0 );
+				ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
+				cm->cur_entries -= return_val;
+				cm->num_cached_queries--;
+				Debug( pcache_debug, "STORED QUERIES = %lu\n",
+						cm->num_cached_queries, 0, 0 );
+				ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
+				Debug( pcache_debug,
+					"STALE QUERY REMOVED, CACHE ="
+					"%d entries\n",
+					cm->cur_entries, 0, 0 );
+				free_query(query);
+			} else if ( !templ->ttr && query->expiry_time > ttl ) {
+				/* We don't need to check for refreshes, and this
+				 * query's expiry is too new, and all subsequent queries
+				 * will be newer yet. So stop looking.
+				 *
+				 * If we have refreshes, then we always have to walk the
+				 * entire query list.
+				 */
+				break;
 			}
-			ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
-			if ( !rem ) {
-				query = templ->query_last;
-				continue;
-			}
-			ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
-			remove_query(qm, query);
-			ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
-			if ( BER_BVISNULL( &query->q_uuid ))
-				return_val = 0;
-			else
-				return_val = remove_query_data(op, &rs, &query->q_uuid);
-			Debug( pcache_debug, "STALE QUERY REMOVED, SIZE=%d\n",
-						return_val, 0, 0 );
-			ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
-			cm->cur_entries -= return_val;
-			cm->num_cached_queries--;
-			Debug( pcache_debug, "STORED QUERIES = %lu\n",
-					cm->num_cached_queries, 0, 0 );
-			ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
-			Debug( pcache_debug,
-				"STALE QUERY REMOVED, CACHE ="
-				"%d entries\n",
-				cm->cur_entries, 0, 0 );
-			free_query(query);
-			query = templ->query_last;
 		}
 	}
+
+leave:
 	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
 	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
 		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
 	}
 	/* If there were no queries, defer processing for a while */
-	cm->cc_paused = pause;
+	if ( cm->cc_paused != pause )
+		cm->cc_paused = pause;
 	ldap_pvt_runqueue_resched( &slapd_rq, rtask, pause );
 
 	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
@@ -2651,7 +3522,10 @@
 	PC_ATTR,
 	PC_TEMP,
 	PC_RESP,
-	PC_QUERIES
+	PC_QUERIES,
+	PC_OFFLINE,
+	PC_BIND,
+	PC_PRIVATE_DB
 };
 
 static ConfigDriver pc_cf_gen;
@@ -2659,44 +3533,83 @@
 static ConfigCfAdd pc_cfadd;
 
 static ConfigTable pccfg[] = {
-	{ "proxycache", "backend> <max_entries> <numattrsets> <entry limit> "
+	{ "pcache", "backend> <max_entries> <numattrsets> <entry limit> "
 				"<cycle_time",
 		6, 6, 0, ARG_MAGIC|ARG_NO_DELETE|PC_MAIN, pc_cf_gen,
-		"( OLcfgOvAt:2.1 NAME 'olcProxyCache' "
-			"DESC 'ProxyCache basic parameters' "
+		"( OLcfgOvAt:2.1 NAME ( 'olcPcache' 'olcProxyCache' ) "
+			"DESC 'Proxy Cache basic parameters' "
 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-	{ "proxyattrset", "index> <attributes...",
+	{ "pcacheAttrset", "index> <attributes...",
 		2, 0, 0, ARG_MAGIC|PC_ATTR, pc_cf_gen,
-		"( OLcfgOvAt:2.2 NAME 'olcProxyAttrset' "
+		"( OLcfgOvAt:2.2 NAME ( 'olcPcacheAttrset' 'olcProxyAttrset' ) "
 			"DESC 'A set of attributes to cache' "
 			"SYNTAX OMsDirectoryString )", NULL, NULL },
-	{ "proxytemplate", "filter> <attrset-index> <TTL> <negTTL",
-		4, 6, 0, ARG_MAGIC|PC_TEMP, pc_cf_gen,
-		"( OLcfgOvAt:2.3 NAME 'olcProxyTemplate' "
+	{ "pcacheTemplate", "filter> <attrset-index> <TTL> <negTTL> "
+			"<limitTTL> <TTR",
+		4, 7, 0, ARG_MAGIC|PC_TEMP, pc_cf_gen,
+		"( OLcfgOvAt:2.3 NAME ( 'olcPcacheTemplate' 'olcProxyCacheTemplate' ) "
 			"DESC 'Filter template, attrset, cache TTL, "
-				"optional negative TTL, optional sizelimit TTL' "
+				"optional negative TTL, optional sizelimit TTL, "
+				"optional TTR' "
 			"SYNTAX OMsDirectoryString )", NULL, NULL },
-	{ "response-callback", "head|tail(default)",
+	{ "pcachePosition", "head|tail(default)",
 		2, 2, 0, ARG_MAGIC|PC_RESP, pc_cf_gen,
-		"( OLcfgOvAt:2.4 NAME 'olcProxyResponseCB' "
+		"( OLcfgOvAt:2.4 NAME 'olcPcachePosition' "
 			"DESC 'Response callback position in overlay stack' "
 			"SYNTAX OMsDirectoryString )", NULL, NULL },
-	{ "proxyCacheQueries", "queries",
+	{ "pcacheMaxQueries", "queries",
 		2, 2, 0, ARG_INT|ARG_MAGIC|PC_QUERIES, pc_cf_gen,
-		"( OLcfgOvAt:2.5 NAME 'olcProxyCacheQueries' "
+		"( OLcfgOvAt:2.5 NAME ( 'olcPcacheMaxQueries' 'olcProxyCacheQueries' ) "
 			"DESC 'Maximum number of queries to cache' "
 			"SYNTAX OMsInteger )", NULL, NULL },
-	{ "proxySaveQueries", "TRUE|FALSE",
+	{ "pcachePersist", "TRUE|FALSE",
 		2, 2, 0, ARG_ON_OFF|ARG_OFFSET, (void *)offsetof(cache_manager, save_queries),
-		"( OLcfgOvAt:2.6 NAME 'olcProxySaveQueries' "
+		"( OLcfgOvAt:2.6 NAME ( 'olcPcachePersist' 'olcProxySaveQueries' ) "
 			"DESC 'Save cached queries for hot restart' "
 			"SYNTAX OMsBoolean )", NULL, NULL },
-	{ "proxyCheckCacheability", "TRUE|FALSE",
+	{ "pcacheValidate", "TRUE|FALSE",
 		2, 2, 0, ARG_ON_OFF|ARG_OFFSET, (void *)offsetof(cache_manager, check_cacheability),
-		"( OLcfgOvAt:2.7 NAME 'olcProxyCheckCacheability' "
+		"( OLcfgOvAt:2.7 NAME ( 'olcPcacheValidate' 'olcProxyCheckCacheability' ) "
 			"DESC 'Check whether the results of a query are cacheable, e.g. for schema issues' "
 			"SYNTAX OMsBoolean )", NULL, NULL },
+	{ "pcacheOffline", "TRUE|FALSE",
+		2, 2, 0, ARG_ON_OFF|ARG_MAGIC|PC_OFFLINE, pc_cf_gen,
+		"( OLcfgOvAt:2.8 NAME 'olcPcacheOffline' "
+			"DESC 'Set cache to offline mode and disable expiration' "
+			"SYNTAX OMsBoolean )", NULL, NULL },
+	{ "pcacheBind", "filter> <attrset-index> <TTR> <scope> <base",
+		6, 6, 0, ARG_MAGIC|PC_BIND, pc_cf_gen,
+		"( OLcfgOvAt:2.9 NAME 'olcPcacheBind' "
+			"DESC 'Parameters for caching Binds' "
+			"SYNTAX OMsDirectoryString )", NULL, NULL },
+	{ "pcache-", "private database args",
+		1, 0, STRLENOF("pcache-"), ARG_MAGIC|PC_PRIVATE_DB, pc_cf_gen,
+		NULL, NULL, NULL },
 
+	/* Legacy keywords */
+	{ "proxycache", "backend> <max_entries> <numattrsets> <entry limit> "
+				"<cycle_time",
+		6, 6, 0, ARG_MAGIC|ARG_NO_DELETE|PC_MAIN, pc_cf_gen,
+		NULL, NULL, NULL },
+	{ "proxyattrset", "index> <attributes...",
+		2, 0, 0, ARG_MAGIC|PC_ATTR, pc_cf_gen,
+		NULL, NULL, NULL },
+	{ "proxytemplate", "filter> <attrset-index> <TTL> <negTTL",
+		4, 7, 0, ARG_MAGIC|PC_TEMP, pc_cf_gen,
+		NULL, NULL, NULL },
+	{ "response-callback", "head|tail(default)",
+		2, 2, 0, ARG_MAGIC|PC_RESP, pc_cf_gen,
+		NULL, NULL, NULL },
+	{ "proxyCacheQueries", "queries",
+		2, 2, 0, ARG_INT|ARG_MAGIC|PC_QUERIES, pc_cf_gen,
+		NULL, NULL, NULL },
+	{ "proxySaveQueries", "TRUE|FALSE",
+		2, 2, 0, ARG_ON_OFF|ARG_OFFSET, (void *)offsetof(cache_manager, save_queries),
+		NULL, NULL, NULL },
+	{ "proxyCheckCacheability", "TRUE|FALSE",
+		2, 2, 0, ARG_ON_OFF|ARG_OFFSET, (void *)offsetof(cache_manager, check_cacheability),
+		NULL, NULL, NULL },
+
 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
@@ -2705,8 +3618,9 @@
 		"NAME 'olcPcacheConfig' "
 		"DESC 'ProxyCache configuration' "
 		"SUP olcOverlayConfig "
-		"MUST ( olcProxyCache $ olcProxyAttrset $ olcProxyTemplate ) "
-		"MAY ( olcProxyResponseCB $ olcProxyCacheQueries $ olcProxySaveQueries $ olcProxyCheckCacheability ) )",
+		"MUST ( olcPcache $ olcPcacheAttrset $ olcPcacheTemplate ) "
+		"MAY ( olcPcachePosition $ olcPcacheMaxQueries $ olcPcachePersist $ "
+			"olcPcacheValidate $ olcPcacheOffline $ olcPcacheBind ) )",
 		Cft_Overlay, pccfg, NULL, pc_cfadd },
 	{ "( OLcfgOvOc:2.2 "
 		"NAME 'olcPcacheDatabase' "
@@ -2826,11 +3740,12 @@
 				/* HEADS-UP: always print all;
 				 * if optional == 0, ignore */
 				bv.bv_len = snprintf( c->cr_msg, sizeof( c->cr_msg ),
-					" %d %ld %ld %ld",
+					" %d %ld %ld %ld %ld",
 					temp->attr_set_index,
 					temp->ttl,
 					temp->negttl,
-					temp->limitttl );
+					temp->limitttl,
+					temp->ttr );
 				bv.bv_len += temp->querystr.bv_len + 2;
 				bv.bv_val = ch_malloc( bv.bv_len+1 );
 				ptr = bv.bv_val;
@@ -2843,6 +3758,30 @@
 			if ( !c->rvalue_vals )
 				rc = 1;
 			break;
+		case PC_BIND:
+			for (temp=qm->templates; temp; temp=temp->qmnext) {
+				if ( !temp->bindttr ) continue;
+				bv.bv_len = snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					" %d %ld %s ",
+					temp->attr_set_index,
+					temp->bindttr,
+					ldap_pvt_scope2str( temp->bindscope ));
+				bv.bv_len += temp->bindbase.bv_len + temp->bindftemp.bv_len + 4;
+				bv.bv_val = ch_malloc( bv.bv_len + 1 );
+				ptr = bv.bv_val;
+				*ptr++ = '"';
+				ptr = lutil_strcopy( ptr, temp->bindftemp.bv_val );
+				*ptr++ = '"';
+				ptr = lutil_strcopy( ptr, c->cr_msg );
+				*ptr++ = '"';
+				ptr = lutil_strcopy( ptr, temp->bindbase.bv_val );
+				*ptr++ = '"';
+				*ptr = '\0';
+				ber_bvarray_add( &c->rvalue_vals, &bv );
+			}
+			if ( !c->rvalue_vals )
+				rc = 1;
+			break;
 		case PC_RESP:
 			if ( cm->response_cb == PCACHE_RESPONSE_CB_HEAD ) {
 				BER_BVSTR( &bv, "head" );
@@ -2854,23 +3793,39 @@
 		case PC_QUERIES:
 			c->value_int = cm->max_queries;
 			break;
+		case PC_OFFLINE:
+			c->value_int = (cm->cc_paused & PCACHE_CC_OFFLINE) != 0;
+			break;
 		}
 		return rc;
 	} else if ( c->op == LDAP_MOD_DELETE ) {
-		return 1;	/* FIXME */
-#if 0
+		rc = 1;
 		switch( c->type ) {
-		case PC_ATTR:
+		case PC_ATTR: /* FIXME */
 		case PC_TEMP:
+		case PC_BIND:
+			break;
+		case PC_OFFLINE:
+			cm->cc_paused &= ~PCACHE_CC_OFFLINE;
+			/* If there were cached queries when we went offline,
+			 * restart the checker now.
+			 */
+			if ( cm->num_cached_queries ) {
+				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+				cm->cc_paused = 0;
+				ldap_pvt_runqueue_resched( &slapd_rq, cm->cc_arg, 0 );
+				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+			}
+			rc = 0;
+			break;
 		}
 		return rc;
-#endif
 	}
 
 	switch( c->type ) {
 	case PC_MAIN:
 		if ( cm->numattrsets > 0 ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive already provided" );
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive already provided" );
 			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
 			return( 1 );
 		}
@@ -2943,7 +3898,7 @@
 		break;
 	case PC_ATTR:
 		if ( cm->numattrsets == 0 ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive not provided yet" );
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive not provided yet" );
 			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
 			return( 1 );
 		}
@@ -3039,7 +3994,7 @@
 					attr_name->an_name = attr_name->an_desc->ad_cname;
 				}
 				attr_name->an_oc = NULL;
-				attr_name->an_oc_exclude = 0;
+				attr_name->an_flags = 0;
 				if ( attr_name->an_desc == slap_schema.si_ad_objectClass )
 					qm->attr_sets[num].flags |= PC_GOT_OC;
 				attr_name++;
@@ -3056,7 +4011,7 @@
 		break;
 	case PC_TEMP:
 		if ( cm->numattrsets == 0 ) {
-			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"proxycache\" directive not provided yet" );
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcache\" directive not provided yet" );
 			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
 			return( 1 );
 		}
@@ -3074,9 +4029,22 @@
 			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
 			return 1;
 		}
-		temp = ch_calloc( 1, sizeof( QueryTemplate ));
-		temp->qmnext = qm->templates;
-		qm->templates = temp;
+		{
+			AttributeName *attrs;
+			int cnt;
+			cnt = template_attrs( c->argv[1], &qm->attr_sets[i], &attrs, &text );
+			if ( cnt < 0 ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ), "unable to parse template: %s",
+					text );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				return 1;
+			}
+			temp = ch_calloc( 1, sizeof( QueryTemplate ));
+			temp->qmnext = qm->templates;
+			qm->templates = temp;
+			temp->t_attrs.attrs = attrs;
+			temp->t_attrs.count = cnt;
+		}
 		ldap_pvt_thread_rdwr_init( &temp->t_rwlock );
 		temp->query = temp->query_last = NULL;
 		if ( lutil_parse_time( c->argv[3], &t ) != 0 ) {
@@ -3084,19 +4052,34 @@
 				"unable to parse template ttl=\"%s\"",
 				c->argv[3] );
 			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+pc_temp_fail:
+			ch_free( temp->t_attrs.attrs );
+			ch_free( temp );
 			return( 1 );
 		}
 		temp->ttl = (time_t)t;
 		temp->negttl = (time_t)0;
 		temp->limitttl = (time_t)0;
+		temp->ttr = (time_t)0;
 		switch ( c->argc ) {
+		case 7:
+			if ( lutil_parse_time( c->argv[6], &t ) != 0 ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					"unable to parse template ttr=\"%s\"",
+					c->argv[6] );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				goto pc_temp_fail;
+			}
+			temp->ttr = (time_t)t;
+			/* fallthru */
+
 		case 6:
 			if ( lutil_parse_time( c->argv[5], &t ) != 0 ) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
 					"unable to parse template sizelimit ttl=\"%s\"",
 					c->argv[5] );
 				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
-					return( 1 );
+				goto pc_temp_fail;
 			}
 			temp->limitttl = (time_t)t;
 			/* fallthru */
@@ -3107,7 +4090,7 @@
 					"unable to parse template negative ttl=\"%s\"",
 					c->argv[4] );
 				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
-					return( 1 );
+				goto pc_temp_fail;
 			}
 			temp->negttl = (time_t)t;
 			break;
@@ -3130,6 +4113,135 @@
 					attrarray[i].an_name.bv_val, 0, 0 );
 		}
 		break;
+	case PC_BIND:
+		if ( !qm->templates ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"pcacheTemplate\" directive not provided yet" );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return( 1 );
+		}
+		if ( lutil_atoi( &i, c->argv[2] ) != 0 ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "unable to parse Bind index #=\"%s\"",
+				c->argv[2] );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return( 1 );
+		}
+
+		if ( i < 0 || i >= cm->numattrsets || 
+			!(qm->attr_sets[i].flags & PC_CONFIGURED )) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), "Bind index %d invalid (%s%d)",
+				i, cm->numattrsets > 1 ? "0->" : "", cm->numattrsets - 1 );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return 1;
+		}
+		{	struct berval bv, tempbv;
+			AttributeDescription **descs;
+			int ndescs;
+			ber_str2bv( c->argv[1], 0, 0, &bv );
+			ndescs = ftemp_attrs( &bv, &tempbv, &descs, &text );
+			if ( ndescs < 0 ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ), "unable to parse template: %s",
+					text );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				return 1;
+			}
+			for ( temp = qm->templates; temp; temp=temp->qmnext ) {
+				if ( temp->attr_set_index == i && bvmatch( &tempbv,
+					&temp->querystr ))
+					break;
+			}
+			ch_free( tempbv.bv_val );
+			if ( !temp ) {
+				ch_free( descs );
+				snprintf( c->cr_msg, sizeof( c->cr_msg ), "Bind template %s %d invalid",
+					c->argv[1], i );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				return 1;
+			}
+			ber_dupbv( &temp->bindftemp, &bv );
+			temp->bindfattrs = descs;
+			temp->bindnattrs = ndescs;
+		}
+		if ( lutil_parse_time( c->argv[3], &t ) != 0 ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"unable to parse bind ttr=\"%s\"",
+				c->argv[3] );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+pc_bind_fail:
+			ch_free( temp->bindfattrs );
+			temp->bindfattrs = NULL;
+			ch_free( temp->bindftemp.bv_val );
+			BER_BVZERO( &temp->bindftemp );
+			return( 1 );
+		}
+		num = ldap_pvt_str2scope( c->argv[4] );
+		if ( num < 0 ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"unable to parse bind scope=\"%s\"",
+				c->argv[4] );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			goto pc_bind_fail;
+		}
+		{
+			struct berval dn, ndn;
+			ber_str2bv( c->argv[5], 0, 0, &dn );
+			rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
+			if ( rc ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					"invalid bind baseDN=\"%s\"",
+					c->argv[5] );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				goto pc_bind_fail;
+			}
+			if ( temp->bindbase.bv_val )
+				ch_free( temp->bindbase.bv_val );
+			temp->bindbase = ndn;
+		}
+		{
+			/* convert the template into dummy filter */
+			struct berval bv;
+			char *eq = temp->bindftemp.bv_val, *e2;
+			Filter *f;
+			i = 0;
+			while ((eq = strchr(eq, '=' ))) {
+				eq++;
+				if ( eq[1] == ')' )
+					i++;
+			}
+			bv.bv_len = temp->bindftemp.bv_len + i;
+			bv.bv_val = ch_malloc( bv.bv_len + 1 );
+			for ( e2 = bv.bv_val, eq = temp->bindftemp.bv_val;
+				*eq; eq++ ) {
+				if ( *eq == '=' ) {
+					*e2++ = '=';
+					if ( eq[1] == ')' )
+						*e2++ = '*';
+				} else {
+					*e2++ = *eq;
+				}
+			}
+			*e2 = '\0';
+			f = str2filter( bv.bv_val );
+			if ( !f ) {
+				ch_free( bv.bv_val );
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					"unable to parse bindfilter=\"%s\"", bv.bv_val );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				ch_free( temp->bindbase.bv_val );
+				BER_BVZERO( &temp->bindbase );
+				goto pc_bind_fail;
+			}
+			if ( temp->bindfilter )
+				filter_free( temp->bindfilter );
+			if ( temp->bindfilterstr.bv_val )
+				ch_free( temp->bindfilterstr.bv_val );
+			temp->bindfilterstr = bv;
+			temp->bindfilter = f;
+		}
+		temp->bindttr = (time_t)t;
+		temp->bindscope = num;
+		cm->cache_binds = 1;
+		break;
+
 	case PC_RESP:
 		if ( strcasecmp( c->argv[1], "head" ) == 0 ) {
 			cm->response_cb = PCACHE_RESPONSE_CB_HEAD;
@@ -3151,7 +4263,68 @@
 		}
 		cm->max_queries = c->value_int;
 		break;
+	case PC_OFFLINE:
+		if ( c->value_int )
+			cm->cc_paused |= PCACHE_CC_OFFLINE;
+		else
+			cm->cc_paused &= ~PCACHE_CC_OFFLINE;
+		break;
+	case PC_PRIVATE_DB:
+		if ( cm->db.be_private == NULL ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"private database must be defined before setting database specific options" );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return( 1 );
+		}
+
+		if ( cm->db.bd_info->bi_cf_ocs ) {
+			ConfigTable	*ct;
+			ConfigArgs	c2 = *c;
+			char		*argv0 = c->argv[ 0 ];
+
+			c->argv[ 0 ] = &argv0[ STRLENOF( "pcache-" ) ];
+
+			ct = config_find_keyword( cm->db.bd_info->bi_cf_ocs->co_table, c );
+			if ( ct == NULL ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					"private database does not recognize specific option '%s'",
+					c->argv[ 0 ] );
+				Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+				rc = 1;
+
+			} else {
+				c->table = cm->db.bd_info->bi_cf_ocs->co_type;
+				c->be = &cm->db;
+				c->bi = c->be->bd_info;
+
+				rc = config_add_vals( ct, c );
+
+				c->bi = c2.bi;
+				c->be = c2.be;
+				c->table = c2.table;
+			}
+
+			c->argv[ 0 ] = argv0;
+
+		} else if ( cm->db.be_config != NULL ) {
+			char	*argv0 = c->argv[ 0 ];
+
+			c->argv[ 0 ] = &argv0[ STRLENOF( "pcache-" ) ];
+			rc = cm->db.be_config( &cm->db, c->fname, c->lineno, c->argc, c->argv );
+			c->argv[ 0 ] = argv0;
+
+		} else {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"no means to set private database specific options" );
+			Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
+			return 1;
+		}
+		break;
+	default:
+		rc = SLAP_CONF_UNKNOWN;
+		break;
 	}
+
 	return rc;
 }
 
@@ -3218,7 +4391,12 @@
 	ldap_pvt_thread_mutex_init(&qm->lru_mutex);
 
 	ldap_pvt_thread_mutex_init(&cm->cache_mutex);
+
+#ifndef PCACHE_MONITOR
 	return 0;
+#else /* PCACHE_MONITOR */
+	return pcache_monitor_db_init( be );
+#endif /* PCACHE_MONITOR */
 }
 
 static int
@@ -3288,7 +4466,7 @@
 			Debug( LDAP_DEBUG_ANY, "pcache_db_open(): "
 				"underlying database of type \"%s\"\n"
 				"    serving naming context \"%s\"\n"
-				"    has no \"rootdn\", required by \"proxycache\".\n",
+				"    has no \"rootdn\", required by \"pcache\".\n",
 				on->on_info->oi_orig->bi_type,
 				cm->db.be_suffix[0].bv_val, 0 );
 			return 1;
@@ -3329,7 +4507,8 @@
 			op->ors_deref = LDAP_DEREF_NEVER;
 			op->ors_slimit = 1;
 			op->ors_tlimit = SLAP_NO_LIMIT;
-			ber_str2bv( "(cachedQueryURL=*)", 0, 0, &op->ors_filterstr );
+			op->ors_limit = NULL;
+			ber_str2bv( "(pcacheQueryURL=*)", 0, 0, &op->ors_filterstr );
 			f.f_choice = LDAP_FILTER_PRESENT;
 			f.f_desc = ad_cachedQueryURL;
 			op->ors_filter = &f;
@@ -3430,9 +4609,16 @@
 		SLAP_DBFLAGS( &cm->db ) &= ~SLAP_DBFLAG_MONITORING;
 	}
 
-	if ( !cm->defer_db_open )
+	if ( !cm->defer_db_open ) {
 		rc = pcache_db_open2( on, cr );
+	}
 
+#ifdef PCACHE_MONITOR
+	if ( rc == LDAP_SUCCESS ) {
+		rc = pcache_monitor_db_open( be );
+	}
+#endif /* PCACHE_MONITOR */
+
 	return rc;
 }
 
@@ -3459,6 +4645,16 @@
 	QueryTemplate *tm;
 	int i, rc = 0;
 
+	/* stop the thread ... */
+	if ( cm->cc_arg ) {
+		ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+		if ( ldap_pvt_runqueue_isrunning( &slapd_rq, cm->cc_arg ) ) {
+			ldap_pvt_runqueue_stoptask( &slapd_rq, cm->cc_arg );
+		}
+		ldap_pvt_runqueue_remove( &slapd_rq, cm->cc_arg );
+		ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+	}
+
 	if ( cm->save_queries ) {
 		CachedQuery	*qc;
 		BerVarray	vals = NULL;
@@ -3482,7 +4678,7 @@
 				for ( qc = tm->query; qc; qc = qc->next ) {
 					struct berval	bv;
 
-					if ( query2url( op, qc, &bv ) == 0 ) {
+					if ( query2url( op, qc, &bv, 0 ) == 0 ) {
 						ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx );
 					}
 				}
@@ -3527,15 +4723,6 @@
 	cm->db.be_limits = NULL;
 	cm->db.be_acl = NULL;
 
-	/* stop the thread ... */
-	if ( cm->cc_arg ) {
-		ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
-		if ( ldap_pvt_runqueue_isrunning( &slapd_rq, cm->cc_arg ) ) {
-			ldap_pvt_runqueue_stoptask( &slapd_rq, cm->cc_arg );
-		}
-		ldap_pvt_runqueue_remove( &slapd_rq, cm->cc_arg );
-		ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
-	}
 
 	if ( cm->db.bd_info->bi_db_close ) {
 		rc = cm->db.bd_info->bi_db_close( &cm->db, NULL );
@@ -3549,6 +4736,11 @@
 		}
 		avl_free( tm->qbase, pcache_free_qbase );
 		free( tm->querystr.bv_val );
+		free( tm->bindfattrs );
+		free( tm->bindftemp.bv_val );
+		free( tm->bindfilterstr.bv_val );
+		free( tm->bindbase.bv_val );
+		filter_free( tm->bindfilter );
 		ldap_pvt_thread_rdwr_destroy( &tm->t_rwlock );
 		free( tm->t_attrs.attrs );
 		free( tm );
@@ -3560,6 +4752,12 @@
 	free( qm->attr_sets );
 	qm->attr_sets = NULL;
 
+#ifdef PCACHE_MONITOR
+	if ( rc == LDAP_SUCCESS ) {
+		rc = pcache_monitor_db_close( be );
+	}
+#endif /* PCACHE_MONITOR */
+
 	return rc;
 }
 
@@ -3582,6 +4780,10 @@
 	free( qm );
 	free( cm );
 
+#ifdef PCACHE_MONITOR
+	pcache_monitor_db_destroy( be );
+#endif /* PCACHE_MONITOR */
+
 	return 0;
 }
 
@@ -3628,6 +4830,7 @@
 };
 #endif /* PCACHE_CONTROL_PRIVDB */
 
+static struct berval pcache_exop_MODIFY_PASSWD = BER_BVC( LDAP_EXOP_MODIFY_PASSWD );
 #ifdef PCACHE_EXOP_QUERY_DELETE
 static struct berval pcache_exop_QUERY_DELETE = BER_BVC( PCACHE_EXOP_QUERY_DELETE );
 
@@ -3863,7 +5066,7 @@
 		len = snprintf( buf, sizeof( buf ), " dn=\"%s\"", op->o_req_ndn.bv_val );
 
 		if ( !BER_BVISNULL( &uuid ) && len < sizeof( buf ) ) {
-			snprintf( &buf[ len ], sizeof( buf ) - len, " queryId=\"%s\"", uuid.bv_val );
+			snprintf( &buf[ len ], sizeof( buf ) - len, " pcacheQueryId=\"%s\"", uuid.bv_val );
 		}
 
 		Debug( LDAP_DEBUG_STATS, "%s QUERY DELETE%s\n",
@@ -3901,6 +5104,7 @@
 
         return rs->sr_err;
 }
+#endif /* PCACHE_EXOP_QUERY_DELETE */
 
 static int
 pcache_op_extended( Operation *op, SlapReply *rs )
@@ -3914,6 +5118,7 @@
 	}
 #endif /* PCACHE_CONTROL_PRIVDB */
 
+#ifdef PCACHE_EXOP_QUERY_DELETE
 	if ( bvmatch( &op->ore_reqoid, &pcache_exop_QUERY_DELETE ) ) {
 		struct berval	uuid = BER_BVNULL;
 		ber_tag_t	tag = LBER_DEFAULT;
@@ -3941,12 +5146,335 @@
 		}
 
 		op->o_tmpfree( uuid.bv_val, op->o_tmpmemctx );
+		return rs->sr_err;
 	}
+#endif /* PCACHE_EXOP_QUERY_DELETE */
 
-	return rs->sr_err;
+	/* We only care if we're configured for Bind caching */
+	if ( bvmatch( &op->ore_reqoid, &pcache_exop_MODIFY_PASSWD ) &&
+		cm->cache_binds ) {
+		/* See if the local entry exists and has a password.
+		 * It's too much work to find the matching query, so
+		 * we just see if there's a hashed password to update.
+		 */
+		Operation op2 = *op;
+		Entry *e = NULL;
+		int rc;
+		int doit = 0;
+
+		op2.o_bd = &cm->db;
+		op2.o_dn = op->o_bd->be_rootdn;
+		op2.o_ndn = op->o_bd->be_rootndn;
+		rc = be_entry_get_rw( &op2, &op->o_req_ndn, NULL,
+			slap_schema.si_ad_userPassword, 0, &e );
+		if ( rc == LDAP_SUCCESS && e ) {
+			/* See if a recognized password is hashed here */
+			Attribute *a = attr_find( e->e_attrs,
+				slap_schema.si_ad_userPassword );
+			if ( a && a->a_vals[0].bv_val[0] == '{' &&
+				lutil_passwd_scheme( a->a_vals[0].bv_val )) {
+				doit = 1;
+			}
+			be_entry_release_r( &op2, e );
+		}
+
+		if ( doit ) {
+			rc = overlay_op_walk( op, rs, op_extended, on->on_info,
+				on->on_next );
+			if ( rc == LDAP_SUCCESS ) {
+				req_pwdexop_s *qpw = &op->oq_pwdexop;
+
+				/* We don't care if it succeeds or not */
+				pc_setpw( &op2, &qpw->rs_new, cm );
+			}
+			return rc;
+		}
+	}
+	return SLAP_CB_CONTINUE;
 }
-#endif /* PCACHE_EXOP_QUERY_DELETE */
 
+#ifdef PCACHE_MONITOR
+
+static int
+pcache_monitor_update(
+	Operation	*op,
+	SlapReply	*rs,
+	Entry		*e,
+	void		*priv )
+{
+	cache_manager	*cm = (cache_manager *) priv;
+	query_manager	*qm = cm->qm;
+
+	CachedQuery	*qc;
+	BerVarray	vals = NULL;
+
+	attr_delete( &e->e_attrs, ad_cachedQueryURL );
+	if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( ad_cachedQueryURL, rs->sr_attrs ) )
+		&& qm->templates != NULL )
+	{
+		QueryTemplate *tm;
+
+		for ( tm = qm->templates; tm != NULL; tm = tm->qmnext ) {
+			for ( qc = tm->query; qc; qc = qc->next ) {
+				struct berval	bv;
+
+				if ( query2url( op, qc, &bv, 1 ) == 0 ) {
+					ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx );
+				}
+			}
+		}
+
+
+		if ( vals != NULL ) {
+			attr_merge_normalize( e, ad_cachedQueryURL, vals, NULL );
+			ber_bvarray_free_x( vals, op->o_tmpmemctx );
+		}
+	}
+
+	{
+		Attribute	*a;
+		char		buf[ SLAP_TEXT_BUFLEN ];
+		struct berval	bv;
+
+		/* number of cached queries */
+		a = attr_find( e->e_attrs, ad_numQueries );
+		assert( a != NULL );
+
+		bv.bv_val = buf;
+		bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", cm->num_cached_queries );
+
+		if ( a->a_nvals != a->a_vals ) {
+			ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+		}
+		ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+		/* number of cached entries */
+		a = attr_find( e->e_attrs, ad_numEntries );
+		assert( a != NULL );
+
+		bv.bv_val = buf;
+		bv.bv_len = snprintf( buf, sizeof( buf ), "%d", cm->cur_entries );
+
+		if ( a->a_nvals != a->a_vals ) {
+			ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+		}
+		ber_bvreplace( &a->a_vals[ 0 ], &bv );
+	}
+
+	return SLAP_CB_CONTINUE;
+}
+
+static int
+pcache_monitor_free(
+	Entry		*e,
+	void		**priv )
+{
+	struct berval	values[ 2 ];
+	Modification	mod = { 0 };
+
+	const char	*text;
+	char		textbuf[ SLAP_TEXT_BUFLEN ];
+
+	int		rc;
+
+	/* NOTE: if slap_shutdown != 0, priv might have already been freed */
+	*priv = NULL;
+
+	/* Remove objectClass */
+	mod.sm_op = LDAP_MOD_DELETE;
+	mod.sm_desc = slap_schema.si_ad_objectClass;
+	mod.sm_values = values;
+	mod.sm_numvals = 1;
+	values[ 0 ] = oc_olmPCache->soc_cname;
+	BER_BVZERO( &values[ 1 ] );
+
+	rc = modify_delete_values( e, &mod, 1, &text,
+		textbuf, sizeof( textbuf ) );
+	/* don't care too much about return code... */
+
+	/* remove attrs */
+	mod.sm_values = NULL;
+	mod.sm_desc = ad_cachedQueryURL;
+	mod.sm_numvals = 0;
+	rc = modify_delete_values( e, &mod, 1, &text,
+		textbuf, sizeof( textbuf ) );
+	/* don't care too much about return code... */
+
+	/* remove attrs */
+	mod.sm_values = NULL;
+	mod.sm_desc = ad_numQueries;
+	mod.sm_numvals = 0;
+	rc = modify_delete_values( e, &mod, 1, &text,
+		textbuf, sizeof( textbuf ) );
+	/* don't care too much about return code... */
+
+	/* remove attrs */
+	mod.sm_values = NULL;
+	mod.sm_desc = ad_numEntries;
+	mod.sm_numvals = 0;
+	rc = modify_delete_values( e, &mod, 1, &text,
+		textbuf, sizeof( textbuf ) );
+	/* don't care too much about return code... */
+
+	return SLAP_CB_CONTINUE;
+}
+
+/*
+ * call from within pcache_initialize()
+ */
+static int
+pcache_monitor_initialize( void )
+{
+	static int	pcache_monitor_initialized = 0;
+
+	if ( backend_info( "monitor" ) == NULL ) {
+		return -1;
+	}
+
+	if ( pcache_monitor_initialized++ ) {
+		return 0;
+	}
+
+	return 0;
+}
+
+static int
+pcache_monitor_db_init( BackendDB *be )
+{
+	if ( pcache_monitor_initialize() == LDAP_SUCCESS ) {
+		SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
+	}
+
+	return 0;
+}
+
+static int
+pcache_monitor_db_open( BackendDB *be )
+{
+	slap_overinst		*on = (slap_overinst *)be->bd_info;
+	cache_manager		*cm = on->on_bi.bi_private;
+	Attribute		*a, *next;
+	monitor_callback_t	*cb = NULL;
+	int			rc = 0;
+	BackendInfo		*mi;
+	monitor_extra_t		*mbe;
+	struct berval		dummy = BER_BVC( "" );
+
+	if ( !SLAP_DBMONITORING( be ) ) {
+		return 0;
+	}
+
+	mi = backend_info( "monitor" );
+	if ( !mi || !mi->bi_extra ) {
+		SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
+		return 0;
+	}
+	mbe = mi->bi_extra;
+
+	/* don't bother if monitor is not configured */
+	if ( !mbe->is_configured() ) {
+		static int warning = 0;
+
+		if ( warning++ == 0 ) {
+			Debug( LDAP_DEBUG_ANY, "pcache_monitor_db_open: "
+				"monitoring disabled; "
+				"configure monitor database to enable\n",
+				0, 0, 0 );
+		}
+
+		return 0;
+	}
+
+	/* alloc as many as required (plus 1 for objectClass) */
+	a = attrs_alloc( 1 + 2 );
+	if ( a == NULL ) {
+		rc = 1;
+		goto cleanup;
+	}
+
+	a->a_desc = slap_schema.si_ad_objectClass;
+	attr_valadd( a, &oc_olmPCache->soc_cname, NULL, 1 );
+	next = a->a_next;
+
+	{
+		struct berval	bv = BER_BVC( "0" );
+
+		next->a_desc = ad_numQueries;
+		attr_valadd( next, &bv, NULL, 1 );
+		next = next->a_next;
+
+		next->a_desc = ad_numEntries;
+		attr_valadd( next, &bv, NULL, 1 );
+		next = next->a_next;
+	}
+
+	cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+	cb->mc_update = pcache_monitor_update;
+	cb->mc_free = pcache_monitor_free;
+	cb->mc_private = (void *)cm;
+
+	/* make sure the database is registered; then add monitor attributes */
+	BER_BVZERO( &cm->monitor_ndn );
+	rc = mbe->register_overlay( be, on, &cm->monitor_ndn );
+	if ( rc == 0 ) {
+		rc = mbe->register_entry_attrs( &cm->monitor_ndn, a, cb,
+			&dummy, -1, &dummy);
+	}
+
+cleanup:;
+	if ( rc != 0 ) {
+		if ( cb != NULL ) {
+			ch_free( cb );
+			cb = NULL;
+		}
+
+		if ( a != NULL ) {
+			attrs_free( a );
+			a = NULL;
+		}
+	}
+
+	/* store for cleanup */
+	cm->monitor_cb = (void *)cb;
+
+	/* we don't need to keep track of the attributes, because
+	 * bdb_monitor_free() takes care of everything */
+	if ( a != NULL ) {
+		attrs_free( a );
+	}
+
+	return rc;
+}
+
+static int
+pcache_monitor_db_close( BackendDB *be )
+{
+	slap_overinst *on = (slap_overinst *)be->bd_info;
+	cache_manager *cm = on->on_bi.bi_private;
+
+	if ( cm->monitor_cb != NULL ) {
+		BackendInfo		*mi = backend_info( "monitor" );
+		monitor_extra_t		*mbe;
+
+		if ( mi && &mi->bi_extra ) {
+			mbe = mi->bi_extra;
+			mbe->unregister_entry_callback( NULL,
+				(monitor_callback_t *)cm->monitor_cb,
+				NULL, 0, NULL );
+		}
+	}
+
+	return 0;
+}
+
+static int
+pcache_monitor_db_destroy( BackendDB *be )
+{
+	return 0;
+}
+
+#endif /* PCACHE_MONITOR */
+
 static slap_overinst pcache;
 
 static char *obsolete_names[] = {
@@ -3962,6 +5490,8 @@
 {
 	int i, code;
 	struct berval debugbv = BER_BVC("pcache");
+	ConfigArgs c;
+	char *argv[ 4 ];
 
 	code = slap_loglevel_get( &debugbv, &pcache_debug );
 	if ( code ) {
@@ -3992,16 +5522,44 @@
 	}
 #endif /* PCACHE_EXOP_QUERY_DELETE */
 
-	for ( i = 0; as[i].desc != NULL; i++ ) {
-		code = register_at( as[i].desc, as[i].adp, 0 );
+	argv[ 0 ] = "back-bdb/back-hdb monitor";
+	c.argv = argv;
+	c.argc = 3;
+	c.fname = argv[0];
+
+	for ( i = 0; s_oid[ i ].name; i++ ) {
+		c.lineno = i;
+		argv[ 1 ] = s_oid[ i ].name;
+		argv[ 2 ] = s_oid[ i ].oid;
+
+		if ( parse_oidm( &c, 0, NULL ) != 0 ) {
+			Debug( LDAP_DEBUG_ANY, "pcache_initialize: "
+				"unable to add objectIdentifier \"%s=%s\"\n",
+				s_oid[ i ].name, s_oid[ i ].oid, 0 );
+			return 1;
+		}
+	}
+
+	for ( i = 0; s_ad[i].desc != NULL; i++ ) {
+		code = register_at( s_ad[i].desc, s_ad[i].adp, 0 );
 		if ( code ) {
 			Debug( LDAP_DEBUG_ANY,
 				"pcache_initialize: register_at #%d failed\n", i, 0, 0 );
 			return code;
 		}
-		(*as[i].adp)->ad_type->sat_flags |= SLAP_AT_HIDE;
+		(*s_ad[i].adp)->ad_type->sat_flags |= SLAP_AT_HIDE;
 	}
 
+	for ( i = 0; s_oc[i].desc != NULL; i++ ) {
+		code = register_oc( s_oc[i].desc, s_oc[i].ocp, 0 );
+		if ( code ) {
+			Debug( LDAP_DEBUG_ANY,
+				"pcache_initialize: register_oc #%d failed\n", i, 0, 0 );
+			return code;
+		}
+		(*s_oc[i].ocp)->soc_flags |= SLAP_OC_HIDE;
+	}
+
 	pcache.on_bi.bi_type = "pcache";
 	pcache.on_bi.bi_obsolete_names = obsolete_names;
 	pcache.on_bi.bi_db_init = pcache_db_init;
@@ -4011,19 +5569,15 @@
 	pcache.on_bi.bi_db_destroy = pcache_db_destroy;
 
 	pcache.on_bi.bi_op_search = pcache_op_search;
+	pcache.on_bi.bi_op_bind = pcache_op_bind;
 #ifdef PCACHE_CONTROL_PRIVDB
-	pcache.on_bi.bi_op_bind = pcache_op_privdb;
 	pcache.on_bi.bi_op_compare = pcache_op_privdb;
 	pcache.on_bi.bi_op_modrdn = pcache_op_privdb;
 	pcache.on_bi.bi_op_modify = pcache_op_privdb;
 	pcache.on_bi.bi_op_add = pcache_op_privdb;
 	pcache.on_bi.bi_op_delete = pcache_op_privdb;
 #endif /* PCACHE_CONTROL_PRIVDB */
-#ifdef PCACHE_EXOP_QUERY_DELETE
 	pcache.on_bi.bi_extended = pcache_op_extended;
-#elif defined( PCACHE_CONTROL_PRIVDB )
-	pcache.on_bi.bi_extended = pcache_op_privdb;
-#endif
 
 	pcache.on_bi.bi_chk_controls = pcache_chk_controls;
 

Modified: openldap/trunk/servers/slapd/overlays/ppolicy.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/ppolicy.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/ppolicy.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.75.2.27 2009/07/01 21:01:41 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.75.2.28 2009/08/25 23:07:41 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -1136,6 +1136,7 @@
 		op2.o_tag = LDAP_REQ_MODIFY;
 		op2.o_callback = &cb;
 		op2.orm_modlist = mod;
+		op2.orm_no_opattrs = 0;
 		op2.o_dn = op->o_bd->be_rootdn;
 		op2.o_ndn = op->o_bd->be_rootndn;
 

Copied: openldap/trunk/servers/slapd/overlays/sssvlv.c (from rev 1241, openldap/vendor/openldap-release/servers/slapd/overlays/sssvlv.c)
===================================================================
--- openldap/trunk/servers/slapd/overlays/sssvlv.c	                        (rev 0)
+++ openldap/trunk/servers/slapd/overlays/sssvlv.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -0,0 +1,1240 @@
+/* sssvlv.c - server side sort / virtual list view */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/sssvlv.c,v 1.9.2.3 2009/07/27 17:30:42 quanah Exp $ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2009 The OpenLDAP Foundation.
+ * Portions copyright 2009 Symas Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Howard Chu for inclusion in
+ * OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_SSSVLV
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/ctype.h>
+
+#include <avl.h>
+
+#include "slap.h"
+#include "lutil.h"
+#include "config.h"
+
+#include "../../../libraries/liblber/lber-int.h"	/* ber_rewind */
+
+/* RFC2891: Server Side Sorting
+ * RFC2696: Paged Results
+ */
+#ifndef LDAP_MATCHRULE_IDENTIFIER
+#define LDAP_MATCHRULE_IDENTIFIER      0x80L
+#define LDAP_REVERSEORDER_IDENTIFIER   0x81L
+#define LDAP_ATTRTYPES_IDENTIFIER      0x80L
+#endif
+
+/* draft-ietf-ldapext-ldapv3-vlv-09.txt: Virtual List Views
+ */
+#ifndef LDAP_VLVBYINDEX_IDENTIFIER
+#define LDAP_VLVBYINDEX_IDENTIFIER	   0xa0L
+#define LDAP_VLVBYVALUE_IDENTIFIER     0x81L
+#define LDAP_VLVCONTEXT_IDENTIFIER     0x04L
+
+#define LDAP_VLV_SSS_MISSING	0x4C
+#define LDAP_VLV_RANGE_ERROR	0x4D
+#endif
+
+#define SAFESTR(macro_str, macro_def) ((macro_str) ? (macro_str) : (macro_def))
+
+#define SSSVLV_DEFAULT_MAX_KEYS	5
+
+typedef struct vlv_ctrl {
+	int vc_before;
+	int vc_after;
+	int	vc_offset;
+	int vc_count;
+	struct berval vc_value;
+	unsigned long vc_context;
+} vlv_ctrl;
+
+typedef struct sort_key
+{
+	AttributeDescription	*sk_ad;
+	MatchingRule			*sk_ordering;
+	int						sk_direction;	/* 1=normal, -1=reverse */
+} sort_key;
+
+typedef struct sort_ctrl {
+	int sc_nkeys;
+	sort_key sc_keys[1];
+} sort_ctrl;
+
+
+typedef struct sort_node
+{
+	int sn_conn;
+	struct berval sn_dn;
+	struct berval *sn_vals;
+} sort_node;
+
+typedef struct sssvlv_info
+{
+	int svi_max;	/* max concurrent sorts */
+	int svi_num;	/* current # sorts */
+	int svi_max_keys;	/* max sort keys per request */
+} sssvlv_info;
+
+typedef struct sort_op
+{
+	Avlnode	*so_tree;
+	sort_ctrl *so_ctrl;
+	sssvlv_info *so_info;
+	int so_paged;
+	int so_page_size;
+	int so_nentries;
+	int so_vlv;
+	int so_vlv_rc;
+	int so_vlv_target;
+	unsigned long so_vcontext;
+} sort_op;
+
+/* There is only one conn table for all overlay instances */
+static sort_op **sort_conns;
+static ldap_pvt_thread_mutex_t sort_conns_mutex;
+static const char *debug_header = "sssvlv";
+
+static int sss_cid;
+static int vlv_cid;
+
+/* RFC 2981 Section 2.2
+ * If a sort key is a multi-valued attribute, and an entry happens to
+ * have multiple values for that attribute and no other controls are
+ * present that affect the sorting order, then the server SHOULD use the
+ * least value (according to the ORDERING rule for that attribute).
+ */
+static struct berval* select_value(
+	Attribute		*attr,
+	sort_key			*key )
+{
+	struct berval* ber1, *ber2;
+	MatchingRule *mr = key->sk_ordering;
+	int i, cmp;
+
+	ber1 = &(attr->a_nvals[0]);
+	ber2 = ber1+1;
+	for ( i = 1; i < attr->a_numvals; i++,ber2++ ) {
+		mr->smr_match( &cmp, 0, mr->smr_syntax, mr, ber1, ber2 );
+		if ( cmp > 0 ) {
+			ber1 = ber2;
+		}
+	}
+
+	Debug(LDAP_DEBUG_TRACE, "%s: value selected for compare: %s\n",
+		debug_header,
+		SAFESTR(ber1->bv_val, "<Empty>"),
+		0);
+
+	return ber1;
+}
+
+static int node_cmp( const void* val1, const void* val2 )
+{
+	sort_node *sn1 = (sort_node *)val1;
+	sort_node *sn2 = (sort_node *)val2;
+	sort_ctrl *sc = sort_conns[sn1->sn_conn]->so_ctrl;
+	MatchingRule *mr;
+	int i, cmp = 0;
+
+	for ( i=0; cmp == 0 && i<sc->sc_nkeys; i++ ) {
+		if ( BER_BVISNULL( &sn1->sn_vals[i] )) {
+			if ( BER_BVISNULL( &sn2->sn_vals[i] ))
+				cmp = 0;
+			else
+				cmp = sc->sc_keys[i].sk_direction;
+		} else if ( BER_BVISNULL( &sn2->sn_vals[i] )) {
+			cmp = sc->sc_keys[i].sk_direction * -1;
+		} else {
+			mr = sc->sc_keys[i].sk_ordering;
+			mr->smr_match( &cmp, 0, mr->smr_syntax, mr,
+				&sn1->sn_vals[i], &sn2->sn_vals[i] );
+			if ( cmp )
+				cmp *= sc->sc_keys[i].sk_direction;
+		}
+	}
+	return cmp;
+}
+
+static int node_insert( const void *val1, const void *val2 )
+{
+	/* Never return equal so that new entries are always inserted */
+	return node_cmp( val1, val2 ) < 0 ? -1 : 1;
+}
+
+static int pack_vlv_response_control(
+	Operation		*op,
+	SlapReply		*rs,
+	sort_op			*so,
+	LDAPControl	**ctrlsp )
+{
+	LDAPControl			*ctrl;
+	BerElementBuffer	berbuf;
+	BerElement			*ber		= (BerElement *)&berbuf;
+	struct berval		cookie, bv;
+	int					rc;
+
+	ber_init2( ber, NULL, LBER_USE_DER );
+	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+	rc = ber_printf( ber, "{iii", so->so_vlv_target, so->so_nentries,
+		so->so_vlv_rc );
+
+	if ( rc != -1 && so->so_vcontext ) {
+		cookie.bv_val = (char *)&so->so_vcontext;
+		cookie.bv_len = sizeof(so->so_vcontext);
+		rc = ber_printf( ber, "tO", LDAP_VLVCONTEXT_IDENTIFIER, &cookie );
+	}
+
+	if ( rc != -1 ) {
+		rc = ber_printf( ber, "}" );
+	}
+
+	if ( rc != -1 ) {
+		rc = ber_flatten2( ber, &bv, 0 );
+	}
+
+	if ( rc != -1 ) {
+		ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+
+			bv.bv_len, op->o_tmpmemctx );
+		ctrl->ldctl_oid			= LDAP_CONTROL_VLVRESPONSE;
+		ctrl->ldctl_iscritical	= 0;
+		ctrl->ldctl_value.bv_val = (char *)(ctrl+1);
+		ctrl->ldctl_value.bv_len = bv.bv_len;
+		AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
+		ctrlsp[0] = ctrl;
+	} else {
+		ctrlsp[0] = NULL;
+		rs->sr_err = LDAP_OTHER;
+	}
+
+	ber_free_buf( ber );
+
+	return rs->sr_err;
+}
+
+static int pack_pagedresult_response_control(
+	Operation		*op,
+	SlapReply		*rs,
+	sort_op			*so,
+	LDAPControl	**ctrlsp )
+{
+	LDAPControl			*ctrl;
+	BerElementBuffer	berbuf;
+	BerElement			*ber		= (BerElement *)&berbuf;
+	PagedResultsCookie	resp_cookie;
+	struct berval		cookie, bv;
+	int					rc;
+
+	ber_init2( ber, NULL, LBER_USE_DER );
+	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+	if ( so->so_nentries > 0 ) {
+		resp_cookie		= ( PagedResultsCookie )so->so_tree;
+		cookie.bv_len	= sizeof( PagedResultsCookie );
+		cookie.bv_val	= (char *)&resp_cookie;
+	} else {
+		resp_cookie		= ( PagedResultsCookie )0;
+		BER_BVZERO( &cookie );
+	}
+
+	op->o_conn->c_pagedresults_state.ps_cookie = resp_cookie;
+	op->o_conn->c_pagedresults_state.ps_count
+		= ((PagedResultsState *)op->o_pagedresults_state)->ps_count
+		  + rs->sr_nentries;
+
+	rc = ber_printf( ber, "{iO}", so->so_nentries, &cookie );
+	if ( rc != -1 ) {
+		rc = ber_flatten2( ber, &bv, 0 );
+	}
+
+	if ( rc != -1 ) {
+		ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+
+			bv.bv_len, op->o_tmpmemctx );
+		ctrl->ldctl_oid			= LDAP_CONTROL_PAGEDRESULTS;
+		ctrl->ldctl_iscritical	= 0;
+		ctrl->ldctl_value.bv_val = (char *)(ctrl+1);
+		ctrl->ldctl_value.bv_len = bv.bv_len;
+		AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
+		ctrlsp[0] = ctrl;
+	} else {
+		ctrlsp[0] = NULL;
+		rs->sr_err = LDAP_OTHER;
+	}
+
+	ber_free_buf( ber );
+
+	return rs->sr_err;
+}
+
+static int pack_sss_response_control(
+	Operation		*op,
+	SlapReply		*rs,
+	LDAPControl	**ctrlsp )
+{
+	LDAPControl			*ctrl;
+	BerElementBuffer	berbuf;
+	BerElement			*ber		= (BerElement *)&berbuf;
+	struct berval		bv;
+	int					rc;
+
+	ber_init2( ber, NULL, LBER_USE_DER );
+	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+	/* Pack error code */
+	rc = ber_printf(ber, "{e}", rs->sr_err);
+
+	if ( rc != -1)
+		rc = ber_flatten2( ber, &bv, 0 );
+
+	if ( rc != -1 ) {
+		ctrl = (LDAPControl *)op->o_tmpalloc( sizeof(LDAPControl)+
+			bv.bv_len, op->o_tmpmemctx );
+		ctrl->ldctl_oid			= LDAP_CONTROL_SORTRESPONSE;
+		ctrl->ldctl_iscritical	= 0;
+		ctrl->ldctl_value.bv_val = (char *)(ctrl+1);
+		ctrl->ldctl_value.bv_len = bv.bv_len;
+		AC_MEMCPY( ctrl->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
+		ctrlsp[0] = ctrl;
+	} else {
+		ctrlsp[0] = NULL;
+		rs->sr_err = LDAP_OTHER;
+	}
+
+	ber_free_buf( ber );
+
+	return rs->sr_err;
+}
+
+static void free_sort_op( Connection *conn, sort_op *so )
+{
+	if ( so->so_tree ) {
+		tavl_free( so->so_tree, ch_free );
+		so->so_tree = NULL;
+	}
+
+	ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
+	sort_conns[conn->c_conn_idx] = NULL;
+	so->so_info->svi_num--;
+	ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
+
+	ch_free( so );
+}
+
+static void send_list(
+	Operation		*op,
+	SlapReply		*rs,
+	sort_op			*so)
+{
+	Avlnode	*cur_node, *tmp_node;
+	vlv_ctrl *vc = op->o_controls[vlv_cid];
+	int i, j, dir, rc;
+	BackendDB *be;
+	Entry *e;
+	LDAPControl *ctrls[2];
+
+	/* FIXME: it may be better to just flatten the tree into
+	 * an array before doing all of this...
+	 */
+
+	/* Are we just counting an offset? */
+	if ( BER_BVISNULL( &vc->vc_value )) {
+		if ( vc->vc_offset == vc->vc_count ) {
+			/* wants the last entry in the list */
+			cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT);
+			so->so_vlv_target = so->so_nentries;
+		} else if ( vc->vc_offset == 1 ) {
+			/* wants the first entry in the list */
+			cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT);
+			so->so_vlv_target = 1;
+		} else {
+			int target;
+			/* Just iterate to the right spot */
+			if ( vc->vc_count && vc->vc_count != so->so_nentries ) {
+				if ( vc->vc_offset > vc->vc_count )
+					goto range_err;
+				target = so->so_nentries * vc->vc_offset / vc->vc_count;
+			} else {
+				if ( vc->vc_offset > so->so_nentries ) {
+range_err:
+					so->so_vlv_rc = LDAP_VLV_RANGE_ERROR;
+					pack_vlv_response_control( op, rs, so, ctrls );
+					ctrls[1] = NULL;
+					slap_add_ctrls( op, rs, ctrls );
+					rs->sr_err = LDAP_VLV_ERROR;
+					return;
+				}
+				target = vc->vc_offset;
+			}
+			so->so_vlv_target = target;
+			/* Start at left and go right, or start at right and go left? */
+			if ( target < so->so_nentries / 2 ) {
+				cur_node = tavl_end(so->so_tree, TAVL_DIR_LEFT);
+				dir = TAVL_DIR_RIGHT;
+			} else {
+				cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT);
+				dir = TAVL_DIR_LEFT;
+				target = so->so_nentries - target + 1;
+			}
+			for ( i=1; i<target; i++ )
+				cur_node = tavl_next( cur_node, dir );
+		}
+	} else {
+	/* we're looking for a specific value */
+		sort_ctrl *sc = so->so_ctrl;
+		MatchingRule *mr = sc->sc_keys[0].sk_ordering;
+		sort_node *sn;
+		struct berval bv;
+
+		if ( mr->smr_normalize ) {
+			rc = mr->smr_normalize( SLAP_MR_VALUE_OF_SYNTAX,
+				mr->smr_syntax, mr, &vc->vc_value, &bv, op->o_tmpmemctx );
+			if ( rc ) {
+				so->so_vlv_rc = LDAP_INAPPROPRIATE_MATCHING;
+				pack_vlv_response_control( op, rs, so, ctrls );
+				ctrls[1] = NULL;
+				slap_add_ctrls( op, rs, ctrls );
+				rs->sr_err = LDAP_VLV_ERROR;
+				return;
+			}
+		} else {
+			bv = vc->vc_value;
+		}
+
+		sn = op->o_tmpalloc( sizeof(sort_node) +
+			sc->sc_nkeys * sizeof(struct berval), op->o_tmpmemctx );
+		sn->sn_vals = (struct berval *)(sn+1);
+		sn->sn_conn = op->o_conn->c_conn_idx;
+		sn->sn_vals[0] = bv;
+		for (i=1; i<sc->sc_nkeys; i++) {
+			BER_BVZERO( &sn->sn_vals[i] );
+		}
+		cur_node = tavl_find3( so->so_tree, sn, node_cmp, &j );
+		/* didn't find >= match */
+		if ( j > 0 )
+			cur_node = NULL;
+		op->o_tmpfree( sn, op->o_tmpmemctx );
+
+		if ( !cur_node ) {
+			so->so_vlv_target = so->so_nentries + 1;
+		} else {
+			sort_node *sn = so->so_tree->avl_data;
+			/* start from the left or the right side? */
+			mr->smr_match( &i, 0, mr->smr_syntax, mr, &bv, &sn->sn_vals[0] );
+			if ( i > 0 ) {
+				tmp_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT);
+				dir = TAVL_DIR_LEFT;
+			} else {
+				tmp_node = tavl_end(so->so_tree, TAVL_DIR_LEFT);
+				dir = TAVL_DIR_RIGHT;
+			}
+			for (i=0; tmp_node != cur_node;
+				tmp_node = tavl_next( tmp_node, dir ), i++);
+			so->so_vlv_target = i;
+		}
+		if ( bv.bv_val != vc->vc_value.bv_val )
+			op->o_tmpfree( bv.bv_val, op->o_tmpmemctx );
+	}
+	if ( !cur_node ) {
+		i = 1;
+		cur_node = tavl_end(so->so_tree, TAVL_DIR_RIGHT);
+	} else {
+		i = 0;
+	}
+	for ( ; i<vc->vc_before; i++ ) {
+		tmp_node = tavl_next( cur_node, TAVL_DIR_LEFT );
+		if ( !tmp_node ) break;
+		cur_node = tmp_node;
+	}
+	j = i + vc->vc_after + 1;
+	be = op->o_bd;
+	for ( i=0; i<j; i++ ) {
+		sort_node *sn = cur_node->avl_data;
+		
+		op->o_bd = select_backend( &sn->sn_dn, 0 );
+		e = NULL;
+		rc = be_entry_get_rw( op, &sn->sn_dn, NULL, NULL, 0, &e );
+
+		if ( e && rc == LDAP_SUCCESS ) {
+			rs->sr_entry = e;
+			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+			rs->sr_err = send_search_entry( op, rs );
+			if ( rs->sr_err == LDAP_UNAVAILABLE )
+				break;
+		}
+		cur_node = tavl_next( cur_node, TAVL_DIR_RIGHT );
+		if ( !cur_node ) break;
+	}
+	so->so_vlv_rc = LDAP_SUCCESS;
+
+	op->o_bd = be;
+}
+
+static void send_page( Operation *op, SlapReply *rs, sort_op *so )
+{
+	Avlnode		*cur_node		= so->so_tree;
+	Avlnode		*next_node		= NULL;
+	BackendDB *be = op->o_bd;
+	sort_node *sn;
+	Entry *e;
+	int rc;
+
+	while ( cur_node && rs->sr_nentries < so->so_page_size ) {
+		sort_node *sn = cur_node->avl_data;
+
+		next_node = tavl_next( cur_node, TAVL_DIR_RIGHT );
+
+		op->o_bd = select_backend( &sn->sn_dn, 0 );
+		e = NULL;
+		rc = be_entry_get_rw( op, &sn->sn_dn, NULL, NULL, 0, &e );
+
+		ch_free( cur_node->avl_data );
+		ber_memfree( cur_node );
+
+		cur_node = next_node;
+		so->so_nentries--;
+
+		if ( e && rc == LDAP_SUCCESS ) {
+			rs->sr_entry = e;
+			rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+			rs->sr_err = send_search_entry( op, rs );
+			if ( rs->sr_err == LDAP_UNAVAILABLE )
+				break;
+		}
+	}
+
+	/* Set the first entry to send for the next page */
+	so->so_tree = next_node;
+
+	op->o_bd = be;
+}
+
+static void send_entry(
+	Operation		*op,
+	SlapReply		*rs,
+	sort_op			*so)
+{
+	Debug(LDAP_DEBUG_TRACE,
+		"%s: response control: status=%d, text=%s\n",
+		debug_header, rs->sr_err, SAFESTR(rs->sr_text, "<None>"));
+
+	if ( !so->so_tree )
+		return;
+
+	/* RFC 2891: If critical then send the entries iff they were
+	 * succesfully sorted.  If non-critical send all entries
+	 * whether they were sorted or not.
+	 */
+	if ( (op->o_ctrlflag[sss_cid] != SLAP_CONTROL_CRITICAL) ||
+		 (rs->sr_err == LDAP_SUCCESS) )
+	{
+		if ( so->so_vlv > SLAP_CONTROL_IGNORED ) {
+			send_list( op, rs, so );
+		} else {
+			/* Get the first node to send */
+			Avlnode *start_node = tavl_end(so->so_tree, TAVL_DIR_LEFT);
+			so->so_tree = start_node;
+
+			if ( so->so_paged <= SLAP_CONTROL_IGNORED ) {
+				/* Not paged result search.  Send all entries.
+				 * Set the page size to the number of entries
+				 * so that send_page() will send all entries.
+				 */
+				so->so_page_size = so->so_nentries;
+			}
+
+			send_page( op, rs, so );
+		}
+	}
+}
+
+static void send_result(
+	Operation		*op,
+	SlapReply		*rs,
+	sort_op			*so)
+{
+	LDAPControl *ctrls[3];
+	int rc, i = 0;
+
+	rc = pack_sss_response_control( op, rs, ctrls );
+	if ( rc == LDAP_SUCCESS ) {
+		i++;
+		rc = -1;
+		if ( so->so_paged > SLAP_CONTROL_IGNORED ) {
+			rc = pack_pagedresult_response_control( op, rs, so, ctrls+1 );
+		} else if ( so->so_vlv > SLAP_CONTROL_IGNORED ) {
+			rc = pack_vlv_response_control( op, rs, so, ctrls+1 );
+		}
+		if ( rc == LDAP_SUCCESS )
+			i++;
+	}
+	ctrls[i] = NULL;
+
+	if ( ctrls[0] != NULL )
+		slap_add_ctrls( op, rs, ctrls );
+	send_ldap_result( op, rs );
+
+	if ( so->so_tree == NULL ) {
+		/* Search finished, so clean up */
+		free_sort_op( op->o_conn, so );
+	}
+}
+
+static int sssvlv_op_response(
+	Operation	*op,
+	SlapReply	*rs )
+{
+	sort_ctrl *sc = op->o_controls[sss_cid];
+	sort_op *so = op->o_callback->sc_private;
+
+	if ( rs->sr_type == REP_SEARCH ) {
+		int i;
+		size_t len;
+		sort_node *sn, *sn2;
+		struct berval *bv;
+		char *ptr;
+
+		len = sizeof(sort_node) + sc->sc_nkeys * sizeof(struct berval) +
+			rs->sr_entry->e_nname.bv_len + 1;
+		sn = op->o_tmpalloc( len, op->o_tmpmemctx );
+		sn->sn_vals = (struct berval *)(sn+1);
+
+		/* Build tmp list of key values */
+		for ( i=0; i<sc->sc_nkeys; i++ ) {
+			Attribute *a = attr_find( rs->sr_entry->e_attrs,
+				sc->sc_keys[i].sk_ad );
+			if ( a ) {
+				if ( a->a_numvals > 1 ) {
+					bv = select_value( a, &sc->sc_keys[i] );
+				} else {
+					bv = a->a_nvals;
+				}
+				sn->sn_vals[i] = *bv;
+				len += bv->bv_len + 1;
+			} else {
+				BER_BVZERO( &sn->sn_vals[i] );
+			}
+		}
+
+		/* Now dup into regular memory */
+		sn2 = ch_malloc( len );
+		sn2->sn_vals = (struct berval *)(sn2+1);
+		AC_MEMCPY( sn2->sn_vals, sn->sn_vals,
+				sc->sc_nkeys * sizeof(struct berval));
+
+		ptr = (char *)(sn2->sn_vals + sc->sc_nkeys);
+		sn2->sn_dn.bv_val = ptr;
+		sn2->sn_dn.bv_len = rs->sr_entry->e_nname.bv_len;
+		AC_MEMCPY( ptr, rs->sr_entry->e_nname.bv_val,
+			rs->sr_entry->e_nname.bv_len );
+		ptr += rs->sr_entry->e_nname.bv_len;
+		*ptr++ = '\0';
+		for ( i=0; i<sc->sc_nkeys; i++ ) {
+			if ( !BER_BVISNULL( &sn2->sn_vals[i] )) {
+				AC_MEMCPY(ptr, sn2->sn_vals[i].bv_val, sn2->sn_vals[i].bv_len);
+				sn2->sn_vals[i].bv_val = ptr;
+				ptr += sn2->sn_vals[i].bv_len;
+				*ptr++ = '\0';
+			}
+		}
+		op->o_tmpfree( sn, op->o_tmpmemctx );
+		sn = sn2;
+		sn->sn_conn = op->o_conn->c_conn_idx;
+
+		/* Insert into the AVL tree */
+		tavl_insert(&(so->so_tree), sn, node_insert, avl_dup_error);
+
+		so->so_nentries++;
+
+		/* Collected the keys so that they can be sorted.  Thus, stop
+		 * the entry from propagating.
+		 */
+		rs->sr_err = LDAP_SUCCESS;
+	}
+	else if ( rs->sr_type == REP_RESULT ) {
+		/* Remove serversort response callback.
+		 * We don't want the entries that we are about to send to be
+		 * processed by serversort response again.
+		 */
+		if ( op->o_callback->sc_response == sssvlv_op_response ) {
+			op->o_callback = op->o_callback->sc_next;
+		}
+
+		send_entry( op, rs, so );
+		send_result( op, rs, so );
+	}
+
+	return rs->sr_err;
+}
+
+static int sssvlv_op_search(
+	Operation		*op,
+	SlapReply		*rs)
+{
+	slap_overinst			*on			= (slap_overinst *)op->o_bd->bd_info;
+	sssvlv_info				*si			= on->on_bi.bi_private;
+	int						rc			= SLAP_CB_CONTINUE;
+	int	ok;
+	sort_op *so, so2;
+	sort_ctrl *sc = op->o_controls[sss_cid];
+	PagedResultsState *ps;
+	vlv_ctrl *vc;
+
+	if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) {
+		if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) {
+			LDAPControl *ctrls[2];
+			so2.so_vcontext = 0;
+			so2.so_vlv_target = 0;
+			so2.so_nentries = 0;
+			so2.so_vlv_rc = LDAP_VLV_SSS_MISSING;
+			rc = pack_vlv_response_control( op, rs, &so2, ctrls );
+			if ( rc == LDAP_SUCCESS ) {
+				ctrls[1] = NULL;
+				slap_add_ctrls( op, rs, ctrls );
+			}
+			rs->sr_err = LDAP_VLV_ERROR;
+			rs->sr_text = "Sort control is required with VLV";
+			goto leave;
+		}
+		/* Not server side sort so just continue */
+		return SLAP_CB_CONTINUE;
+	}
+
+	Debug(LDAP_DEBUG_TRACE,
+		"==> sssvlv_search: <%s> %s, control flag: %d\n",
+		op->o_req_dn.bv_val, op->ors_filterstr.bv_val,
+		op->o_ctrlflag[sss_cid]);
+
+	if ( sc->sc_nkeys > si->svi_max_keys ) {
+		rs->sr_text = "Too many sort keys";
+		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+		goto leave;
+	}
+
+	ps = ( op->o_pagedresults > SLAP_CONTROL_IGNORED ) ?
+		(PagedResultsState*)(op->o_pagedresults_state) : NULL;
+	vc = op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ?
+		op->o_controls[vlv_cid] : NULL;
+
+	if ( ps && vc ) {
+		rs->sr_text = "VLV incompatible with PagedResults";
+		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+		goto leave;
+	}
+
+	ok = 1;
+	ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
+	so = sort_conns[op->o_conn->c_conn_idx];
+	/* Is there already a sort running on this conn? */
+	if ( so ) {
+		/* Is it a continuation of a VLV search? */
+		if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED ||
+			vc->vc_context != so->so_vcontext ) {
+			/* Is it a continuation of a paged search? */
+			if ( !ps || so->so_paged <= SLAP_CONTROL_IGNORED ||
+				op->o_conn->c_pagedresults_state.ps_cookie != ps->ps_cookie ) {
+				ok = 0;
+			} else if ( !ps->ps_size ) {
+			/* Abandoning current request */
+				ok = 0;
+				so->so_nentries = 0;
+				rs->sr_err = LDAP_SUCCESS;
+			}
+		}
+		if (( vc && so->so_paged > SLAP_CONTROL_IGNORED ) ||
+			( ps && so->so_vlv > SLAP_CONTROL_IGNORED )) {
+			/* changed from paged to vlv or vice versa, abandon */
+			ok = 0;
+			so->so_nentries = 0;
+			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+		}
+	/* Are there too many running overall? */
+	} else if ( si->svi_num >= si->svi_max ) {
+		ok = 0;
+	} else {
+		/* OK, this connection now has a sort running */
+		si->svi_num++;
+		sort_conns[op->o_conn->c_conn_idx] = &so2;
+	}
+	ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
+	if ( ok ) {
+		/* are we continuing a VLV search? */
+		if ( vc && vc->vc_context ) {
+			so->so_ctrl = sc;
+			send_list( op, rs, so );
+			send_result( op, rs, so );
+			rc = LDAP_SUCCESS;
+		/* are we continuing a paged search? */
+		} else if ( ps && ps->ps_cookie ) {
+			so->so_ctrl = sc;
+			send_page( op, rs, so );
+			send_result( op, rs, so );
+			rc = LDAP_SUCCESS;
+		} else {
+			slap_callback *cb = op->o_tmpalloc( sizeof(slap_callback),
+				op->o_tmpmemctx );
+			/* Install serversort response callback to handle a new search */
+			if ( ps || vc ) {
+				so = ch_malloc( sizeof(sort_op));
+			} else {
+				so = op->o_tmpalloc( sizeof(sort_op), op->o_tmpmemctx );
+			}
+			sort_conns[op->o_conn->c_conn_idx] = so;
+
+			cb->sc_cleanup		= NULL;
+			cb->sc_response		= sssvlv_op_response;
+			cb->sc_next			= op->o_callback;
+			cb->sc_private		= so;
+
+			so->so_tree = NULL;
+			so->so_ctrl = sc;
+			so->so_info = si;
+			if ( ps ) {
+				so->so_paged = op->o_pagedresults;
+				so->so_page_size = ps->ps_size;
+				op->o_pagedresults = SLAP_CONTROL_IGNORED;
+			} else {
+				so->so_paged = 0;
+				so->so_page_size = 0;
+				if ( vc ) {
+					so->so_vlv = op->o_ctrlflag[vlv_cid];
+					so->so_vlv_target = 0;
+					so->so_vlv_rc = 0;
+				}
+			}
+			so->so_vcontext = (unsigned long)so;
+			so->so_nentries = 0;
+
+			op->o_callback		= cb;
+		}
+	} else {
+		if ( so && !so->so_nentries ) {
+			free_sort_op( op->o_conn, so );
+		} else {
+			rs->sr_text = "Other sort requests already in progress";
+			rs->sr_err = LDAP_BUSY;
+		}
+leave:
+		rc = rs->sr_err;
+		send_ldap_result( op, rs );
+	}
+
+	return rc;
+}
+
+static int get_ordering_rule(
+	AttributeDescription	*ad,
+	struct berval			*matchrule,
+	SlapReply				*rs,
+	MatchingRule			**ordering )
+{
+	MatchingRule* mr;
+
+	if ( matchrule && matchrule->bv_val ) {
+		mr = mr_find( matchrule->bv_val );
+		if ( mr == NULL ) {
+			rs->sr_err = LDAP_INAPPROPRIATE_MATCHING;
+			rs->sr_text = "serverSort control: No ordering rule";
+			Debug(LDAP_DEBUG_TRACE, "%s: no ordering rule function for %s\n",
+				debug_header, matchrule->bv_val, 0);
+		}
+	}
+	else {
+		mr = ad->ad_type->sat_ordering;
+		if ( mr == NULL ) {
+			rs->sr_err = LDAP_INAPPROPRIATE_MATCHING;
+			rs->sr_text = "serverSort control: No ordering rule";
+			Debug(LDAP_DEBUG_TRACE,
+				"%s: no ordering rule specified and no default ordering rule for attribute %s\n",
+				debug_header, ad->ad_cname.bv_val, 0);
+		}
+	}
+
+	*ordering = mr;
+	return rs->sr_err;
+}
+
+static int count_key(BerElement *ber)
+{
+	char *end;
+	ber_len_t len;
+	ber_tag_t tag;
+	int count = 0;
+
+	/* Server Side Sort Control is a SEQUENCE of SEQUENCE */
+	for ( tag = ber_first_element( ber, &len, &end );
+		  tag == LBER_SEQUENCE;
+		  tag = ber_next_element( ber, &len, end ))
+	{
+		tag = ber_skip_tag( ber, &len );
+		ber_skip_data( ber, len );
+		++count;
+	}
+	ber_rewind( ber );
+
+	return count;
+}
+
+static int build_key(
+	BerElement		*ber,
+	SlapReply		*rs,
+	sort_key			*key )
+{
+	struct berval attr;
+	struct berval matchrule = BER_BVNULL;
+	ber_int_t reverse = 0;
+	ber_tag_t tag;
+	ber_len_t len;
+	MatchingRule *ordering = NULL;
+	AttributeDescription *ad = NULL;
+	const char *text;
+
+	if (( tag = ber_scanf( ber, "{" )) == LBER_ERROR ) {
+		rs->sr_text = "serverSort control: decoding error";
+		rs->sr_err = LDAP_PROTOCOL_ERROR;
+		return rs->sr_err;
+	}
+
+	if (( tag = ber_scanf( ber, "m", &attr )) == LBER_ERROR ) {
+		rs->sr_text = "serverSort control: attribute decoding error";
+		rs->sr_err = LDAP_PROTOCOL_ERROR;
+		return rs->sr_err;
+	}
+
+	tag = ber_peek_tag( ber, &len );
+	if ( tag == LDAP_MATCHRULE_IDENTIFIER ) {
+		if (( tag = ber_scanf( ber, "m", &matchrule )) == LBER_ERROR ) {
+			rs->sr_text = "serverSort control: matchrule decoding error";
+			rs->sr_err = LDAP_PROTOCOL_ERROR;
+			return rs->sr_err;
+		}
+		tag = ber_peek_tag( ber, &len );
+	}
+
+	if ( tag == LDAP_REVERSEORDER_IDENTIFIER ) {
+		if (( tag = ber_scanf( ber, "b", &reverse )) == LBER_ERROR ) {
+			rs->sr_text = "serverSort control: reverse decoding error";
+			rs->sr_err = LDAP_PROTOCOL_ERROR;
+			return rs->sr_err;
+		}
+	}
+
+	if (( tag = ber_scanf( ber, "}" )) == LBER_ERROR ) {
+		rs->sr_text = "serverSort control: decoding error";
+		rs->sr_err = LDAP_PROTOCOL_ERROR;
+		return rs->sr_err;
+	}
+
+	if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS ) {
+		rs->sr_text =
+			"serverSort control: Unrecognized attribute type in sort key";
+		Debug(LDAP_DEBUG_TRACE,
+			"%s: Unrecognized attribute type in sort key: %s\n",
+			debug_header, SAFESTR(attr.bv_val, "<None>"), 0);
+		rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
+		return rs->sr_err;
+	}
+
+	/* get_ordering_rule will set sr_err and sr_text */
+	get_ordering_rule( ad, &matchrule, rs, &ordering );
+	if ( rs->sr_err != LDAP_SUCCESS ) {
+		return rs->sr_err;
+	}
+
+	key->sk_ad = ad;
+	key->sk_ordering = ordering;
+	key->sk_direction = reverse ? -1 : 1;
+
+	return rs->sr_err;
+}
+
+static int sss_parseCtrl(
+	Operation		*op,
+	SlapReply		*rs,
+	LDAPControl		*ctrl )
+{
+	BerElementBuffer	berbuf;
+	BerElement			*ber;
+	ber_tag_t		tag;
+	ber_len_t		len;
+	int					i;
+	sort_ctrl	*sc;
+
+	rs->sr_err = LDAP_PROTOCOL_ERROR;
+
+	if ( op->o_ctrlflag[sss_cid] > SLAP_CONTROL_IGNORED ) {
+		rs->sr_text = "sorted results control specified multiple times";
+	} else if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+		rs->sr_text = "sorted results control value is absent";
+	} else if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+		rs->sr_text = "sorted results control value is empty";
+	} else {
+		rs->sr_err = LDAP_SUCCESS;
+	}
+	if ( rs->sr_err != LDAP_SUCCESS )
+		return rs->sr_err;
+
+	op->o_ctrlflag[sss_cid] = ctrl->ldctl_iscritical ?
+		SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
+
+	ber = (BerElement *)&berbuf;
+	ber_init2( ber, &ctrl->ldctl_value, 0 );
+	i = count_key( ber );
+
+	sc = op->o_tmpalloc( sizeof(sort_ctrl) +
+		(i-1) * sizeof(sort_key), op->o_tmpmemctx );
+	sc->sc_nkeys = i;
+	op->o_controls[sss_cid] = sc;
+
+	/* peel off initial sequence */
+	ber_scanf( ber, "{" );
+
+	i = 0;
+	do {
+		if ( build_key( ber, rs, &sc->sc_keys[i] ) != LDAP_SUCCESS )
+			break;
+		i++;
+		tag = ber_peek_tag( ber, &len );
+	} while ( tag != LBER_DEFAULT );
+
+	return rs->sr_err;
+}
+
+static int vlv_parseCtrl(
+	Operation		*op,
+	SlapReply		*rs,
+	LDAPControl		*ctrl )
+{
+	BerElementBuffer	berbuf;
+	BerElement			*ber;
+	ber_tag_t		tag;
+	ber_len_t		len;
+	int					i;
+	vlv_ctrl	*vc, vc2;
+
+	rs->sr_err = LDAP_PROTOCOL_ERROR;
+	rs->sr_text = NULL;
+
+	if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) {
+		rs->sr_text = "vlv control specified multiple times";
+	} else if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+		rs->sr_text = "vlv control value is absent";
+	} else if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+		rs->sr_text = "vlv control value is empty";
+	}
+	if ( rs->sr_text != NULL )
+		return rs->sr_err;
+
+	op->o_ctrlflag[vlv_cid] = ctrl->ldctl_iscritical ?
+		SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
+
+	ber = (BerElement *)&berbuf;
+	ber_init2( ber, &ctrl->ldctl_value, 0 );
+
+	rs->sr_err = LDAP_PROTOCOL_ERROR;
+
+	tag = ber_scanf( ber, "{ii", &vc2.vc_before, &vc2.vc_after );
+	if ( tag == LBER_ERROR ) {
+		return rs->sr_err;
+	}
+
+	tag = ber_peek_tag( ber, &len );
+	if ( tag == LDAP_VLVBYINDEX_IDENTIFIER ) {
+		tag = ber_scanf( ber, "{ii}", &vc2.vc_offset, &vc2.vc_count );
+		if ( tag == LBER_ERROR )
+			return rs->sr_err;
+		BER_BVZERO( &vc2.vc_value );
+	} else if ( tag == LDAP_VLVBYVALUE_IDENTIFIER ) {
+		tag = ber_scanf( ber, "m", &vc2.vc_value );
+		if ( tag == LBER_ERROR || BER_BVISNULL( &vc2.vc_value ))
+			return rs->sr_err;
+	} else {
+		return rs->sr_err;
+	}
+	tag = ber_peek_tag( ber, &len );
+	if ( tag == LDAP_VLVCONTEXT_IDENTIFIER ) {
+		struct berval bv;
+		tag = ber_scanf( ber, "m", &bv );
+		if ( tag == LBER_ERROR || bv.bv_len != sizeof(vc2.vc_context))
+			return rs->sr_err;
+		AC_MEMCPY( &vc2.vc_context, bv.bv_val, bv.bv_len );
+	} else {
+		vc2.vc_context = 0;
+	}
+
+	vc = op->o_tmpalloc( sizeof(vlv_ctrl), op->o_tmpmemctx );
+	*vc = vc2;
+	op->o_controls[vlv_cid] = vc;
+	rs->sr_err = LDAP_SUCCESS;
+
+	return rs->sr_err;
+}
+
+static int sssvlv_connection_destroy( BackendDB *be, Connection *conn )
+{
+	slap_overinst	*on		= (slap_overinst *)be->bd_info;
+
+	if ( sort_conns[conn->c_conn_idx] )
+		free_sort_op( conn, sort_conns[conn->c_conn_idx] );
+
+	return LDAP_SUCCESS;
+}
+
+static int sssvlv_db_open(
+	BackendDB		*be,
+	ConfigReply		*cr )
+{
+	slap_overinst	*on = (slap_overinst *)be->bd_info;
+	sssvlv_info *si = on->on_bi.bi_private;
+	int rc;
+
+	/* If not set, default to 1/2 of available threads */
+	if ( !si->svi_max )
+		si->svi_max = connection_pool_max / 2;
+
+	rc = overlay_register_control( be, LDAP_CONTROL_SORTREQUEST );
+	if ( rc == LDAP_SUCCESS )
+		rc = overlay_register_control( be, LDAP_CONTROL_VLVREQUEST );
+	return rc;
+}
+
+static ConfigTable sssvlv_cfg[] = {
+	{ "sssvlv-max", "num",
+		2, 2, 0, ARG_INT|ARG_OFFSET,
+			(void *)offsetof(sssvlv_info, svi_max),
+		"( OLcfgOvAt:21.1 NAME 'olcSssVlvMax' "
+			"DESC 'Maximum number of concurrent Sort requests' "
+			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+	{ "sssvlv-maxkeys", "num",
+		2, 2, 0, ARG_INT|ARG_OFFSET,
+			(void *)offsetof(sssvlv_info, svi_max_keys),
+		"( OLcfgOvAt:21.2 NAME 'olcSssVlvMaxKeys' "
+			"DESC 'Maximum number of Keys in a Sort request' "
+			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
+};
+
+static ConfigOCs sssvlv_ocs[] = {
+	{ "( OLcfgOvOc:21.1 "
+		"NAME 'olcSssVlvConfig' "
+		"DESC 'SSS VLV configuration' "
+		"SUP olcOverlayConfig "
+		"MAY ( olcSssVlvMax $ olcSssVlvMaxKeys ) )",
+		Cft_Overlay, sssvlv_cfg, NULL, NULL },
+	{ NULL, 0, NULL }
+};
+
+static int sssvlv_db_init(
+	BackendDB		*be,
+	ConfigReply		*cr)
+{
+	slap_overinst	*on = (slap_overinst *)be->bd_info;
+	sssvlv_info *si;
+	
+	si = (sssvlv_info *)ch_malloc(sizeof(sssvlv_info));
+	on->on_bi.bi_private = si;
+
+	si->svi_max = 0;
+	si->svi_num = 0;
+	si->svi_max_keys = SSSVLV_DEFAULT_MAX_KEYS;
+
+	if ( dtblsize && !sort_conns ) {
+		ldap_pvt_thread_mutex_init( &sort_conns_mutex );
+		/* accommodate for c_conn_idx == -1 */
+		sort_conns = ch_calloc( sizeof(sort_op *), dtblsize + 1 );
+		sort_conns++;
+	}
+
+	return LDAP_SUCCESS;
+}
+
+static int sssvlv_db_destroy(
+	BackendDB		*be,
+	ConfigReply		*cr )
+{
+	slap_overinst	*on = (slap_overinst *)be->bd_info;
+	sssvlv_info *si = (sssvlv_info *)on->on_bi.bi_private;
+	
+	if ( si ) {
+		ch_free( si );
+		on->on_bi.bi_private = NULL;
+	}
+	return LDAP_SUCCESS;
+}
+
+static slap_overinst sssvlv;
+
+int sssvlv_initialize()
+{
+	int rc;
+
+	sssvlv.on_bi.bi_type				= "sssvlv";
+	sssvlv.on_bi.bi_db_init				= sssvlv_db_init;
+	sssvlv.on_bi.bi_db_destroy			= sssvlv_db_destroy;
+	sssvlv.on_bi.bi_db_open				= sssvlv_db_open;
+	sssvlv.on_bi.bi_connection_destroy	= sssvlv_connection_destroy;
+	sssvlv.on_bi.bi_op_search			= sssvlv_op_search;
+
+	sssvlv.on_bi.bi_cf_ocs = sssvlv_ocs;
+
+	rc = config_register_schema( sssvlv_cfg, sssvlv_ocs );
+	if ( rc )
+		return rc;
+
+	rc = register_supported_control2( LDAP_CONTROL_SORTREQUEST,
+			SLAP_CTRL_SEARCH,
+			NULL,
+			sss_parseCtrl,
+			1 /* replace */,
+			&sss_cid );
+
+	if ( rc == LDAP_SUCCESS ) {
+		rc = register_supported_control2( LDAP_CONTROL_VLVREQUEST,
+			SLAP_CTRL_SEARCH,
+			NULL,
+			vlv_parseCtrl,
+			1 /* replace */,
+			&vlv_cid );
+	}
+
+	if ( rc == LDAP_SUCCESS ) {
+		rc = overlay_register( &sssvlv );
+		if ( rc != LDAP_SUCCESS ) {
+			fprintf( stderr, "Failed to register server side sort overlay\n" );
+		}
+	}
+	else {
+		fprintf( stderr, "Failed to register control %d\n", rc );
+	}
+
+	return rc;
+}
+
+#if SLAPD_OVER_SSSVLV == SLAPD_MOD_DYNAMIC
+int init_module( int argc, char *argv[])
+{
+	return sssvlv_initialize();
+}
+#endif
+
+#endif /* SLAPD_OVER_SSSVLV */

Modified: openldap/trunk/servers/slapd/overlays/translucent.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/translucent.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/translucent.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* translucent.c - translucent proxy module */
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/translucent.c,v 1.13.2.27 2009/06/08 19:27:05 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/translucent.c,v 1.13.2.32 2009/08/25 23:05:25 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -158,7 +158,8 @@
 
 	/* FIXME: should not hardcode "olcDatabase" here */
 	bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
-		"olcDatabase=%s", ov->db.bd_info->bi_type );
+		"olcDatabase=" SLAP_X_ORDERED_FMT "%s",
+		0, ov->db.bd_info->bi_type );
 	if ( bv.bv_len >= sizeof( ca->cr_msg ) ) {
 		return -1;
 	}
@@ -282,22 +283,6 @@
 }
 
 /*
-** dup_bervarray()
-**	copy a BerVarray;
-*/
-
-BerVarray dup_bervarray(BerVarray b) {
-	int i, len;
-	BerVarray nb;
-	for(len = 0; b[len].bv_val; len++);
-	nb = ch_malloc((len+1) * sizeof(BerValue));
-	for(i = 0; i < len; i++) ber_dupbv(&nb[i], &b[i]);
-	nb[len].bv_val = NULL;
-	nb[len].bv_len = 0;
-	return(nb);
-}
-
-/*
 ** free_attr_chain()
 **	free only the Attribute*, not the contents;
 **
@@ -785,6 +770,8 @@
 	Filter *orig;
 	Avlnode *list;
 	int step;
+	int slimit;
+	AttributeName *attrs;
 } trans_ctx;
 
 static int translucent_search_cb(Operation *op, SlapReply *rs) {
@@ -809,6 +796,13 @@
 	Debug(LDAP_DEBUG_TRACE, "==> translucent_search_cb: %s\n",
 		rs->sr_entry->e_name.bv_val, 0, 0);
 
+	op->ors_slimit = tc->slimit + ( tc->slimit > 0 ? 1 : 0 );
+	if ( op->ors_attrs == slap_anlist_all_attributes ) {
+		op->ors_attrs = tc->attrs;
+		rs->sr_attrs = tc->attrs;
+		rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );
+	}
+
 	on = tc->on;
 	ov = on->on_bi.bi_private;
 
@@ -834,6 +828,11 @@
 				if ( rc == LDAP_COMPARE_TRUE ) {
 					rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
 					rs->sr_entry = re;
+
+					if ( tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) {
+						return LDAP_SIZELIMIT_EXCEEDED;
+					}
+
 					return SLAP_CB_CONTINUE;
 				} else {
 					entry_free( re );
@@ -883,12 +882,16 @@
 		for(ax = le->e_attrs; ax; ax = ax->a_next) {
 			for(a = re->e_attrs; a; a = a->a_next) {
 				if(a->a_desc == ax->a_desc) {
+					test_f = 1;
 					if(a->a_vals != a->a_nvals)
 						ber_bvarray_free(a->a_nvals);
 					ber_bvarray_free(a->a_vals);
-					a->a_vals = dup_bervarray(ax->a_vals);
-					a->a_nvals = (ax->a_vals == ax->a_nvals) ?
-						a->a_vals : dup_bervarray(ax->a_nvals);
+					ber_bvarray_dup_x( &a->a_vals, ax->a_vals, NULL );
+					if ( ax->a_vals == ax->a_nvals ) {
+						a->a_nvals = a->a_vals;
+					} else {
+						ber_bvarray_dup_x( &a->a_nvals, ax->a_nvals, NULL );
+					}
 					break;
 				}
 			}
@@ -963,6 +966,11 @@
 	}
 
 	op->o_bd = db;
+
+	if ( rc == SLAP_CB_CONTINUE && tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) {
+		return LDAP_SIZELIMIT_EXCEEDED;
+	}
+
 	return rc;
 }
 
@@ -1105,13 +1113,16 @@
 	tc.orig = op->ors_filter;
 	tc.list = NULL;
 	tc.step = 0;
+	tc.slimit = op->ors_slimit;
+	tc.attrs = NULL;
 	fbv = op->ors_filterstr;
 
 	op->o_callback = &cb;
 
 	if ( fr || !fl ) {
-		AttributeName *attrs = op->ors_attrs;
-		op->ors_attrs = NULL;
+		tc.attrs = op->ors_attrs;
+		op->ors_slimit = SLAP_NO_LIMIT;
+		op->ors_attrs = slap_anlist_all_attributes;
 		op->o_bd = &ov->db;
 		tc.step |= RMT_SIDE;
 		if ( fl ) {
@@ -1120,7 +1131,7 @@
 			filter2bv_x( op, fr, &op->ors_filterstr );
 		}
 		rc = ov->db.bd_info->bi_op_search(op, rs);
-		op->ors_attrs = attrs;
+		op->ors_attrs = tc.attrs;
 		op->o_bd = tc.db;
 		if ( fl ) {
 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
@@ -1137,6 +1148,7 @@
 	op->ors_filter = tc.orig;
 	op->o_callback = cb.sc_next;
 	rs->sr_attrs = op->ors_attrs;
+	rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );
 
 	/* Send out anything remaining on the list and finish */
 	if ( tc.step & USE_LIST ) {
@@ -1162,6 +1174,8 @@
 		send_ldap_result( op, rs );
 	}
 
+	op->ors_slimit = tc.slimit;
+
 	/* Free in reverse order */
 	if ( fl )
 		trans_filter_free( op, fl );

Modified: openldap/trunk/servers/slapd/overlays/unique.c
===================================================================
--- openldap/trunk/servers/slapd/overlays/unique.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/overlays/unique.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* unique.c - attribute uniqueness module */
-/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/unique.c,v 1.20.2.14 2009/01/22 00:01:13 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/unique.c,v 1.20.2.16 2009/08/02 18:44:04 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -47,6 +47,7 @@
 	struct berval dn;
 	struct berval ndn;
 	struct berval filter;
+	Filter *f;
 	struct unique_attrs_s *attrs;
 	int scope;
 } unique_domain_uri;
@@ -141,6 +142,7 @@
 		ch_free ( uri->dn.bv_val );
 		ch_free ( uri->ndn.bv_val );
 		ch_free ( uri->filter.bv_val );
+		filter_free( uri->f );
 		attr = uri->attrs;
 		while ( attr ) {
 			next_attr = attr->next;
@@ -214,6 +216,13 @@
 			rc = ARG_BAD_CONF;
 			goto exit;
 		}
+
+		if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
+			Debug( LDAP_DEBUG_ANY,
+				"slapo-unique needs a rootdn; "
+				"backend <%s> has none, YMMV.\n",
+				be->be_nsuffix[0].bv_val, 0, 0 );
+		}
 	}
 
 	attr_str = url_desc->lud_attrs;
@@ -247,17 +256,16 @@
 	}
 
 	if (url_desc->lud_filter) {
-		Filter *f = str2filter( url_desc->lud_filter );
 		char *ptr;
-		if ( !f ) {
+		uri->f = str2filter( url_desc->lud_filter );
+		if ( !uri->f ) {
 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
 				  "unique: bad filter");
 			rc = ARG_BAD_CONF;
 			goto exit;
 		}
 		/* make sure the strfilter is in normal form (ITS#5581) */
-		filter2bv( f, &uri->filter );
-		filter_free( f );
+		filter2bv( uri->f, &uri->filter );
 		ptr = strstr( uri->filter.bv_val, "(?=" /*)*/ );
 		if ( ptr != NULL && ptr <= ( uri->filter.bv_val - STRLENOF( "(?=" /*)*/ ) + uri->filter.bv_len ) )
 		{
@@ -459,6 +467,13 @@
 		abort();
 	}
 
+	if ( rc ) {
+		ch_free( c->value_dn.bv_val );
+		BER_BVZERO( &c->value_dn );
+		ch_free( c->value_ndn.bv_val );
+		BER_BVZERO( &c->value_ndn );
+	}
+
 	return rc;
 }
 
@@ -1071,6 +1086,17 @@
 			     && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
 				continue;
 
+			if ( uri->f ) {
+				if ( test_filter( NULL, op->ora_e, uri->f )
+					== LDAP_COMPARE_FALSE )
+				{
+					Debug( LDAP_DEBUG_TRACE,
+						"==> unique_add_skip<%s>\n",
+						op->o_req_dn.bv_val, 0, 0 );
+					continue;
+				}
+			}
+
 			if(!(a = op->ora_e->e_attrs)) {
 				op->o_bd->bd_info = (BackendInfo *) on->on_info;
 				send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,

Modified: openldap/trunk/servers/slapd/passwd.c
===================================================================
--- openldap/trunk/servers/slapd/passwd.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/passwd.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* passwd.c - password extended operation routines */
-/* $OpenLDAP: pkg/ldap/servers/slapd/passwd.c,v 1.128.2.12 2009/01/22 00:01:02 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/passwd.c,v 1.128.2.13 2009/08/25 21:36:51 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -57,6 +57,7 @@
 	int rc;
 	BackendDB *op_be;
 	int freenewpw = 0;
+	struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
 
 	assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
 
@@ -100,19 +101,22 @@
 	}
 
 	if ( !BER_BVISEMPTY( &id ) ) {
-		rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
-				&op->o_req_ndn, op->o_tmpmemctx );
+		rs->sr_err = dnPrettyNormal( NULL, &id, &dn, &ndn, op->o_tmpmemctx );
 		id.bv_val[id.bv_len] = idNul;
 		if ( rs->sr_err != LDAP_SUCCESS ) {
 			rs->sr_text = "Invalid DN";
 			rc = rs->sr_err;
 			goto error_return;
 		}
+		op->o_req_dn = dn;
+		op->o_req_ndn = ndn;
 		op->o_bd = select_backend( &op->o_req_ndn, 1 );
 
 	} else {
-		ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
-		ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
+		ber_dupbv_x( &dn, &op->o_dn, op->o_tmpmemctx );
+		ber_dupbv_x( &ndn, &op->o_ndn, op->o_tmpmemctx );
+		op->o_req_dn = dn;
+		op->o_req_ndn = ndn;
 		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
 		op->o_bd = op->o_conn->c_authz_backend;
 		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
@@ -313,12 +317,12 @@
 	if ( freenewpw ) {
 		free( qpw->rs_new.bv_val );
 	}
-	if ( !BER_BVISNULL( &op->o_req_dn ) ) {
-		op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
+	if ( !BER_BVISNULL( &dn ) ) {
+		op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
 		BER_BVZERO( &op->o_req_dn );
 	}
-	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
-		op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
+	if ( !BER_BVISNULL( &ndn ) ) {
+		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
 		BER_BVZERO( &op->o_req_ndn );
 	}
 

Modified: openldap/trunk/servers/slapd/proto-slap.h
===================================================================
--- openldap/trunk/servers/slapd/proto-slap.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/proto-slap.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/proto-slap.h,v 1.670.2.49 2009/06/02 23:58:20 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/proto-slap.h,v 1.670.2.54 2009/08/25 22:44:25 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -851,6 +851,10 @@
 LDAP_SLAPD_V (const char *) slapd_slp_attrs;
 LDAP_SLAPD_V (slap_ssf_t) local_ssf;
 LDAP_SLAPD_V (struct runqueue_s) slapd_rq;
+#ifdef LDAP_TCP_BUFFER
+LDAP_SLAPD_V (int) slapd_tcp_rmem;
+LDAP_SLAPD_V (int) slapd_tcp_wmem;
+#endif /* LDAP_TCP_BUFFER */
 
 #ifdef HAVE_WINSOCK
 LDAP_SLAPD_F (ber_socket_t) slapd_socknew(ber_socket_t s);
@@ -922,6 +926,12 @@
 LDAP_SLAPD_F (int) dnIsSuffix LDAP_P((
 	const struct berval *dn, const struct berval *suffix ));
 
+LDAP_SLAPD_F (int) dnIsWithinScope LDAP_P((
+	struct berval *ndn, struct berval *nbase, int scope ));
+
+LDAP_SLAPD_F (int) dnIsSuffixScope LDAP_P((
+	struct berval *ndn, struct berval *nbase, int scope ));
+
 LDAP_SLAPD_F (int) dnIsOneLevelRDN LDAP_P(( struct berval *rdn ));
 
 LDAP_SLAPD_F (int) dnExtractRdn LDAP_P((
@@ -985,6 +995,7 @@
 LDAP_SLAPD_F (int) entry_dn_cmp LDAP_P(( const void *v_a, const void *v_b ));
 LDAP_SLAPD_F (int) entry_id_cmp LDAP_P(( const void *v_a, const void *v_b ));
 LDAP_SLAPD_F (Entry *) entry_dup LDAP_P(( Entry *e ));
+LDAP_SLAPD_F (Entry *) entry_dup2 LDAP_P(( Entry *dest, Entry *src ));
 LDAP_SLAPD_F (Entry *) entry_dup_bv LDAP_P(( Entry *e ));
 LDAP_SLAPD_F (Entry *) entry_alloc LDAP_P((void));
 LDAP_SLAPD_F (int) entry_prealloc LDAP_P((int num));
@@ -1767,6 +1778,9 @@
 
 LDAP_SLAPD_F (int)  syncrepl_add_glue LDAP_P(( 
 					Operation*, Entry* ));
+LDAP_SLAPD_F (void) syncrepl_diff_entry LDAP_P((
+	Operation *op, Attribute *old, Attribute *anew,
+	Modifications **mods, Modifications **ml, int is_ctx ));
 LDAP_SLAPD_F (void) syncinfo_free LDAP_P(( struct syncinfo_s *, int all ));
 
 /* syntax.c */

Modified: openldap/trunk/servers/slapd/result.c
===================================================================
--- openldap/trunk/servers/slapd/result.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/result.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* result.c - routines to send ldap results, errors, and referrals */
-/* $OpenLDAP: pkg/ldap/servers/slapd/result.c,v 1.289.2.28 2009/07/01 17:01:58 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/result.c,v 1.289.2.30 2009/08/13 00:02:37 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -302,11 +302,11 @@
 
 		ber_printf( sber, "{e}", LDAP_UNWILLING_TO_PERFORM );
 
-		if( ber_flatten2( ber, &sorted.ldctl_value, 0 ) == -1 ) {
+		if( ber_flatten2( sber, &sorted.ldctl_value, 0 ) == -1 ) {
 			return -1;
 		}
 
-		(void) ber_free_buf( ber );
+		(void) ber_free_buf( sber );
 
 		rc = send_ldap_control( ber, &sorted );
 		if( rc == -1 ) return rc;
@@ -616,6 +616,7 @@
 	assert( LDAP_UNSOLICITED_ERROR( rs->sr_err ) );
 
 	rs->sr_type = REP_EXTENDED;
+	rs->sr_rspdata = NULL;
 
 	Debug( LDAP_DEBUG_TRACE,
 		"send_ldap_disconnect %d:%s\n",

Modified: openldap/trunk/servers/slapd/sasl.c
===================================================================
--- openldap/trunk/servers/slapd/sasl.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/sasl.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/sasl.c,v 1.239.2.17 2009/06/02 22:09:53 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/sasl.c,v 1.239.2.18 2009/08/13 00:02:37 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -1540,7 +1540,7 @@
 		}
 
 		/* Must send response using old security layer */
-		if (response.bv_len) rs->sr_sasldata = &response;
+		rs->sr_sasldata = (response.bv_len ? &response : NULL);
 		send_ldap_sasl( op, rs );
 		
 		/* Now dispose of the old security layer.

Modified: openldap/trunk/servers/slapd/schema_init.c
===================================================================
--- openldap/trunk/servers/slapd/schema_init.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/schema_init.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* schema_init.c - init builtin schema */
-/* $OpenLDAP: pkg/ldap/servers/slapd/schema_init.c,v 1.386.2.33 2009/05/08 00:27:00 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/schema_init.c,v 1.386.2.36 2009/08/13 00:35:54 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -274,17 +274,24 @@
 
 /* X.509 certificate list validation */
 static int
+checkTime( struct berval *in, struct berval *out );
+
+static int
 certificateListValidate( Syntax *syntax, struct berval *in )
 {
 	BerElementBuffer berbuf;
 	BerElement *ber = (BerElement *)&berbuf;
 	ber_tag_t tag;
-	ber_len_t len;
+	ber_len_t len, wrapper_len;
+	char *wrapper_start;
+	int wrapper_ok = 0;
 	ber_int_t version = SLAP_X509_V1;
+	struct berval bvdn, bvtu;
 
 	ber_init2( ber, in, LBER_USE_DER );
-	tag = ber_skip_tag( ber, &len );	/* Signed wrapper */
+	tag = ber_skip_tag( ber, &wrapper_len );	/* Signed wrapper */
 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
+	wrapper_start = ber->ber_ptr;
 	tag = ber_skip_tag( ber, &len );	/* Sequence */
 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
 	tag = ber_peek_tag( ber, &len );
@@ -297,12 +304,18 @@
 	tag = ber_skip_tag( ber, &len );	/* Signature Algorithm */
 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
 	ber_skip_data( ber, len );
-	tag = ber_skip_tag( ber, &len );	/* Issuer DN */
+	tag = ber_peek_tag( ber, &len );	/* Issuer DN */
 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
+	len = ber_ptrlen( ber );
+	bvdn.bv_val = in->bv_val + len;
+	bvdn.bv_len = in->bv_len - len;
+	tag = ber_skip_tag( ber, &len );
 	ber_skip_data( ber, len );
 	tag = ber_skip_tag( ber, &len );	/* thisUpdate */
 	/* Time is a CHOICE { UTCTime, GeneralizedTime } */
 	if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
+	bvtu.bv_val = (char *)ber->ber_ptr;
+	bvtu.bv_len = len;
 	ber_skip_data( ber, len );
 	/* Optional nextUpdate */
 	tag = ber_skip_tag( ber, &len );
@@ -319,10 +332,11 @@
 			tag = ber_skip_tag( ber, &len );
 		}
 	}
-	/* Optional Extensions */
+	/* Optional Extensions - Sequence of Sequence */
 	if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
+		ber_len_t seqlen;
 		if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
-		tag = ber_skip_tag( ber, &len );
+		tag = ber_peek_tag( ber, &seqlen );
 		if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
 		ber_skip_data( ber, len );
 		tag = ber_skip_tag( ber, &len );
@@ -334,9 +348,44 @@
 	/* Signature */
 	if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
 	ber_skip_data( ber, len );
+	if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
 	tag = ber_skip_tag( ber, &len );
 	/* Must be at end now */
-	if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
+	/* NOTE: OpenSSL tolerates CL with garbage past the end */
+	if ( len || tag != LBER_DEFAULT ) {
+		struct berval issuer_dn = BER_BVNULL, thisUpdate;
+		char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
+		int rc;
+
+		if ( ! wrapper_ok ) {
+			return LDAP_INVALID_SYNTAX;
+		}
+
+		rc = dnX509normalize( &bvdn, &issuer_dn );
+		if ( rc != LDAP_SUCCESS ) {
+			rc = LDAP_INVALID_SYNTAX;
+			goto done;
+		}
+
+		thisUpdate.bv_val = tubuf;
+		thisUpdate.bv_len = sizeof(tubuf); 
+		if ( checkTime( &bvtu, &thisUpdate ) ) {
+			rc = LDAP_INVALID_SYNTAX;
+			goto done;
+		}
+
+		Debug( LDAP_DEBUG_ANY,
+			"certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
+			issuer_dn.bv_val, thisUpdate.bv_val, 0 );
+
+done:;
+		if ( ! BER_BVISNULL( &issuer_dn ) ) {
+			ber_memfree( issuer_dn.bv_val );
+		}
+
+		return rc;
+	}
+
 	return LDAP_SUCCESS;
 }
 
@@ -388,7 +437,7 @@
 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
 	ber_skip_data( ber, len );
 
-	ber_peek_tag( ber, &len );
+	tag = ber_peek_tag( ber, &len );
 
 	if ( tag == LBER_BITSTRING ) {	/* issuerUniqueID */
 		tag = ber_skip_tag( ber, &len );
@@ -3616,6 +3665,9 @@
 
 	rc = generalizedTimeValidate( NULL, &bv );
 	if ( rc == LDAP_SUCCESS && out != NULL ) {
+		if ( out->bv_len > bv.bv_len ) {
+			out->bv_val[ bv.bv_len ] = '\0';
+		}
 		out->bv_len = bv.bv_len;
 	}
 
@@ -6626,7 +6678,7 @@
 	{"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
 		SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
-		NULL, NULL, csnOrderingMatch,
+		NULL, csnNormalize, csnOrderingMatch,
 		NULL, NULL,
 		"CSNMatch" },
 

Modified: openldap/trunk/servers/slapd/search.c
===================================================================
--- openldap/trunk/servers/slapd/search.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/search.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/search.c,v 1.181.2.8 2009/01/22 00:01:03 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/search.c,v 1.181.2.9 2009/07/27 20:19:18 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -152,7 +152,7 @@
 		const char *dummy;	/* ignore msgs from bv2ad */
 		op->ors_attrs[i].an_desc = NULL;
 		op->ors_attrs[i].an_oc = NULL;
-		op->ors_attrs[i].an_oc_exclude = 0;
+		op->ors_attrs[i].an_flags = 0;
 		if ( slap_bv2ad( &op->ors_attrs[i].an_name,
 			&op->ors_attrs[i].an_desc, &dummy ) != LDAP_SUCCESS )
 		{

Modified: openldap/trunk/servers/slapd/slap.h
===================================================================
--- openldap/trunk/servers/slapd/slap.h	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slap.h	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* slap.h - stand alone ldap server include file */
-/* $OpenLDAP: pkg/ldap/servers/slapd/slap.h,v 1.764.2.49 2009/07/01 17:01:58 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slap.h,v 1.764.2.54 2009/08/25 22:44:25 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -62,7 +62,6 @@
 #define LDAP_COLLECTIVE_ATTRIBUTES
 #define LDAP_COMP_MATCH
 #define LDAP_SYNC_TIMESTAMP
-#define SLAP_CONTROL_X_SORTEDRESULTS
 #define SLAP_CONTROL_X_SESSION_TRACKING
 #define SLAP_CONTROL_X_WHATFAILED
 #define SLAP_CONFIG_DELETE
@@ -843,10 +842,13 @@
 #define SLAP_AD_PROXIED		0x01U
 #define	SLAP_AD_NOINSERT	0x02U
 
+#define	SLAP_AN_OCEXCLUDE	0x01
+#define	SLAP_AN_OCINITED	0x02
+
 struct AttributeName {
 	struct berval		an_name;
 	AttributeDescription	*an_desc;
-	int			an_oc_exclude;
+	int			an_flags;
 	ObjectClass		*an_oc;
 };
 
@@ -2062,9 +2064,9 @@
 	BerVarray sr_ref;
 	LDAPControl **sr_ctrls;
 	union sr_u {
+		rep_search_s sru_search;
 		rep_sasl_s sru_sasl;
 		rep_extended_s sru_extended;
-		rep_search_s sru_search;
 	} sr_un;
 	slap_mask_t sr_flags;
 #define REP_ENTRY_MODIFIABLE	0x0001U
@@ -2353,7 +2355,6 @@
 } slap_overinfo;
 
 /* Should successive callbacks in a chain be processed? */
-#define	SLAP_CB_FREEME		0x04000
 #define	SLAP_CB_BYPASS		0x08800
 #define	SLAP_CB_CONTINUE	0x08000
 
@@ -2754,7 +2755,7 @@
 #define send_ldap_intermediate( op, rs ) \
 	((op)->o_conn->c_send_ldap_intermediate)( op, rs )
 
-typedef struct slap_listener Listener;
+typedef struct Listener Listener;
 
 /*
  * represents a connection from an ldap client
@@ -2901,7 +2902,7 @@
 /*
  * listener; need to access it from monitor backend
  */
-struct slap_listener {
+struct Listener {
 	struct berval sl_url;
 	struct berval sl_name;
 	mode_t	sl_perms;
@@ -2916,6 +2917,13 @@
 	ber_socket_t sl_sd;
 	Sockaddr sl_sa;
 #define sl_addr	sl_sa.sa_in_addr
+#ifdef LDAP_DEVEL
+#define LDAP_TCP_BUFFER
+#endif
+#ifdef LDAP_TCP_BUFFER
+	int	sl_tcp_rmem;	/* custom TCP read buffer size */
+	int	sl_tcp_wmem;	/* custom TCP write buffer size */
+#endif
 };
 
 /*

Modified: openldap/trunk/servers/slapd/slapacl.c
===================================================================
--- openldap/trunk/servers/slapd/slapacl.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slapacl.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/slapacl.c,v 1.24.2.9 2009/01/22 00:01:03 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slapacl.c,v 1.24.2.10 2009/07/22 20:28:46 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -73,6 +73,7 @@
 	char			*attr = NULL;
 	int			doclose = 0;
 	BackendDB		*bd;
+	void			*thrctx;
 
 	slap_tool_init( progname, SLAPACL, argc, argv );
 
@@ -96,7 +97,8 @@
 	argv = &argv[ optind ];
 	argc -= optind;
 
-	connection_fake_init( &conn, &opbuf, &conn );
+	thrctx = ldap_pvt_thread_pool_context();
+	connection_fake_init( &conn, &opbuf, thrctx );
 	op = &opbuf.ob_op;
 	op->o_tmpmemctx = NULL;
 

Modified: openldap/trunk/servers/slapd/slapauth.c
===================================================================
--- openldap/trunk/servers/slapd/slapauth.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slapauth.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/slapauth.c,v 1.10.2.5 2009/01/22 00:01:03 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slapauth.c,v 1.10.2.6 2009/07/22 20:28:47 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2004-2009 The OpenLDAP Foundation.
@@ -83,13 +83,15 @@
 	Connection		conn = {0};
 	OperationBuffer	opbuf;
 	Operation		*op;
+	void			*thrctx;
 
 	slap_tool_init( progname, SLAPAUTH, argc, argv );
 
 	argv = &argv[ optind ];
 	argc -= optind;
 
-	connection_fake_init( &conn, &opbuf, &conn );
+	thrctx = ldap_pvt_thread_pool_context();
+	connection_fake_init( &conn, &opbuf, thrctx );
 	op = &opbuf.ob_op;
 
 	conn.c_sasl_bind_mech = mech;

Modified: openldap/trunk/servers/slapd/slapi/slapi_ops.c
===================================================================
--- openldap/trunk/servers/slapd/slapi/slapi_ops.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slapi/slapi_ops.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/slapi/slapi_ops.c,v 1.111.2.6 2009/01/22 00:01:15 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slapi/slapi_ops.c,v 1.111.2.7 2009/08/25 22:44:26 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2002-2009 The OpenLDAP Foundation.
@@ -33,7 +33,7 @@
 
 #ifdef LDAP_SLAPI
 
-static struct slap_listener slapi_listener = {
+static struct Listener slapi_listener = {
 	BER_BVC("slapi://"),
 	BER_BVC("slapi://")
 };

Modified: openldap/trunk/servers/slapd/slapi/slapi_pblock.c
===================================================================
--- openldap/trunk/servers/slapd/slapi/slapi_pblock.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slapi/slapi_pblock.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/slapi/slapi_pblock.c,v 1.63.2.9 2009/01/22 00:01:15 kurt Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slapi/slapi_pblock.c,v 1.63.2.10 2009/07/27 20:19:19 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2002-2009 The OpenLDAP Foundation.
@@ -1152,7 +1152,7 @@
 			for ( i = 0; attrs[i] != NULL; i++ ) {
 				an[j].an_desc = NULL;
 				an[j].an_oc = NULL;
-				an[j].an_oc_exclude = 0;
+				an[j].an_flags = 0;
 				an[j].an_name.bv_val = attrs[i];
 				an[j].an_name.bv_len = strlen( attrs[i] );
 				if ( slap_bv2ad( &an[j].an_name, &an[j].an_desc, &pb->pb_rs->sr_text ) == LDAP_SUCCESS ) {

Modified: openldap/trunk/servers/slapd/slapschema.c
===================================================================
--- openldap/trunk/servers/slapd/slapschema.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/slapschema.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,4 +1,4 @@
-/* $OpenLDAP: pkg/ldap/servers/slapd/slapschema.c,v 1.1.2.2 2009/06/02 22:36:18 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/slapschema.c,v 1.1.2.3 2009/07/22 20:28:47 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 1998-2009 The OpenLDAP Foundation.
@@ -49,6 +49,7 @@
 	Connection conn = { 0 };
 	OperationBuffer	opbuf;
 	Operation *op = NULL;
+	void *thrctx;
 
 	slap_tool_init( progname, SLAPCAT, argc, argv );
 
@@ -78,7 +79,8 @@
 		exit( EXIT_FAILURE );
 	}
 
-	connection_fake_init( &conn, &opbuf, &conn );
+	thrctx = ldap_pvt_thread_pool_context();
+	connection_fake_init( &conn, &opbuf, thrctx );
 	op = &opbuf.ob_op;
 	op->o_tmpmemctx = NULL;
 	op->o_bd = be;

Modified: openldap/trunk/servers/slapd/syncrepl.c
===================================================================
--- openldap/trunk/servers/slapd/syncrepl.c	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/servers/slapd/syncrepl.c	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */
-/* $OpenLDAP: pkg/ldap/servers/slapd/syncrepl.c,v 1.254.2.80 2009/06/11 21:53:44 quanah Exp $ */
+/* $OpenLDAP: pkg/ldap/servers/slapd/syncrepl.c,v 1.254.2.85 2009/08/25 23:43:35 quanah Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
  * Copyright 2003-2009 The OpenLDAP Foundation.
@@ -1620,6 +1620,13 @@
 	op->o_tag = LBER_DEFAULT;
 	op->o_bd = si->si_wbe;
 
+	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+		Debug( LDAP_DEBUG_ANY,
+			"syncrepl_message_to_op: %s got empty dn",
+			si->si_ridtxt, 0, 0 );
+		return LDAP_OTHER;
+	}
+
 	while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
 		== LDAP_SUCCESS ) {
 		if ( bv.bv_val == NULL )
@@ -1857,6 +1864,13 @@
 		return rc;
 	}
 
+	if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+		Debug( LDAP_DEBUG_ANY,
+			"syncrepl_message_to_entry: %s got empty dn",
+			si->si_ridtxt, 0, 0 );
+		return LDAP_OTHER;
+	}
+
 	if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
 		/* NOTE: this could be done even before decoding the DN,
 		 * although encoding errors wouldn't be detected */
@@ -3088,6 +3102,10 @@
 	return rc;
 }
 
+/* Compare the attribute from the old entry to the one in the new
+ * entry. The Modifications from the new entry will either be left
+ * in place, or changed to an Add or Delete as needed.
+ */
 static void
 attr_cmp( Operation *op, Attribute *old, Attribute *new,
 	Modifications ***mret, Modifications ***mcur )
@@ -3231,6 +3249,86 @@
 	*mret = modtail;
 }
 
+/* Generate a set of modifications to change the old entry into the
+ * new one. On input ml is a list of modifications equivalent to
+ * the new entry. It will be massaged and the result will be stored
+ * in mods.
+ */
+void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
+	Modifications **mods, Modifications **ml, int is_ctx)
+{
+	Modifications **modtail = mods;
+
+	/* We assume that attributes are saved in the same order
+	 * in the remote and local databases. So if we walk through
+	 * the attributeDescriptions one by one they should match in
+	 * lock step. If not, look for an add or delete.
+	 */
+	while ( old && new )
+	{
+		/* If we've seen this before, use its mod now */
+		if ( new->a_flags & SLAP_ATTR_IXADD ) {
+			attr_cmp( op, NULL, new, &modtail, &ml );
+			new = new->a_next;
+			continue;
+		}
+		/* Skip contextCSN */
+		if ( is_ctx && old->a_desc ==
+			slap_schema.si_ad_contextCSN ) {
+			old = old->a_next;
+			continue;
+		}
+
+		if ( old->a_desc != new->a_desc ) {
+			Modifications *mod;
+			Attribute *tmp;
+
+			/* If it's just been re-added later,
+			 * remember that we've seen it.
+			 */
+			tmp = attr_find( new, old->a_desc );
+			if ( tmp ) {
+				tmp->a_flags |= SLAP_ATTR_IXADD;
+			} else {
+				/* If it's a new attribute, pull it in.
+				 */
+				tmp = attr_find( old, new->a_desc );
+				if ( !tmp ) {
+					attr_cmp( op, NULL, new, &modtail, &ml );
+					new = new->a_next;
+					continue;
+				}
+				/* Delete old attr */
+				mod = ch_malloc( sizeof( Modifications ) );
+				mod->sml_op = LDAP_MOD_DELETE;
+				mod->sml_flags = 0;
+				mod->sml_desc = old->a_desc;
+				mod->sml_type = mod->sml_desc->ad_cname;
+				mod->sml_numvals = 0;
+				mod->sml_values = NULL;
+				mod->sml_nvalues = NULL;
+				*modtail = mod;
+				modtail = &mod->sml_next;
+			}
+			old = old->a_next;
+			continue;
+		}
+		/* kludge - always update modifiersName so that it
+		 * stays co-located with the other mod opattrs. But only
+		 * if we know there are other valid mods.
+		 */
+		if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
+			old->a_desc == slap_schema.si_ad_modifyTimestamp ))
+			attr_cmp( op, NULL, new, &modtail, &ml );
+		else
+			attr_cmp( op, old, new, &modtail, &ml );
+		new = new->a_next;
+		old = old->a_next;
+	}
+	*modtail = *ml;
+	*ml = NULL;
+}
+
 static int
 dn_callback(
 	Operation*	op,
@@ -3351,78 +3449,9 @@
 					 */
 				}
 
-				modtail = &dni->mods;
-				ml = dni->modlist;
-
-				/* We assume that attributes are saved in the same order
-				 * in the remote and local databases. So if we walk through
-				 * the attributeDescriptions one by one they should match in
-				 * lock step. If not, look for an add or delete.
-				 */
-				for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
-						old && new; )
-				{
-					/* If we've seen this before, use its mod now */
-					if ( new->a_flags & SLAP_ATTR_IXADD ) {
-						attr_cmp( op, NULL, new, &modtail, &ml );
-						new = new->a_next;
-						continue;
-					}
-					/* Skip contextCSN */
-					if ( is_ctx && old->a_desc ==
-						slap_schema.si_ad_contextCSN ) {
-						old = old->a_next;
-						continue;
-					}
-
-					if ( old->a_desc != new->a_desc ) {
-						Modifications *mod;
-						Attribute *tmp;
-
-						/* If it's just been re-added later,
-						 * remember that we've seen it.
-						 */
-						tmp = attr_find( new, old->a_desc );
-						if ( tmp ) {
-							tmp->a_flags |= SLAP_ATTR_IXADD;
-						} else {
-							/* If it's a new attribute, pull it in.
-							 */
-							tmp = attr_find( old, new->a_desc );
-							if ( !tmp ) {
-								attr_cmp( op, NULL, new, &modtail, &ml );
-								new = new->a_next;
-								continue;
-							}
-							/* Delete old attr */
-							mod = ch_malloc( sizeof( Modifications ) );
-							mod->sml_op = LDAP_MOD_DELETE;
-							mod->sml_flags = 0;
-							mod->sml_desc = old->a_desc;
-							mod->sml_type = mod->sml_desc->ad_cname;
-							mod->sml_numvals = 0;
-							mod->sml_values = NULL;
-							mod->sml_nvalues = NULL;
-							*modtail = mod;
-							modtail = &mod->sml_next;
-						}
-						old = old->a_next;
-						continue;
-					}
-					/* kludge - always update modifiersName so that it
-					 * stays co-located with the other mod opattrs. But only
-					 * if we know there are other valid mods.
-					 */
-					if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
-						old->a_desc == slap_schema.si_ad_modifyTimestamp ))
-						attr_cmp( op, NULL, new, &modtail, &ml );
-					else
-						attr_cmp( op, old, new, &modtail, &ml );
-					new = new->a_next;
-					old = old->a_next;
-				}
-				*modtail = *ml;
-				*ml = NULL;
+				syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
+					dni->new_entry->e_attrs, &dni->mods, dni->modlist,
+					is_ctx );
 			}
 		}
 	} else if ( rs->sr_type == REP_RESULT ) {
@@ -3729,12 +3758,14 @@
 			}
 			ch_free( npe );
 		}
-		sie->si_cookieState->cs_ref--;
-		if ( !sie->si_cookieState->cs_ref ) {
-			ch_free( sie->si_cookieState->cs_sids );
-			ber_bvarray_free( sie->si_cookieState->cs_vals );
-			ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
-			ch_free( sie->si_cookieState );
+		if ( sie->si_cookieState ) {
+			sie->si_cookieState->cs_ref--;
+			if ( !sie->si_cookieState->cs_ref ) {
+				ch_free( sie->si_cookieState->cs_sids );
+				ber_bvarray_free( sie->si_cookieState->cs_vals );
+				ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
+				ch_free( sie->si_cookieState );
+			}
 		}
 		ch_free( sie );
 		sie = si_next;
@@ -3791,21 +3822,6 @@
 	GOT_REQUIRED		= (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
 };
 
-static struct {
-	struct berval key;
-	int val;
-} scopes[] = {
-	{ BER_BVC("base"), LDAP_SCOPE_BASE },
-	{ BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
-	{ BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL },	/* OpenLDAP extension */
-	{ BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
-	{ BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE },
-	{ BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
-	{ BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
-	{ BER_BVC("subtree"), LDAP_SCOPE_SUBTREE },	/* OpenLDAP extension */
-	{ BER_BVNULL, 0 }
-};
-
 static slap_verbmasks datamodes[] = {
 	{ BER_BVC("default"), SYNCDATA_DEFAULT },
 	{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
@@ -4023,19 +4039,15 @@
 		{
 			int j;
 			val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
-			for ( j = 0; !BER_BVISNULL(&scopes[j].key); j++ ) {
-				if (!strcasecmp( val, scopes[j].key.bv_val ) ) {
-					si->si_scope = scopes[j].val;
-					break;
-				}
-			}
-			if ( BER_BVISNULL(&scopes[j].key) ) {
+			j = ldap_pvt_str2scope( val );
+			if ( j < 0 ) {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
 					"Error: parse_syncrepl_line: "
 					"unknown scope \"%s\"", val);
 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
 				return -1;
 			}
+			si->si_scope = j;
 			si->si_got |= GOT_SCOPE;
 		} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
 					STRLENOF( ATTRSONLYSTR ) ) )
@@ -4332,6 +4344,8 @@
 	rc = parse_syncrepl_line( c, si );
 
 	if ( rc == 0 ) {
+		LDAPURLDesc *lud;
+
 		/* Must be LDAPv3 because we need controls */
 		switch ( si->si_bindconf.sb_version ) {
 		case 0:
@@ -4349,24 +4363,35 @@
 			return 1;
 		}
 
+		if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ),
+				"<%s> invalid URL", c->argv[0] );
+			Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
+				c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
+			return 1;
+		}
+
 		si->si_be = c->be;
 		if ( slapMode & SLAP_SERVER_MODE ) {
-			Listener **l = slapd_get_listeners();
 			int isMe = 0;
-
-			/* check if URL points to current server. If so, ignore
-			 * this configuration. We require an exact match. Just
-			 * in case they really want to do this, they can vary
-			 * the case of the URL to allow it.
+			/* check if consumer points to current server and database.
+			 * If so, ignore this configuration.
 			 */
-			if ( l && !SLAP_DBHIDDEN( c->be ) ) {
+			if ( !SLAP_DBHIDDEN( c->be ) ) {
 				int i;
-				for ( i=0; l[i]; i++ ) {
-					if ( bvmatch( &l[i]->sl_url, &si->si_bindconf.sb_uri ) ) {
+				/* if searchbase doesn't match current DB suffix,
+				 * assume it's different
+				 */
+				for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
+					if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
 						isMe = 1;
 						break;
 					}
 				}
+				/* if searchbase matches, see if URLs match */
+				if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
+						lud ) == NULL )
+					isMe = 0;
 			}
 
 			if ( !isMe ) {
@@ -4385,6 +4410,7 @@
 			/* mirrormode still needs to see this flag in tool mode */
 			rc = config_sync_shadow( c ) ? -1 : 0;
 		}
+		ldap_free_urldesc( lud );
 	}
 
 #ifdef HAVE_TLS
@@ -4425,7 +4451,7 @@
 static void
 syncrepl_unparse( syncinfo_t *si, struct berval *bv )
 {
-	struct berval bc, uri;
+	struct berval bc, uri, bs;
 	char buf[BUFSIZ*2], *ptr;
 	ber_len_t len;
 	int i;
@@ -4479,13 +4505,10 @@
 		ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
 		*ptr++ = '"';
 	}
-	for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
-		if ( si->si_scope == scopes[i].val ) {
-			if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return;
-			ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
-			ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
-			break;
-		}
+	if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
+		if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
+		ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
+		ptr = lutil_strcopy( ptr, bs.bv_val );
 	}
 	if ( si->si_attrsonly ) {
 		if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;

Modified: openldap/trunk/tests/data/monitor1.out
===================================================================
--- openldap/trunk/tests/data/monitor1.out	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/data/monitor1.out	2009-09-23 17:57:37 UTC (rev 1243)
@@ -9,8 +9,8 @@
 monitorConnectionRead: 2
 monitorConnectionWrite: 0
 monitorConnectionMask: rx
-monitorConnectionListener: ldap://localhost:9011/
-monitorConnectionLocalAddress: IP=127.0.0.1:9011
+monitorConnectionListener: ldap://localhost:@PORT1@/
+monitorConnectionLocalAddress: IP=127.0.0.1:@PORT1@
 entryDN: cn=Connection 1,cn=Connections,cn=Monitor
 
 dn: cn=Connections,cn=Monitor

Modified: openldap/trunk/tests/data/slapd-proxycache.conf
===================================================================
--- openldap/trunk/tests/data/slapd-proxycache.conf	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/data/slapd-proxycache.conf	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 # proxy cache slapd config 
-# $OpenLDAP: pkg/ldap/tests/data/slapd-proxycache.conf,v 1.24.2.8 2009/01/22 00:01:16 kurt Exp $
+# $OpenLDAP: pkg/ldap/tests/data/slapd-proxycache.conf,v 1.24.2.9 2009/08/25 21:24:47 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -44,13 +44,15 @@
 limits		dn="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" size=1
 
 overlay		pcache
-proxycache	@BACKEND@ 100 2 @ENTRY_LIMIT@ @CACHETTL@
-proxyattrset 0  	sn cn title uid
-proxyattrset 1  	mail postaladdress telephonenumber cn uid
-proxytemplate   	(|(cn=)(sn=)) 0 @CACHETTL@ @NCACHETTL@ @SCACHETTL@
-proxytemplate   	(sn=) 0 @CACHETTL@ @NCACHETTL@ @SCACHETTL@
-proxytemplate   	(uid=) 1 @CACHETTL@ @NCACHETTL@ @SCACHETTL@
-proxytemplate   	(mail=) 0 @CACHETTL@ @NCACHETTL@ @SCACHETTL@
+pcache	@BACKEND@ 100 2 @ENTRY_LIMIT@ @CCPERIOD@
+pcacheattrset 0  	sn cn title uid
+pcacheattrset 1  	mail postaladdress telephonenumber cn uid
+pcachetemplate   	(|(cn=)(sn=)) 0 @TTL@ @NTTL@ @STTL@
+pcachetemplate   	(sn=) 0 @TTL@ @NTTL@ @STTL@
+pcachetemplate   	(uid=) 1 @TTL@ @NTTL@ @STTL@
+pcachetemplate   	(mail=) 0 @TTL@ @NTTL@ @STTL@
+pcachetemplate   	(&(objectclass=)(uid=)) 1 @TTL@ @NTTL@ @STTL@ @TTR@
+pcachebind		(&(objectclass=person)(uid=)) 1 @BTTR@ sub "ou=Alumni Association,ou=people,dc=example,dc=com"
 
 #bdb#cachesize 20
 #hdb#cachesize 20

Modified: openldap/trunk/tests/run.in
===================================================================
--- openldap/trunk/tests/run.in	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/run.in	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $OpenLDAP: pkg/ldap/tests/run.in,v 1.47.2.13 2009/01/30 18:48:14 quanah Exp $
+# $OpenLDAP: pkg/ldap/tests/run.in,v 1.47.2.14 2009/08/13 00:05:07 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -225,7 +225,7 @@
 # disable LDAP initialization
 LDAPNOINIT=true; export LDAPNOINIT
 
-echo "Running ${SCRIPT}..."
+echo "Running ${SCRIPT} for ${BACKEND}..."
 while [ $COUNTER -le $LOOP ]; do
 	if [ $LOOP -gt 1 ]; then
 		echo "Running $COUNTER of $LOOP iterations"

Modified: openldap/trunk/tests/scripts/all
===================================================================
--- openldap/trunk/tests/scripts/all	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/all	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/all,v 1.26.2.7 2009/03/24 18:10:51 quanah Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/all,v 1.26.2.8 2009/08/13 00:05:07 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -51,13 +51,13 @@
 EOF
 	fi
 
-	echo ">>>>> Starting ${TB}`basename $CMD`${TN} ..."
+	echo ">>>>> Starting ${TB}`basename $CMD`${TN} for $BACKEND..."
 	$CMD
 	RC=$?
 	if test $RC -eq 0 ; then
-		echo ">>>>> $CMD completed ${TB}OK${TN}."
+		echo ">>>>> $CMD completed ${TB}OK${TN} for $BACKEND."
 	else
-		echo ">>>>> $CMD ${TB}failed${TN} (exit $RC)"
+		echo ">>>>> $CMD ${TB}failed${TN} for $BACKEND (exit $RC)"
 		exit $RC
 	fi
 

Modified: openldap/trunk/tests/scripts/conf.sh
===================================================================
--- openldap/trunk/tests/scripts/conf.sh	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/conf.sh	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/conf.sh,v 1.49.2.9 2009/01/22 00:01:18 kurt Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/conf.sh,v 1.49.2.10 2009/08/25 21:24:47 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -71,10 +71,6 @@
 	-e "s;@PORT5@;${PORT5};"			\
 	-e "s;@PORT6@;${PORT6};"			\
 	-e "s/@SASL_MECH@/${SASL_MECH}/"		\
-	-e "s/@CACHETTL@/${CACHETTL}/"			\
-	-e "s/@NCACHETTL@/${NCACHETTL}/"		\
-	-e "s/@SCACHETTL@/${SCACHETTL}/"		\
-	-e "s/@ENTRY_LIMIT@/${CACHE_ENTRY_LIMIT}/"	\
 	-e "s;@TESTDIR@;${TESTDIR};"			\
 	-e "s;@DATADIR@;${DATADIR};"			\
 	-e "s;@SCHEMADIR@;${SCHEMADIR};"

Modified: openldap/trunk/tests/scripts/test020-proxycache
===================================================================
--- openldap/trunk/tests/scripts/test020-proxycache	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/test020-proxycache	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/test020-proxycache,v 1.26.2.10 2009/01/22 00:01:19 kurt Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/test020-proxycache,v 1.26.2.11 2009/08/25 21:24:47 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -13,10 +13,13 @@
 ## top-level directory of the distribution or, alternatively, at
 ## <http://www.OpenLDAP.org/license.html>.
 
-CACHETTL="1m"
-NCACHETTL="1m"
-SCACHETTL="1m"
-CACHE_ENTRY_LIMIT=6
+PCACHETTL=${PCACHETTL-"1m"}
+PCACHENTTL=${PCACHENTTL-"1m"}
+PCACHESTTL=${PCACHESTTL-"1m"}
+PCACHE_ENTRY_LIMIT=${PCACHE_ENTRY_LIMIT-"6"}
+PCACHE_CCPERIOD=${PCACHE_CCPERIOD-"2"}
+PCACHETTR=${PCACHETTR-"2"}
+PCACHEBTTR=${PCACHEBTTR-"5"}
 
 . $SRCDIR/scripts/defines.sh
 
@@ -82,7 +85,16 @@
 fi
 
 echo "Starting proxy cache on TCP/IP port $PORT2..."
-. $CONFFILTER < $PROXYCACHECONF > $CONF2
+. $CONFFILTER < $PROXYCACHECONF | sed \
+	-e "s/@TTL@/${PCACHETTL}/"			\
+	-e "s/@NTTL@/${PCACHENTTL}/"		\
+	-e "s/@STTL@/${PCACHENTTL}/"		\
+	-e "s/@TTR@/${PCACHETTR}/"			\
+	-e "s/@ENTRY_LIMIT@/${PCACHE_ENTRY_LIMIT}/"	\
+	-e "s/@CCPERIOD@/${PCACHE_CCPERIOD}/"			\
+	-e "s/@BTTR@/${PCACHEBTTR}/"			\
+	> $CONF2
+
 $SLAPD -f $CONF2 -h $URI2 -d $LVL -d pcache > $LOG2 2>&1 &
 CACHEPID=$!
 if test $WAIT != 0 ; then
@@ -226,11 +238,11 @@
 FILTER="(mail=*example.com)"
 ATTRS="cn sn title uid"
 USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
-PASSWD="bjorn"
+UPASSWD="bjorn"
 echo "Query $CNT: filter:$FILTER attrs:$ATTRS"  
 echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
 $LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
-	-D "$USERDN" -w "$PASSWD" \
+	-D "$USERDN" -w "$UPASSWD" \
 	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
 RC=$?
 case $RC in
@@ -253,11 +265,11 @@
 FILTER="(uid=b*)"
 ATTRS="mail"
 USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
-PASSWD="bjorn"
+UPASSWD="bjorn"
 echo "Query $CNT: filter:$FILTER attrs:$ATTRS"  
 echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
 $LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
-	-D "$USERDN" -w "$PASSWD" \
+	-D "$USERDN" -w "$UPASSWD" \
 	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
 RC=$?
 case $RC in
@@ -362,11 +374,11 @@
 FILTER="(mail=*example.com)"
 ATTRS="cn sn title uid"
 USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
-PASSWD="bjorn"
+UPASSWD="bjorn"
 echo "Query $CNT: filter:$FILTER attrs:$ATTRS"  
 echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
 $LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
-	-D "$USERDN" -w "$PASSWD" \
+	-D "$USERDN" -w "$UPASSWD" \
 	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
 RC=$?
 case $RC in
@@ -389,11 +401,11 @@
 FILTER="(uid=b*)"
 ATTRS="mail"
 USERDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com"
-PASSWD="bjorn"
+UPASSWD="bjorn"
 echo "Query $CNT: filter:$FILTER attrs:$ATTRS"  
 echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
 $LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
-	-D "$USERDN" -w "$PASSWD" \
+	-D "$USERDN" -w "$UPASSWD" \
 	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
 RC=$?
 case $RC in
@@ -434,12 +446,11 @@
 		} 
 	}'`
 
-test $KILLSERVERS != no && kill -HUP $KILLPIDS
-
 if test "$ANSWERABILITY" = "$ANSWERED" ; then
 	echo "Successfully verified answerability"
 else 
 	echo "Error in verifying answerability"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
 	exit 1
 fi
 
@@ -452,9 +463,153 @@
 
 if test $? != 0 ; then
 	echo "Comparison failed"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
 	exit 1
 fi
 
+echo ""
+echo "Testing cache refresh"
+
+CNT=`expr $CNT + 1`
+FILTER="(&(objectclass=person)(uid=dots))"
+ATTRS="cn mail telephonenumber"
+echo "Query $CNT: filter:$FILTER attrs:$ATTRS" 
+echo "# Query $CNT: filter:$FILTER attrs:$ATTRS" >> $SEARCHOUT
+$LDAPSEARCH -x -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
+	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapsearch failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+$LDAPMODIFY -x -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD <<EOF \
+	> /dev/null 2>&1
+dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+changetype: modify
+replace: mail
+mail: dots at admin.example2.com
+-
+
+EOF
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapmodify failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+SLEEP=`expr $PCACHETTR + $PCACHE_CCPERIOD`
+echo "Waiting $SLEEP seconds for cache to refresh"
+
+sleep $SLEEP
+
+echo "Checking entry again"
+$LDAPSEARCH -x -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT2 \
+	"$FILTER" $ATTRS >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapsearch failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+grep "^mail: dots at admin" $SEARCHOUT > /dev/null
+RC=$?
+if test $RC != 0 ; then
+	echo "Refresh failed"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+	exit 0
+fi
+
+echo ""
+echo "Testing Bind caching"
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: $USERDN"
+echo "# Query $CNT: $USERDN" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -h $LOCALHOST -p $PORT2 \
+	-D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapsearch failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+grep "CACHING BIND" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+	echo "Refresh failed"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+	exit 0
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD="jaj"
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -h $LOCALHOST -p $PORT2 \
+	-D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapsearch failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+grep "CACHED BIND" $LOG2 > /dev/null
+RC=$?
+if test $RC != 0 ; then
+	echo "Refresh failed"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+	exit 0
+fi
+
+echo ""
+echo "Testing pwdModify"
+$LDAPPASSWD -h $LOCALHOST -p $PORT2 \
+	-D "$MANAGERDN" -w "$PASSWD" -s newpw "$USERDN" >> $TESTOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+	echo "ldappasswd failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+RC=`grep "CACH.* BIND" $LOG2 | wc -l`
+if test $RC != 3 ; then
+	echo "ldappasswd didn't update the cache"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+	exit 0
+fi
+
+CNT=`expr $CNT + 1`
+USERDN="cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com"
+UPASSWD=newpw
+echo "Query $CNT: (Bind should be cached)"
+echo "# Query $CNT: (Bind should be cached)" >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "" -s base -h $LOCALHOST -p $PORT2 \
+	-D "$USERDN" -w "$UPASSWD" >> $SEARCHOUT 2>> $TESTOUT
+RC=$?
+if test $RC != 0 ; then
+	echo "ldapsearch failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
+RC=`grep "CACH.* BIND" $LOG2 | wc -l`
+if test $RC != 4 ; then
+	echo "Bind wasn't answered from cache"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS && wait
+	exit 0
+fi
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
 echo ">>>>> Test succeeded"
 
 test $KILLSERVERS != no && wait

Modified: openldap/trunk/tests/scripts/test024-unique
===================================================================
--- openldap/trunk/tests/scripts/test024-unique	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/test024-unique	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/test024-unique,v 1.8.2.6 2009/01/22 00:01:19 kurt Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/test024-unique,v 1.8.2.7 2009/07/27 18:39:18 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 2004-2009 The OpenLDAP Foundation.
@@ -425,6 +425,7 @@
 changetype: modify
 add: olcUniqueURI
 olcUniqueURI: ldap:///?sn?sub?(cn=e*)
+olcUniqueURI: ldap:///?uid?sub?(cn=edgar)
 -
 delete: olcUniqueURI
 olcUniqueURI: ldap:///?description?one
@@ -445,6 +446,7 @@
 olcOverlay: {0}unique
 olcUniqueURI: ldap:///?employeeNumber,displayName?sub
 olcUniqueURI: ldap:///?sn?sub?(cn=e*)
+olcUniqueURI: ldap:///?uid?sub?(cn=edgar)
 
 EOF
 diff $TESTDIR/third-config.ldif $TESTDIR/third-reference.ldif > /dev/null 2>&1
@@ -473,6 +475,24 @@
 	exit -1
 fi
 
+echo "Adding a record unique in all domains because of filter conditions "
+$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
+	 $TESTOUT 2>&1 << EOF
+dn: uid=empty,ou=users,o=unique
+objectClass: inetOrgPerson
+uid: edgar
+cn: empty
+sn: empty
+EOF
+
+RC=$?
+if test $RC != 0 ; then
+	echo "spurious unique error ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit -1
+fi
+
+
 echo "Adding a record unique in one domain, non-unique in the filtered domain..."
 
 $LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \

Modified: openldap/trunk/tests/scripts/test046-dds
===================================================================
--- openldap/trunk/tests/scripts/test046-dds	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/test046-dds	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/test046-dds,v 1.4.2.5 2009/01/22 00:01:20 kurt Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/test046-dds,v 1.4.2.6 2009/08/13 00:47:41 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 2005-2009 The OpenLDAP Foundation.
@@ -396,7 +396,7 @@
 dn: $MEETINGDN
 changetype: modify
 add: member
-member: $JAJDN
+member: $JOHNDDN
 EOMODS
 RC=$?
 if test $RC != 0 ; then
@@ -478,6 +478,17 @@
 	exit $RC
 fi
 
+echo "Trying to refresh the meeting as $JAJDN (should fail)..."
+$LDAPEXOP -D "$JAJDN" -w "jaj" -h $LOCALHOST -p $PORT1 \
+	"refresh" "$MEETINGDN" "240" \
+	>> $TESTOUT 2>&1
+RC=$?
+if test $RC = 0 ; then
+	echo "ldapexop should have failed ($RC)!"
+	test $KILLSERVERS != no && kill -HUP $KILLPIDS
+	exit $RC
+fi
+
 echo "Trying to delete the meeting as $BABSDN (should fail)..."
 $LDAPMODIFY -D "$BABSDN" -w bjensen -h $LOCALHOST -p $PORT1 \
 	>> $TESTOUT 2>&1 << EOMODS

Modified: openldap/trunk/tests/scripts/test056-monitor
===================================================================
--- openldap/trunk/tests/scripts/test056-monitor	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/test056-monitor	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/test056-monitor,v 1.2.2.3 2009/07/02 20:11:10 quanah Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/test056-monitor,v 1.2.2.5 2009/08/17 17:43:01 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2008 The OpenLDAP Foundation.
@@ -16,6 +16,11 @@
 echo "running defines.sh"
 . $SRCDIR/scripts/defines.sh
 
+if test $MONITORDB = "no" ; then 
+	echo "Monitor backend not available, test skipped"
+	exit 0
+fi 
+
 mkdir -p $TESTDIR $DBDIR1
 
 echo "Starting slapd on TCP/IP port $PORT..."
@@ -66,7 +71,7 @@
 echo "Filtering ldapsearch results..."
 sed -e "$localrewrite" < $SEARCHOUT   | . $LDIFFILTER > $SEARCHFLT
 echo "Filtering expected data..."
-sed -e "$localrewrite" < $MONITOROUT1 | . $LDIFFILTER > $LDIFFLT
+. $CONFFILTER < $MONITOROUT1 | sed -e "$localrewrite" | . $LDIFFILTER > $LDIFFLT
 echo "Comparing filter output..."
 $CMP $SEARCHFLT $LDIFFLT > $CMPOUT
 

Modified: openldap/trunk/tests/scripts/test058-syncrepl-asymmetric
===================================================================
--- openldap/trunk/tests/scripts/test058-syncrepl-asymmetric	2009-09-23 17:26:22 UTC (rev 1242)
+++ openldap/trunk/tests/scripts/test058-syncrepl-asymmetric	2009-09-23 17:57:37 UTC (rev 1243)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $OpenLDAP: pkg/ldap/tests/scripts/test058-syncrepl-asymmetric,v 1.1.2.2 2009/04/28 00:50:29 quanah Exp $
+# $OpenLDAP: pkg/ldap/tests/scripts/test058-syncrepl-asymmetric,v 1.1.2.3 2009/08/13 00:50:43 quanah Exp $
 ## This work is part of OpenLDAP Software <http://www.openldap.org/>.
 ##
 ## Copyright 1998-2009 The OpenLDAP Foundation.
@@ -2089,6 +2089,8 @@
 	exit $RC
 fi
 
+sleep $SLEEP1
+
 echo "Checking contextCSN after site2 servers repopulated..."
 . $TESTDIR/checkcsn.sh
 




More information about the Pkg-openldap-devel mailing list