diff --git a/contrib/ldapsasl/README b/contrib/ldapsasl/README
new file mode 100644
index 0000000000000000000000000000000000000000..36c3f6b9902cb48ac1cd0922b4e595cf01ba9bb4
--- /dev/null
+++ b/contrib/ldapsasl/README
@@ -0,0 +1,50 @@
+LDAP auxprop plugin for SASL-enabled servers.
+Copyright (C) 2002 by Howard Chu, hyc@symas.com
+
+This software is an experimental proof-of-concept and is not intended for
+general use. It is licensed under the terms ofthe OpenLDAP license.
+
+The file ldapdb.c was written for Cyrus SASL 2.1.3 and OpenLDAP 2.1.3.
+It can be compiled by copying into the Cyrus SASL source tree, in the
+plugins subdirectory. No configuration or build script is provided.
+
+To compile, type "make ldapdb.lo". To link, you'll have to copy the
+link rule for one of the other plugins. Below is a sample on my Linux
+system:
+
+	/bin/sh ./libtool --mode=link gcc  -Wall -W -g -O2 -L/usr/local/lib -Wl,-rpath,/usr/local/lib -module -export-dynamic -rpath /usr/lib/sasl2 -o libldapdb.la  -version-info 2:4:0 ldapdb.lo -lldap -llber -lssl -lcrypto
+
+Once installed, you need to add some config items to the SASL server's
+config file in /usr/lib/sasl2. For example:
+
+ldapdb_uri: ldapi://
+ldapdb_id: root
+ldapdb_pw: secret
+ldapdb_mech: PLAIN
+
+This config assumes an LDAP server on the same machine as the server
+that is using SASL. The LDAP server must be configured to map the SASL
+authcId "root" into a DN that has proxy authorization privileges to
+every account that is allowed to login to this server. (See the OpenLDAP
+Admin Guide for details.)
+
+Unlike other LDAP-enabled plugins for other services that are common
+on the web, this plugin does not require you to configure DN search
+patterns to map usernames to LDAP DNs. This plugin requires SASL name
+mapping to be configured on the target slapd. This approach keeps the
+LDAP-specific configuration details in one place, the slapd.conf, and
+makes the configuration of remote services much simpler.
+
+One additional keyword "ldapdb_rc" may be specified in the config file.
+The filename specified here will be put into the server's LDAPRC
+environment variable, and libldap-specific config options may be set
+in that ldaprc file. The main purpose behind this option is to allow
+a client TLS certificate to be configured, so that SASL/EXTERNAL may
+be used between the SASL server and the LDAP server. This is the most
+optimal way to use this plugin when the servers are on separate machines.
+
+This plugin likely has very poor performance. You'll need something
+better for a real production environment. Please send feedback via the
+openldap-software mailing list for now.
+
+  -- Howard Chu, 2002-07-12
diff --git a/contrib/ldapsasl/ldapdb.c b/contrib/ldapsasl/ldapdb.c
new file mode 100644
index 0000000000000000000000000000000000000000..0772aeafa20ee33e8e23f7388b05146ff87bc34f
--- /dev/null
+++ b/contrib/ldapsasl/ldapdb.c
@@ -0,0 +1,220 @@
+/* SASL LDAP auxprop implementation
+ * Copyright (C) 2002 Howard Chu, hyc@symas.com
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+
+#include "plugin_common.h"
+
+#include <ldap.h>
+
+static char ldapdb[] = "ldapdb";
+
+SASL_AUXPROP_PLUG_INIT( ldapdb )
+
+typedef struct ldapctx {
+	const char *uri;	/* URI of LDAP server */
+	const char *id;	/* SASL authcid to bind as */
+	const char *pw;	/* password for bind */
+	const char *mech;	/* SASL mech */
+} ldapctx;
+
+typedef struct gluectx {
+	ldapctx *lc;
+	sasl_server_params_t *lp;
+	const char *user;
+} gluectx;
+
+static int ldapdb_interact(LDAP *ld, unsigned flags __attribute__((unused)),
+	void *def, void *inter)
+{
+	sasl_interact_t *in = inter;
+	gluectx *gc = def;
+	const char *p;
+
+	for (;in->id != SASL_CB_LIST_END;in++)
+	{
+		p = NULL;
+		switch(in->id)
+		{
+			case SASL_CB_GETREALM:
+				ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &p);
+				break;		
+			case SASL_CB_AUTHNAME:
+				p = gc->lc->id;
+				break;
+			case SASL_CB_PASS:
+				p = gc->lc->pw;
+				break;
+			case SASL_CB_USER:
+				p = gc->user;
+				break;
+		}
+		if (p)
+		{
+			int l = strlen(p);
+			in->result = gc->lp->utils->malloc(l+1);
+			if (!in->result)
+				return LDAP_NO_MEMORY;
+			strcpy((char *)in->result, p);
+			in->len = l;
+		}
+	}
+	return LDAP_SUCCESS;
+}
+
+static void ldapdb_auxprop_lookup(void *glob_context,
+				  sasl_server_params_t *sparams,
+				  unsigned flags,
+				  const char *user,
+				  unsigned ulen)
+{
+    ldapctx *ctx = glob_context;
+    int ret, i, n, *aindx;
+    const struct propval *pr;
+    LDAP *ld = NULL;
+    gluectx gc = { ctx, sparams, NULL };
+    struct berval *dn = NULL, **bvals;
+    LDAPMessage *msg, *res;
+    char **attrs = NULL, *authzid = NULL;
+    
+    if(!ctx || !sparams || !user) return;
+
+    pr = sparams->utils->prop_get(sparams->propctx);
+    if(!pr) return;
+
+    /* count how many attrs to fetch */
+    for(i = 0, n = 0; pr[i].name; i++) {
+	if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
+	    continue;
+	if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
+	    continue;
+	n++;
+    }
+    /* nothing to do, bail out */
+    if (!n) return;
+
+    /* alloc an array of attr names for search, and index to the props */
+    attrs = sparams->utils->malloc((n+1)*sizeof(char *)*2);
+    if (!attrs) return;
+
+    aindx = (int *)(attrs + n + 1);
+
+    /* copy attr list */
+    for (i=0, n=0; pr[i].name; i++) {
+	if(pr[i].name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID))
+	    continue;
+	if(pr[i].values && !(flags & SASL_AUXPROP_OVERRIDE))
+	    continue;
+    	attrs[n] = (char *)pr[i].name;
+	if (pr[i].name[0] == '*') attrs[n]++;
+	aindx[n] = i;
+	n++;
+    }
+    attrs[n] = NULL;
+    	
+    if(ldap_initialize(&ld, ctx->uri)) {
+    	sparams->utils->free(attrs);
+    	return;
+    }
+
+    authzid = sparams->utils->malloc(ulen + sizeof("u:"));
+    if (!authzid) goto done;
+    strcpy(authzid, "u:");
+    strcpy(authzid+2, user);
+    gc.user = authzid;
+
+    i = LDAP_VERSION3;
+    ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &i);
+
+    ret = ldap_sasl_interactive_bind_s(ld, NULL, ctx->mech, NULL, NULL,
+    	LDAP_SASL_QUIET, ldapdb_interact, &gc);
+    if (ret != LDAP_SUCCESS) goto done;
+    
+    ret = ldap_extended_operation_s(ld, LDAP_EXOP_X_WHO_AM_I, NULL, NULL,
+    	NULL, NULL, &dn);
+    if (ret != LDAP_SUCCESS || !dn) goto done;
+    
+    if (dn->bv_val && !strncmp(dn->bv_val, "dn:", 3))
+    ret = ldap_search_s(ld, dn->bv_val+3, LDAP_SCOPE_BASE, "(objectclass=*)",
+    	attrs, 0, &res);
+    ber_bvfree(dn);
+
+    if (ret != LDAP_SUCCESS) goto done;
+
+    for(msg=ldap_first_message(ld, res); msg; msg=ldap_next_message(ld, msg))
+    {
+    	if (ldap_msgtype(msg) != LDAP_RES_SEARCH_ENTRY) continue;
+	for (i=0; i<n; i++)
+	{
+	    bvals = ldap_get_values_len(ld, msg, attrs[i]);
+	    if (!bvals) continue;
+	    if (pr[aindx[i]].values)
+	    	sparams->utils->prop_erase(sparams->propctx, pr[aindx[i]].name);
+	    sparams->utils->prop_set(sparams->propctx, pr[aindx[i]].name,
+				 bvals[0]->bv_val, bvals[0]->bv_len);
+	    ber_bvecfree(bvals);
+	}
+    }
+    ldap_msgfree(res);
+
+ done:
+    if(authzid) sparams->utils->free(authzid);
+    if(attrs) sparams->utils->free(attrs);
+    if(ld) ldap_unbind(ld);
+}
+
+static void ldapdb_auxprop_free(void *glob_ctx, const sasl_utils_t *utils)
+{
+	utils->free(glob_ctx);
+}
+
+static sasl_auxprop_plug_t ldapdb_auxprop_plugin = {
+    0,           /* Features */
+    0,           /* spare */
+    NULL,        /* glob_context */
+    ldapdb_auxprop_free,	/* auxprop_free */
+    ldapdb_auxprop_lookup, /* auxprop_lookup */
+    ldapdb,    /* name */
+    NULL         /* spare */
+};
+
+int ldapdb_auxprop_plug_init(const sasl_utils_t *utils,
+                             int max_version,
+                             int *out_version,
+                             sasl_auxprop_plug_t **plug,
+                             const char *plugname __attribute__((unused))) 
+{
+    ldapctx tmp, *p;
+    const char *s;
+
+    if(!out_version || !plug) return SASL_BADPARAM;
+
+    if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
+    
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_uri", &tmp.uri, NULL);
+    if(!tmp.uri) return SASL_BADPARAM;
+
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_id", &tmp.id, NULL);
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_pw", &tmp.pw, NULL);
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_mech", &tmp.mech, NULL);
+    utils->getopt(utils->getopt_context, ldapdb, "ldapdb_rc", &s, NULL);
+    if(s && setenv("LDAPRC", s, 1)) return SASL_BADPARAM;
+
+    p = utils->malloc(sizeof(ldapctx));
+    if (!p) return SASL_NOMEM;
+    *p = tmp;
+    ldapdb_auxprop_plugin.glob_context = p;
+
+    *out_version = SASL_AUXPROP_PLUG_VERSION;
+
+    *plug = &ldapdb_auxprop_plugin;
+
+    return SASL_OK;
+}
diff --git a/libraries/Makefile.in b/libraries/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..f07cb00fde2967a4160abf09d9a13793b6e10071
--- /dev/null
+++ b/libraries/Makefile.in
@@ -0,0 +1,10 @@
+# $OpenLDAP$
+## Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+## COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+##
+## Libraries Makefile for OpenLDAP
+
+SUBDIRS= liblutil liblunicode libldif \
+	liblber libldap libldap_r \
+	libavl libldbm librewrite
+
diff --git a/libraries/libavl/Makefile.in b/libraries/libavl/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..f9c8e4402837a04aefc96ca9162a6889bee9a057
--- /dev/null
+++ b/libraries/libavl/Makefile.in
@@ -0,0 +1,20 @@
+# $OpenLDAP$
+## Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+## COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+##
+## LIBAVL
+##
+
+SRCS = avl.c testavl.c
+XSRCS = version.c
+OBJS = avl.o
+
+LDAP_INCDIR= ../../include       
+LDAP_LIBDIR= ../../libraries
+
+LIBRARY = libavl.a
+PROGRAMS	= testavl
+XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA) $(LDAP_LIBLUTIL_A)
+
+testavl:	$(XLIBS) testavl.o
+	$(LTLINK) -o $@ testavl.o $(LIBS)
diff --git a/libraries/liblber/Makefile.in b/libraries/liblber/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..87da85611af1df06b5fab412db614d79de313cb6
--- /dev/null
+++ b/libraries/liblber/Makefile.in
@@ -0,0 +1,40 @@
+# $OpenLDAP$
+## Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+## COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+##
+## LIBLBER
+##
+
+LIBRARY = liblber.la
+
+NT_SRCS = nt_err.c
+NT_OBJS = nt_err.lo
+
+LIB_DEFS = -DLBER_LIBRARY
+
+SRCS= assert.c decode.c encode.c io.c bprint.c debug.c \
+	memory.c options.c sockbuf.c $(@PLAT@_SRCS)
+OBJS= assert.lo decode.lo encode.lo io.lo bprint.lo debug.lo\
+	memory.lo options.lo sockbuf.lo $(@PLAT@_OBJS)
+XSRCS= version.c
+
+PROGRAMS= dtest etest idtest
+
+LDAP_INCDIR= ../../include
+LDAP_LIBDIR= ../../libraries
+
+XLIBS = $(LIBRARY) $(LDAP_LIBLUTIL_A)
+XXLIBS = 
+NT_LINK_LIBS = $(AC_LIBS)
+
+dtest:    $(XLIBS) dtest.o
+	$(LTLINK) -o $@ dtest.o $(LIBS)
+etest:  $(XLIBS) etest.o
+	$(LTLINK) -o $@ etest.o $(LIBS)
+idtest:  $(XLIBS) idtest.o
+	$(LTLINK) -o $@ idtest.o $(LIBS)
+
+install-local: FORCE
+	-$(MKDIR) $(DESTDIR)$(libdir)
+	$(LTINSTALL) $(INSTALLFLAGS) -m 644 $(LIBRARY) $(DESTDIR)$(libdir)
+
diff --git a/libraries/liblutil/debug.c b/libraries/liblber/debug.c
similarity index 61%
rename from libraries/liblutil/debug.c
rename to libraries/liblber/debug.c
index 1d47361d8e53adca94a876b002583d017f21a518..8d182d83f26ded57b6ec693c80fbf901cf9b5991 100644
--- a/libraries/liblutil/debug.c
+++ b/libraries/liblber/debug.c
@@ -12,6 +12,7 @@
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/time.h>
+#include <ac/ctype.h>
 
 #ifdef LDAP_SYSLOG
 #include <ac/syslog.h>
@@ -20,6 +21,7 @@
 #include "ldap_log.h"
 #include "ldap_defaults.h"
 #include "lber.h"
+#include "ldap_pvt.h"
 
 struct DEBUGLEVEL
 {
@@ -27,7 +29,7 @@ struct DEBUGLEVEL
 	int  level;
 };
 
-static struct DEBUGLEVEL **levelArray;
+int ldap_loglevels[LDAP_SUBSYS_NUM];
 static long   numLevels = 0;
 
 static FILE *log_file = NULL;
@@ -56,6 +58,39 @@ static char *lutil_levels[] = {"emergency", "alert", "critical",
 			   "results", "detail1", "detail2",
 			   NULL};
 
+static char *lutil_subsys[LDAP_SUBSYS_NUM] = {"global","operation", "transport",
+			   	"connection", "filter", "ber", 
+				"config", "acl", "cache", "index", 
+				"ldif", "tools", "slapd", "slurpd",
+				"backend", "back_bdb", "back_ldbm", 
+				"back_ldap", "back_meta", "back_mon" };
+
+int lutil_mnem2subsys( const char *subsys )
+{
+    int i;
+    for( i = 0; i < LDAP_SUBSYS_NUM; i++ )
+    {
+		if ( !strcasecmp( subsys, lutil_subsys[i] ) )
+		{
+	    	return i;
+		}
+    }
+    return -1;
+}
+
+void lutil_set_all_backends( level )
+{
+    int i;
+
+    for( i = 0; i < LDAP_SUBSYS_NUM; i++ )
+    {
+		if ( !strncasecmp( "back_", lutil_subsys[i], strlen("back_") ) )
+		{
+			ldap_loglevels[i] = level;
+		}
+    }
+}
+
 int lutil_mnem2level( const char *level )
 {
     int i;
@@ -66,47 +101,38 @@ int lutil_mnem2level( const char *level )
 	    return i;
 	}
     }
-    return 0;
+    return -1;
 }
 
-static void addSubsys( const char *subsys, int level )
+static int addSubsys( const char *subsys, int level )
 {
-	int i, j;
+	int subsys_num;
 
-	if ( !strcasecmp( subsys, "global") ) global_level = level;
-
-	for( i = 0; i < numLevels; i++ )
+	if ( !strcasecmp( subsys, "backend" ) )
 	{
-		if ( levelArray[i] == NULL )
-		{
-			levelArray[i] = (struct DEBUGLEVEL*)ber_memalloc( sizeof( struct DEBUGLEVEL ) );
-			levelArray[i]->subsystem = (char*)ber_memalloc( strlen( subsys ) + 1 );
-			strcpy ( levelArray[i]->subsystem, subsys );
-			levelArray[i]->level = level;
-			return;
-		}
-		if( !strcasecmp( subsys, levelArray[i]->subsystem ) )
-		{
-			levelArray[i]->level = level;
-			return;
-		}
+		lutil_set_all_backends( level );
+		return level;
 	}
-	levelArray = (struct DEBUGLEVEL**)ber_memrealloc( levelArray, sizeof( struct DEBUGLEVEL* ) * (numLevels + 10) );
-	for( j = numLevels; j < (numLevels + 10); j++ )
+	else
 	{
-		levelArray[j] = NULL;
+		subsys_num = lutil_mnem2subsys(subsys);
+		if(subsys_num < 0)
+		{
+			fprintf(stderr, "Unknown Subsystem name [ %s ] - Discarded\n", 
+				subsys);
+			fflush(stderr);
+			return -1;
+		}
+
+		ldap_loglevels[subsys_num] = level;
+		return level;
 	}
-	numLevels += 10;
-	levelArray[i] = (struct DEBUGLEVEL*)ber_memalloc( sizeof( struct DEBUGLEVEL ) );
-	levelArray[i]->subsystem = (char*)ber_memalloc( strlen( subsys ) + 1 );
-	strcpy( levelArray[i]->subsystem, subsys );
-	levelArray[i]->level = level;
-	return;
+	return -1;
 }
 
-void lutil_set_debug_level( const char* subsys, int level )
+int lutil_set_debug_level( const char* subsys, int level )
 {
-    addSubsys( subsys, level );
+    return( addSubsys( subsys, level ) );
 }
 
 int lutil_debug_file( FILE *file )
@@ -126,33 +152,25 @@ void lutil_log_int(
 	time_t now;
 	struct tm *today;
 #endif
-	int i;
-
-	if ( levelArray == NULL ) return; /* logging isn't set up */
+	size_t i;
+	char * t_subsys;
+	char * tmp;
 
-	/*
-	 * Look for the subsystem in the level array.  When we find it,
-	 * break out of the loop.
-	 */
-	for( i = 0; i < numLevels; i++ ) {
-		if ( levelArray[i] == NULL ) break; 
-		if ( ! strcasecmp( levelArray[i]->subsystem, subsys ) ) break;
-	}
-
-	/*
-	 * If we didn't find the subsystem, or the set level is less than
-	 * the requested output level, don't output it.
-	 */
-	if ( (level > global_level) &&
-		((i > numLevels ) || (levelArray[i] == NULL) || ( level > levelArray[i]->level )) )
-	{
-		return;
-	}
+	t_subsys = strdup(subsys);
+	
+	for(tmp = t_subsys, i = 0; i < strlen(t_subsys); i++, tmp++)
+		*tmp = TOUPPER( (unsigned char) *tmp );
 
 #ifdef LDAP_SYSLOG
 	/* we're configured to use syslog */
 	if( use_syslog ) {
+#ifdef HAVE_VSYSLOG
 		vsyslog( debug2syslog(level), fmt, vl );
+#else
+		char data[4096];
+		vsnprintf( data, sizeof(data), fmt, vl );
+		syslog( debug2syslog(level), data );
+#endif
 		return;
 	}
 #endif
@@ -198,7 +216,10 @@ void lutil_log_int(
 	/*
 	 * format the output data.
 	 */
+
+	fprintf(file, "\n%s:: ", t_subsys ); 
 	vfprintf( file, fmt, vl );
+	fflush( file );
 }
 
 /*
@@ -206,13 +227,13 @@ void lutil_log_int(
  * level of the log output and the format and data.  Send this on to the
  * internal routine with the print file, if any.
  */
-void lutil_log( const char *subsys, int level, const char *fmt, ... )
+void lutil_log( const int subsys, int level, const char *fmt, ... )
 {
 	FILE* outfile = NULL;
 	va_list vl;
 	va_start( vl, fmt );
 	ber_get_option( NULL, LBER_OPT_LOG_PRINT_FILE, &outfile );
-	lutil_log_int( outfile, subsys, level, fmt, vl );
+	lutil_log_int( outfile, lutil_subsys[subsys], level, fmt, vl );
 	va_end( vl );
 }
 
@@ -232,32 +253,38 @@ void lutil_log_initialize(int argc, char **argv)
      */
     for( i = 0; i < argc; i++ )
     {
-	char *next = argv[i];
-	if ( i < argc-1 && next[0] == '-' && next[1] == 'd' )
-	{
-	    char subsys[64];
-	    int level;
-	    char *optarg = argv[i+1];
-	    char *index = strchr( optarg, '=' );
-	    if ( index != NULL )
-	    {
-		*index = 0;
-		strcpy ( subsys, optarg );
-		level = atoi( index+1 );
-		if ( level <= 0 ) level = lutil_mnem2level( index + 1 );
-		lutil_set_debug_level( subsys, level );
-		*index = '=';
-	    }
-	    else
-	    {
-		global_level = atoi( optarg );
-		/* 
-		 * if a negative number was used, make the global level the
-		 * maximum sane level.
-		 */
-		if ( global_level < 0 ) global_level = 65535;
-	    }
-	}
+		char *next = argv[i];
+	
+		if ( i < argc-1 && next[0] == '-' && next[1] == 'd' )
+		{
+	   		char subsys[64];
+	   		int level;
+	    	char *optarg = argv[i+1];
+	    	char *index = strchr( optarg, '=' );
+	    	if ( index != NULL )
+	    	{
+				*index = 0;
+				strcpy ( subsys, optarg );
+				level = atoi( index+1 );
+				if ( level <= 0 ) level = lutil_mnem2level( index + 1 );
+				lutil_set_debug_level( subsys, level );
+				*index = '=';
+	    	}
+	    	else
+	    	{
+				global_level = atoi( optarg );
+				ldap_loglevels[0] = global_level;
+				/* 
+		 		* if a negative number was used, make the global level the
+		 		* maximum sane level.
+		 		*/
+				if ( global_level < 0 ) 
+				{
+					global_level = 65535;
+					ldap_loglevels[0] = 65535;
+	    		}
+	    	}
+		}
     }
 }
 
@@ -296,6 +323,6 @@ void (lutil_debug)( int debug, int level, const char *fmt, ... )
 		fflush( log_file );
 	}
 
-    fputs( buffer, stderr );
+	fputs( buffer, stderr );
 	va_end( vl );
 }
diff --git a/libraries/liblber/decode.c b/libraries/liblber/decode.c
index a722c9eb7a319a12ad027c85310c1d9c6264ccb4..e69bb496fa0673f09e6397519a45dfa8625427dd 100644
--- a/libraries/liblber/decode.c
+++ b/libraries/liblber/decode.c
@@ -1,5 +1,10 @@
 /* decode.c - ber input decoding routines */
+/* $OpenLDAP$ */
 /*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* Portions
  * Copyright (c) 1990 Regents of the University of Michigan.
  * All rights reserved.
  *
@@ -11,88 +16,80 @@
  * is provided ``as is'' without express or implied warranty.
  */
 
+#include "portable.h"
+
 #include <stdio.h>
-#ifdef MACOS
-#include <stdlib.h>
-#include <stdarg.h>
-#include "macos.h"
-#else /* MACOS */
-#if defined(NeXT) || defined(VMS)
-#include <stdlib.h>
-#else /* next || vms */
-#include <malloc.h>
-#endif /* next || vms */
-#if defined(BC31) || defined(_WIN32)
-#include <stdarg.h>
-#else /* BC31 || _WIN32 */
-#include <varargs.h>
-#endif /* BC31 || _WIN32 */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#ifdef PCNFS
-#include <tklib.h>
-#endif /* PCNFS */
-#endif /* MACOS */
-
-#if defined( DOS ) || defined( _WIN32 )
-#include "msdos.h"
-#endif /* DOS */
-
-#include <string.h>
-#include "lber.h"
-
-#ifdef LDAP_DEBUG
-int	lber_debug;
-#endif
 
-#ifdef NEEDPROTOS
-static int ber_getnint( BerElement *ber, long *num, int len );
-#endif /* NEEDPROTOS */
+#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 ));
 
 /* return the tag - LBER_DEFAULT returned means trouble */
-unsigned long
+ber_tag_t
 ber_get_tag( BerElement *ber )
 {
 	unsigned char	xbyte;
-	unsigned long	tag;
-	char		*tagp;
-	int		i;
+	ber_tag_t	tag;
+	unsigned int	i;
 
-	if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
-		return( LBER_DEFAULT );
+	assert( ber != NULL );
+	assert( LBER_VALID( ber ) );
 
-	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
-		return( (unsigned long) xbyte );
+	if ( ber_pvt_ber_remaining( ber ) < 1 ) {
+		return LBER_DEFAULT;
+	}
 
-	tagp = (char *) &tag;
-	tagp[0] = xbyte;
-	for ( i = 1; i < sizeof(long); i++ ) {
-		if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 )
-			return( LBER_DEFAULT );
+	if ( ber->ber_ptr == ber->ber_buf )
+		tag = *(unsigned char *)ber->ber_ptr;
+	else
+		tag = ber->ber_tag;
+	ber->ber_ptr++;
 
-		tagp[i] = xbyte;
+	if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
+		return tag;
+	}
+
+	for ( i = 1; i < sizeof(ber_tag_t); i++ ) {
+		if ( ber_read( ber, (char *) &xbyte, 1 ) != 1 ) {
+			return LBER_DEFAULT;
+		}
 
-		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
+		tag <<= 8;
+		tag |= 0x00ffUL & (ber_tag_t) xbyte;
+
+		if ( ! (xbyte & LBER_MORE_TAG_MASK) ) {
 			break;
+		}
 	}
 
 	/* tag too big! */
-	if ( i == sizeof(long) )
-		return( LBER_DEFAULT );
+	if ( i == sizeof(ber_tag_t) ) {
+		return LBER_DEFAULT;
+	}
 
-	/* want leading, not trailing 0's */
-	return( tag >> (sizeof(long) - i - 1) );
+	return tag;
 }
 
-unsigned long
-ber_skip_tag( BerElement *ber, unsigned long *len )
+ber_tag_t
+ber_skip_tag( BerElement *ber, ber_len_t *len )
 {
-	unsigned long	tag;
+	ber_tag_t	tag;
 	unsigned char	lc;
-	int		noctets, diff;
-	unsigned long	netlen;
+	ber_len_t	i, noctets;
+	unsigned char netlen[sizeof(ber_len_t)];
+
+	assert( ber != NULL );
+	assert( len != NULL );
+	assert( LBER_VALID( ber ) );
 
 	/*
 	 * Any ber element looks like this: tag length contents.
@@ -104,57 +101,93 @@ ber_skip_tag( BerElement *ber, unsigned long *len )
 	 *	2) primitive encodings used whenever possible
 	 */
 
+	*len = 0;
+
 	/*
 	 * First, we read the tag.
 	 */
 
-	if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
+	if ( (tag = ber_get_tag( ber )) == LBER_DEFAULT ) {
+		return LBER_DEFAULT;
+	}
 
 	/*
 	 * Next, read the length.  The first byte contains the length of
-	 * the length.  If bit 8 is set, the length is the long form,
+	 * 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 an unsigned long.
+	 * greater than what we can hold in a ber_len_t.
 	 */
 
-	*len = netlen = 0;
 	if ( ber_read( ber, (char *) &lc, 1 ) != 1 )
-		return( LBER_DEFAULT );
-	if ( lc & 0x80 ) {
-		noctets = (lc & 0x7f);
-		if ( noctets > sizeof(unsigned long) )
-			return( LBER_DEFAULT );
-		diff = sizeof(unsigned long) - noctets;
-		if ( ber_read( ber, (char *) &netlen + diff, noctets )
-		    != noctets )
-			return( LBER_DEFAULT );
-		*len = LBER_NTOHL( netlen );
+		return LBER_DEFAULT;
+
+	if ( lc & 0x80U ) {
+		noctets = (lc & 0x7fU);
+
+		if ( noctets > sizeof(ber_len_t) ) {
+			return LBER_DEFAULT;
+		}
+
+		if( (unsigned) ber_read( ber, netlen, noctets ) != noctets ) {
+			return LBER_DEFAULT;
+		}
+
+		for( i = 0; i < noctets; i++ ) {
+			*len <<= 8;
+			*len |= netlen[i];
+		}
+
 	} else {
 		*len = lc;
 	}
 
-	return( tag );
+	/* BER length should be non-negative */
+	if( *len < 0 ) {
+		return LBER_DEFAULT;
+	}
+
+	/* BER element should have enough data left */
+	if( *len > (ber_len_t) ber_pvt_ber_remaining( ber ) ) {
+		return LBER_DEFAULT;
+	}
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
+
+	return tag;
 }
 
-unsigned long
-ber_peek_tag( BerElement *ber, unsigned long *len )
+ber_tag_t
+ber_peek_tag(
+	BerElement *ber,
+	ber_len_t *len )
 {
-	char		*save;
-	unsigned long	tag;
+	/*
+	 * This implementation assumes ber_skip_tag() only
+	 * modifies ber_ptr field of the BerElement.
+	 */
+
+	char *save;
+	ber_tag_t	tag, old;
 
+	old = ber->ber_tag;
 	save = ber->ber_ptr;
 	tag = ber_skip_tag( ber, len );
 	ber->ber_ptr = save;
+	ber->ber_tag = old;
 
-	return( tag );
+	return tag;
 }
 
-static int
-ber_getnint( BerElement *ber, long *num, int len )
+static ber_len_t
+ber_getnint(
+	BerElement *ber,
+	ber_int_t *num,
+	ber_len_t len )
 {
-	int	diff, sign, i;
-	long	netnum;
+	unsigned char buf[sizeof(ber_int_t)];
+
+	assert( ber != NULL );
+	assert( num != NULL );
+	assert( LBER_VALID( ber ) );
 
 	/*
 	 * The tag and length have already been stripped off.  We should
@@ -163,281 +196,496 @@ ber_getnint( BerElement *ber, long *num, int len )
 	 * extend after we read it in.
 	 */
 
-	if ( len > sizeof(long) )
-		return( -1 );
+	if ( len > sizeof(ber_int_t) ) {
+		return -1;
+	}
+
+	/* read into the low-order bytes of our buffer */
+	if ( (ber_len_t) ber_read( ber, (char *) buf, len ) != len ) {
+		return -1;
+	}
 
-	netnum = 0;
-	diff = sizeof(long) - len;
-	/* read into the low-order bytes of netnum */
-	if ( ber_read( ber, ((char *) &netnum) + diff, len ) != len )
-		return( -1 );
+	if( len ) {
+		/* sign extend if necessary */
+		ber_len_t i;
+		ber_int_t netnum = 0x80 & buf[0] ? -1 : 0;
 
-	/* sign extend if necessary */
-	sign = ((0x80 << ((len - 1) * 8)) & netnum);
-	if ( sign && len < sizeof(long) ) {
-		for ( i = sizeof(long) - 1; i > len - 1; i-- ) {
-			netnum |= (0xffL << (i * 8));
+		/* shift in the bytes */
+		for( i=0 ; i<len; i++ ) {
+			netnum = (netnum << 8 ) | buf[i];
 		}
+
+		*num = netnum;
+
+	} else {
+		*num = 0;
 	}
-	*num = LBER_NTOHL( netnum );
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
-	return( len );
+	return len;
 }
 
-unsigned long
-ber_get_int( BerElement *ber, long *num )
+ber_tag_t
+ber_get_int(
+	BerElement *ber,
+	ber_int_t *num )
 {
-	unsigned long	tag, len;
+	ber_tag_t	tag;
+	ber_len_t	len;
 
-	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
+	assert( ber != NULL );
+	assert( LBER_VALID( ber ) );
 
-	if ( ber_getnint( ber, num, (int)len ) != len )
-		return( LBER_DEFAULT );
-	else
-		return( tag );
+	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
+		return LBER_DEFAULT;
+	}
+
+	if ( ber_getnint( ber, num, len ) != len ) {
+		return LBER_DEFAULT;
+	}
+	
+	return tag;
 }
 
-unsigned long
-ber_get_stringb( BerElement *ber, char *buf, unsigned long *len )
+ber_tag_t
+ber_get_enum(
+	BerElement *ber,
+	ber_int_t *num )
 {
-	unsigned long	datalen, tag;
-#ifdef STR_TRANSLATION
-	char		*transbuf;
-#endif /* STR_TRANSLATION */
+	return ber_get_int( ber, num );
+}
 
-	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
-	if ( datalen > (*len - 1) )
-		return( LBER_DEFAULT );
+ber_tag_t
+ber_get_stringb(
+	BerElement *ber,
+	char *buf,
+	ber_len_t *len )
+{
+	ber_len_t	datalen;
+	ber_tag_t	tag;
 
-	if ( ber_read( ber, buf, datalen ) != datalen )
-		return( LBER_DEFAULT );
+	assert( ber != NULL );
+	assert( LBER_VALID( ber ) );
+
+	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT ) {
+		return LBER_DEFAULT;
+	}
+
+	/* must fit within allocated space with termination */
+	if ( datalen >= *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;
 
 	buf[datalen] = '\0';
 
-#ifdef STR_TRANSLATION
-	if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
-	    && ber->ber_decode_translate_proc != NULL ) {
-		transbuf = buf;
-		++datalen;
-		if ( (*(ber->ber_decode_translate_proc))( &transbuf, &datalen,
-		    0 ) != 0 ) {
-			return( LBER_DEFAULT );
+	*len = datalen;
+	return tag;
+}
+
+/* Definitions for recursive get_string
+ *
+ * ChArray, BvArray, and BvVec are self-explanatory.
+ * BvOff is a struct berval embedded in an array of larger structures
+ * of siz bytes at off bytes from the beginning of the struct.
+ */
+enum bgbvc { ChArray, BvArray, BvVec, BvOff };
+
+/* Use this single cookie for state, to keep actual
+ * stack use to the absolute minimum.
+ */
+typedef struct bgbvr {
+	enum bgbvc choice;
+	BerElement *ber;
+	ber_tag_t tag;
+	ber_len_t len;
+	char *last;
+	int alloc;
+	ber_len_t siz;
+	ber_len_t off;
+	union {
+		char ***c;
+		BerVarray *ba;
+		struct berval ***bv;
+	} res;
+} bgbvr;
+
+/* Recursive get_string, for decoding a vector of strings. The number
+ * of elements in the vector is limited only by available stack space.
+ * Each invocation consumes 24 bytes of stack on a 32-bit machine.
+ */
+static ber_tag_t
+ber_get_stringbvr( bgbvr *b, int n )
+{
+	struct berval bv, *bvp = NULL;
+
+	if ( n )
+		b->tag = ber_next_element( b->ber, &b->len, b->last );
+	else
+		b->tag = ber_first_element( b->ber, &b->len, &b->last );
+
+	if ( b->tag == LBER_DEFAULT )
+	{
+		b->len = n;
+
+		if ( n == 0 ) {
+			*b->res.c = NULL;
+			return 0;
 		}
-		if ( datalen > *len ) {
-			free( transbuf );
-			return( LBER_DEFAULT );
+		/* Allocate the result vector */
+		switch (b->choice) {
+		case ChArray:
+			*b->res.c = LBER_MALLOC( (n+1) * sizeof( char * ));
+			if ( *b->res.c == NULL )
+				return LBER_DEFAULT;
+			(*b->res.c)[n] = NULL;
+			break;
+		case BvArray:
+			*b->res.ba = LBER_MALLOC( (n+1) * sizeof( struct berval ));
+			if ( *b->res.ba == NULL )
+				return LBER_DEFAULT;
+			(*b->res.ba)[n].bv_val = NULL;
+			break;
+		case BvVec:
+			*b->res.bv = LBER_MALLOC( (n+1) * sizeof( struct berval *));
+			if ( *b->res.bv == NULL )
+				return LBER_DEFAULT;
+			(*b->res.bv)[n] = NULL;
+			break;
+		case BvOff:
+			*b->res.ba = LBER_MALLOC( (n+1) * b->siz );
+			if ( *b->res.ba == NULL )
+				return LBER_DEFAULT;
+			((struct berval *)((long)(*b->res.ba) + n*b->siz +
+				b->off))->bv_val = NULL;
+			break;
 		}
-		SAFEMEMCPY( buf, transbuf, datalen );
-		free( transbuf );
-		--datalen;
+		return 0;
 	}
-#endif /* STR_TRANSLATION */
 
-	*len = datalen;
-	return( tag );
+	/* Do all local allocs before the recursion. Then there
+	 * cannot possibly be any failures on the return trip.
+	 */
+	if ( b->choice == BvVec )
+		bvp = LBER_MALLOC( sizeof( struct berval ));
+
+	if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT ) {
+		if ( bvp ) LBER_FREE( bvp );
+		return LBER_DEFAULT;
+	}
+
+	b->tag = ber_get_stringbvr( b, n+1 );
+	
+	if ( b->tag == 0 )
+	{
+		/* store my result */
+		switch (b->choice) {
+		case ChArray:
+			(*b->res.c)[n] = bv.bv_val;
+			break;
+		case BvArray:
+			(*b->res.ba)[n] = bv;
+			break;
+		case BvVec:
+			(*b->res.bv)[n] = bvp;
+			*bvp = bv;
+			break;
+		case BvOff:
+			*(BerVarray)((long)(*b->res.ba)+n*b->siz+b->off) = bv;
+		}
+	} else {
+		/* Failure will propagate up and free in reverse
+		 * order, which is actually ideal.
+		 */
+		if ( b->alloc ) LBER_FREE( bv.bv_val );
+		if ( bvp ) LBER_FREE( bvp );
+	}
+	return b->tag;
 }
 
-unsigned long
-ber_get_stringa( BerElement *ber, char **buf )
+ber_tag_t
+ber_get_stringbv( BerElement *ber, struct berval *bv, int alloc )
 {
-	unsigned long	datalen, tag;
-
-	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
-
-	if ( (*buf = (char *) malloc( (size_t)datalen + 1 )) == NULL )
-		return( LBER_DEFAULT );
-
-	if ( ber_read( ber, *buf, datalen ) != datalen )
-		return( LBER_DEFAULT );
-	(*buf)[datalen] = '\0';
-
-#ifdef STR_TRANSLATION
-	if ( datalen > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
-	    && ber->ber_decode_translate_proc != NULL ) {
-		++datalen;
-		if ( (*(ber->ber_decode_translate_proc))( buf, &datalen, 1 )
-		    != 0 ) {
-			free( *buf );
-			return( LBER_DEFAULT );
+	ber_tag_t	tag;
+
+	assert( ber != NULL );
+	assert( bv != NULL );
+
+	assert( LBER_VALID( ber ) );
+
+	if ( (tag = ber_skip_tag( ber, &bv->bv_len )) == LBER_DEFAULT ) {
+		bv->bv_val = NULL;
+		return LBER_DEFAULT;
+	}
+
+	if ( (ber_len_t) ber_pvt_ber_remaining( ber ) < bv->bv_len ) {
+		return LBER_DEFAULT;
+	}
+
+	if ( alloc ) {
+		if ( (bv->bv_val = (char *) LBER_MALLOC( bv->bv_len + 1 )) == NULL ) {
+			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;
 	}
-#endif /* STR_TRANSLATION */
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
+	bv->bv_val[bv->bv_len] = '\0';
 
-	return( tag );
+	return tag;
+}
+
+ber_tag_t
+ber_get_stringa( BerElement *ber, char **buf )
+{
+	BerValue	bv;
+	ber_tag_t	tag;
+
+	assert( buf != NULL );
+
+	tag = ber_get_stringbv( ber, &bv, 1 );
+	*buf = bv.bv_val;
+
+	return tag;
 }
 
-unsigned long
+ber_tag_t
 ber_get_stringal( BerElement *ber, struct berval **bv )
 {
-	unsigned long	len, tag;
-
-	if ( (*bv = (struct berval *) malloc( sizeof(struct berval) )) == NULL )
-		return( LBER_DEFAULT );
-
-	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
-
-	if ( ((*bv)->bv_val = (char *) malloc( (size_t)len + 1 )) == NULL )
-		return( LBER_DEFAULT );
-
-	if ( ber_read( ber, (*bv)->bv_val, len ) != len )
-		return( LBER_DEFAULT );
-	((*bv)->bv_val)[len] = '\0';
-	(*bv)->bv_len = len;
-
-#ifdef STR_TRANSLATION
-	if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0
-	    && ber->ber_decode_translate_proc != NULL ) {
-		++len;
-		if ( (*(ber->ber_decode_translate_proc))( &((*bv)->bv_val),
-		    &len, 1 ) != 0 ) {
-			free( (*bv)->bv_val );
-			return( LBER_DEFAULT );
-		}
-		(*bv)->bv_len = len - 1;
+	ber_tag_t	tag;
+
+	assert( ber != NULL );
+	assert( bv != NULL );
+
+	*bv = (struct berval *) LBER_MALLOC( sizeof(struct berval) );
+	if ( *bv == NULL ) {
+		return LBER_DEFAULT;
 	}
-#endif /* STR_TRANSLATION */
 
-	return( tag );
+	tag = ber_get_stringbv( ber, *bv, 1 );
+	if ( tag == LBER_DEFAULT ) {
+		LBER_FREE( *bv );
+		*bv = NULL;
+	}
+	return tag;
 }
 
-unsigned long
-ber_get_bitstringa( BerElement *ber, char **buf, unsigned long *blen )
+ber_tag_t
+ber_get_bitstringa(
+	BerElement *ber,
+	char **buf,
+	ber_len_t *blen )
 {
-	unsigned long	datalen, tag;
+	ber_len_t	datalen;
+	ber_tag_t	tag;
 	unsigned char	unusedbits;
 
-	if ( (tag = ber_skip_tag( ber, &datalen )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
+	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;
+	}
 	--datalen;
 
-	if ( (*buf = (char *) malloc( (size_t)datalen )) == NULL )
-		return( LBER_DEFAULT );
+	if ( (*buf = (char *) LBER_MALLOC( datalen )) == NULL ) {
+		return LBER_DEFAULT;
+	}
 
-	if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 )
-		return( LBER_DEFAULT );
+	if ( ber_read( ber, (char *)&unusedbits, 1 ) != 1 ) {
+		LBER_FREE( buf );
+		*buf = NULL;
+		return LBER_DEFAULT;
+	}
 
-	if ( ber_read( ber, *buf, datalen ) != datalen )
-		return( LBER_DEFAULT );
+	if ( (ber_len_t) ber_read( ber, *buf, datalen ) != datalen ) {
+		LBER_FREE( buf );
+		*buf = NULL;
+		return LBER_DEFAULT;
+	}
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
 	*blen = datalen * 8 - unusedbits;
-	return( tag );
+	return tag;
 }
 
-unsigned long
+ber_tag_t
 ber_get_null( BerElement *ber )
 {
-	unsigned long	len, tag;
+	ber_len_t	len;
+	ber_tag_t	tag;
+
+	assert( ber != NULL );
+	assert( LBER_VALID( ber ) );
 
-	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT )
-		return( LBER_DEFAULT );
+	if ( (tag = ber_skip_tag( ber, &len )) == LBER_DEFAULT ) {
+		return LBER_DEFAULT;
+	}
 
-	if ( len != 0 )
-		return( LBER_DEFAULT );
+	if ( len != 0 ) {
+		return LBER_DEFAULT;
+	}
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
 	return( tag );
 }
 
-unsigned long
-ber_get_boolean( BerElement *ber, int *boolval )
+ber_tag_t
+ber_get_boolean(
+	BerElement *ber,
+	ber_int_t *boolval )
 {
-	long	longbool;
-	int	rc;
+	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 rc;
 }
 
-unsigned long
-ber_first_element( BerElement *ber, unsigned long *len, char **last )
+ber_tag_t
+ber_first_element(
+	BerElement *ber,
+	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 */
 	if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
-		return( LBER_DEFAULT );
+		*last = NULL;
+		return LBER_DEFAULT;
 	}
+	ber->ber_tag = *(unsigned char *)ber->ber_ptr;
 
 	*last = ber->ber_ptr + *len;
 
 	if ( *last == ber->ber_ptr ) {
-		return( LBER_DEFAULT );
+		return LBER_DEFAULT;
 	}
 
-	return( ber_peek_tag( ber, len ) );
+	return ber_peek_tag( ber, len );
 }
 
-unsigned long
-ber_next_element( BerElement *ber, unsigned long *len, char *last )
+ber_tag_t
+ber_next_element(
+	BerElement *ber,
+	ber_len_t *len,
+	LDAP_CONST char *last )
 {
+	assert( ber != NULL );
+	assert( len != NULL );
+	assert( last != NULL );
+
+	assert( LBER_VALID( ber ) );
+
 	if ( ber->ber_ptr == last ) {
-		return( LBER_DEFAULT );
+		return LBER_DEFAULT;
 	}
 
-	return( ber_peek_tag( ber, len ) );
+	return ber_peek_tag( ber, len );
 }
 
 /* VARARGS */
-unsigned long
-ber_scanf(
-#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
-	BerElement *ber, char *fmt, ... )
-#else
-	va_alist )
-va_dcl
-#endif
+ber_tag_t
+ber_scanf ( BerElement *ber,
+	LDAP_CONST char *fmt,
+	... )
 {
 	va_list		ap;
-#if !defined( MACOS ) && !defined( BC31 ) && !defined( _WIN32 )
-	BerElement	*ber;
-	char		*fmt;
-#endif
+	LDAP_CONST char		*fmt_reset;
+	char		*s, **ss;
+#ifdef TMP_SLOTS
 	char		*last;
-	char		*s, **ss, ***sss;
-	struct berval 	***bv, **bvp, *bval;
-	int		*i, j;
-	long		*l, rc, tag;
-	unsigned long	len;
+	char ***sss;
+	ber_tag_t tag;
+	struct berval ***bv;
+	int j;
+#endif
+	struct berval	**bvp, *bval;
+	ber_int_t	*i;
+	ber_len_t	*l;
+	ber_tag_t	*t;
+	ber_tag_t	rc;
+	ber_len_t	len;
 
-#if defined( MACOS ) || defined( BC31 ) || defined( _WIN32 )
 	va_start( ap, fmt );
-#else
-	va_start( ap );
-	ber = va_arg( ap, BerElement * );
-	fmt = va_arg( ap, char * );
-#endif
 
-#ifdef LDAP_DEBUG
-	if ( lber_debug & 64 ) {
-		fprintf( stderr, "ber_scanf fmt (%s) ber:\n", fmt );
-		ber_dump( ber, 1 );
-	}
+	assert( ber != NULL );
+	assert( fmt != NULL );
+
+	assert( LBER_VALID( ber ) );
+
+	fmt_reset = fmt;
+
+#ifdef NEW_LOGGING
+	LDAP_LOG( BER, ENTRY, "ber_scanf fmt (%s) ber:\n", fmt, 0, 0 );
+
+	if ( LDAP_LOGS_TEST(BER, DETAIL2 ))
+			BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
+#else
+	ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
+		"ber_scanf fmt (%s) ber:\n", fmt );
+	ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
 #endif
 
 	for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
+		/* When this is modified, remember to update
+		 * the error-cleanup code below accordingly. */
 		switch ( *fmt ) {
+		case '!': { /* Hook */
+				BERDecodeCallback *f;
+				void *p;
+
+				f = va_arg( ap, BERDecodeCallback * );
+				p = va_arg( ap, void * );
+
+				rc = (*f)( ber, p, 0 );
+			} break;
+
 		case 'a':	/* octet string - allocate storage as needed */
 			ss = va_arg( ap, char ** );
 			rc = ber_get_stringa( ber, ss );
 			break;
 
 		case 'b':	/* boolean */
-			i = va_arg( ap, int * );
+			i = va_arg( ap, ber_int_t * );
 			rc = ber_get_boolean( ber, i );
 			break;
 
 		case 'e':	/* enumerated */
 		case 'i':	/* int */
-			l = va_arg( ap, long * );
-			rc = ber_get_int( ber, l );
+			i = va_arg( ap, ber_int_t * );
+			rc = ber_get_int( ber, i );
 			break;
 
 		case 'l':	/* length of next item */
-			l = va_arg( ap, long * );
-			rc = ber_peek_tag( ber, (unsigned long *)l );
+			l = va_arg( ap, ber_len_t * );
+			rc = ber_peek_tag( ber, l );
 			break;
 
 		case 'n':	/* null */
@@ -446,14 +694,18 @@ va_dcl
 
 		case 's':	/* octet string - in a buffer */
 			s = va_arg( ap, char * );
-			l = va_arg( ap, long * );
-			rc = ber_get_stringb( ber, s, (unsigned long *)l );
+			l = va_arg( ap, ber_len_t * );
+			rc = ber_get_stringb( ber, s, l );
+			break;
+
+		case 'm':	/* octet string in berval, in-place */
+			bval = va_arg( ap, struct berval * );
+			rc = ber_get_stringbv( ber, bval, 0 );
 			break;
 
 		case 'o':	/* octet string in a supplied berval */
 			bval = va_arg( ap, struct berval * );
-			ber_peek_tag( ber, &bval->bv_len );
-			rc = ber_get_stringa( ber, &bval->bv_val );
+			rc = ber_get_stringbv( ber, bval, 1 );
 			break;
 
 		case 'O':	/* octet string - allocate & include length */
@@ -463,71 +715,79 @@ va_dcl
 
 		case 'B':	/* bit string - allocate storage as needed */
 			ss = va_arg( ap, char ** );
-			l = va_arg( ap, long * ); /* for length, in bits */
-			rc = ber_get_bitstringa( ber, ss, (unsigned long *)l );
+			l = va_arg( ap, ber_len_t * ); /* for length, in bits */
+			rc = ber_get_bitstringa( ber, ss, l );
 			break;
 
 		case 't':	/* tag of next item */
-			i = va_arg( ap, int * );
-			*i = rc = ber_peek_tag( ber, &len );
+			t = va_arg( ap, ber_tag_t * );
+			*t = rc = ber_peek_tag( ber, &len );
 			break;
 
 		case 'T':	/* skip tag of next item */
-			i = va_arg( ap, int * );
-			*i = rc = ber_skip_tag( ber, &len );
+			t = va_arg( ap, ber_tag_t * );
+			*t = rc = ber_skip_tag( ber, &len );
 			break;
 
 		case 'v':	/* sequence of strings */
-			sss = va_arg( ap, char *** );
-			*sss = NULL;
-			j = 0;
-			for ( tag = ber_first_element( ber, &len, &last );
-			    tag != LBER_DEFAULT && rc != LBER_DEFAULT;
-			    tag = ber_next_element( ber, &len, last ) ) {
-				if ( *sss == NULL ) {
-					*sss = (char **) malloc(
-					    2 * sizeof(char *) );
-				} else {
-					*sss = (char **) realloc( *sss,
-					    (j + 2) * sizeof(char *) );
-				}
-				rc = ber_get_stringa( ber, &((*sss)[j]) );
-				j++;
-			}
-			if ( j > 0 )
-				(*sss)[j] = NULL;
+		{
+			bgbvr cookie = { ChArray };
+			cookie.ber = ber;
+			cookie.res.c = va_arg( ap, char *** );
+			cookie.alloc = 1;
+			rc = ber_get_stringbvr( &cookie, 0 );
 			break;
+		}
 
 		case 'V':	/* sequence of strings + lengths */
-			bv = va_arg( ap, struct berval *** );
-			*bv = NULL;
-			j = 0;
-			for ( tag = ber_first_element( ber, &len, &last );
-			    tag != LBER_DEFAULT && rc != LBER_DEFAULT;
-			    tag = ber_next_element( ber, &len, last ) ) {
-				if ( *bv == NULL ) {
-					*bv = (struct berval **) malloc(
-					    2 * sizeof(struct berval *) );
-				} else {
-					*bv = (struct berval **) realloc( *bv,
-					    (j + 2) * sizeof(struct berval *) );
-				}
-				rc = ber_get_stringal( ber, &((*bv)[j]) );
-				j++;
-			}
-			if ( j > 0 )
-				(*bv)[j] = NULL;
+		{
+			bgbvr cookie = { BvVec };
+			cookie.ber = ber;
+			cookie.res.bv = va_arg( ap, struct berval *** );
+			cookie.alloc = 1;
+			rc = ber_get_stringbvr( &cookie, 0 );
+			break;
+		}
+
+		case 'W':	/* bvarray */
+		{
+			bgbvr cookie = { BvArray };
+			cookie.ber = ber;
+			cookie.res.ba = va_arg( ap, struct berval ** );
+			cookie.alloc = 1;
+			rc = ber_get_stringbvr( &cookie, 0 );
 			break;
+		}
+
+		case 'M':	/* bvoffarray - must include address of
+				 * a record len, and record offset.
+				 * number of records will be returned thru
+				 * len ptr on finish. parsed in-place.
+				 */
+		{
+			bgbvr cookie = { BvOff };
+			cookie.ber = ber;
+			cookie.res.ba = va_arg( ap, struct berval ** );
+			cookie.alloc = 0;
+			l = va_arg( ap, ber_len_t * );
+			cookie.siz = *l;
+			cookie.off = va_arg( ap, ber_len_t );
+			rc = ber_get_stringbvr( &cookie, 0 );
+			*l = cookie.len;
+			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;
 			break;
 
 		case '{':	/* begin sequence */
 		case '[':	/* begin set */
-			if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V' )
+			if ( *(fmt + 1) != 'v' && *(fmt + 1) != 'V'
+				&& *(fmt + 1) != 'W' && *(fmt + 1) != 'M' )
 				rc = ber_skip_tag( ber, &len );
 			break;
 
@@ -536,63 +796,115 @@ va_dcl
 			break;
 
 		default:
-#ifndef NO_USERINTERFACE
-			fprintf( stderr, "unknown fmt %c\n", *fmt );
-#endif /* NO_USERINTERFACE */
+			if( ber->ber_debug ) {
+#ifdef NEW_LOGGING
+				LDAP_LOG( BER, ERR, 
+					"ber_scanf: unknown fmt %c\n", *fmt, 0, 0 );
+#else
+				ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
+					"ber_scanf: unknown fmt %c\n", *fmt );
+#endif
+			}
 			rc = LBER_DEFAULT;
 			break;
 		}
 	}
 
 	va_end( ap );
+	if ( rc == LBER_DEFAULT ) {
+	    /*
+	     * Error.  Reclaim malloced memory that was given to the caller.
+	     * Set allocated pointers to NULL, "data length" outvalues to 0.
+	     */
+	    va_start( ap, fmt );
 
-	return( rc );
-}
+	    for ( ; fmt_reset < fmt; fmt_reset++ ) {
+		switch ( *fmt_reset ) {
+		case '!': { /* Hook */
+				BERDecodeCallback *f;
+				void *p;
 
-void
-ber_bvfree( struct berval *bv )
-{
-	if ( bv->bv_val != NULL )
-		free( bv->bv_val );
-	free( (char *) bv );
-}
+				f = va_arg( ap, BERDecodeCallback * );
+				p = va_arg( ap, void * );
 
-void
-ber_bvecfree( struct berval **bv )
-{
-	int	i;
+				(void) (*f)( ber, p, 1 );
+			} break;
 
-	for ( i = 0; bv[i] != NULL; i++ )
-		ber_bvfree( bv[i] );
-	free( (char *) bv );
-}
+		case 'a':	/* octet string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			if ( *ss ) {
+				LBER_FREE( *ss );
+				*ss = NULL;
+			}
+			break;
 
-struct berval *
-ber_bvdup( struct berval *bv )
-{
-	struct berval	*new;
+		case 'b':	/* boolean */
+		case 'e':	/* enumerated */
+		case 'i':	/* int */
+			(void) va_arg( ap, int * );
+			break;
 
-	if ( (new = (struct berval *) malloc( sizeof(struct berval) ))
-	    == NULL ) {
-		return( NULL );
-	}
-	if ( (new->bv_val = (char *) malloc( bv->bv_len + 1 )) == NULL ) {
-		return( NULL );
-	}
-	SAFEMEMCPY( new->bv_val, bv->bv_val, (size_t) bv->bv_len );
-	new->bv_val[bv->bv_len] = '\0';
-	new->bv_len = bv->bv_len;
+		case 's':	/* octet string - in a buffer */
+			(void) va_arg( ap, char * );
+			(void) va_arg( ap, ber_len_t * );
+			break;
 
-	return( new );
-}
+		case 'l':	/* length of next item */
+			(void) va_arg( ap, ber_len_t * );
+			break;
 
+		case 't':	/* tag of next item */
+		case 'T':	/* skip tag of next item */
+			(void) va_arg( ap, ber_tag_t * );
+			break;
 
-#ifdef STR_TRANSLATION
-void
-ber_set_string_translators( BerElement *ber, BERTranslateProc encode_proc,
-	BERTranslateProc decode_proc )
-{
-    ber->ber_encode_translate_proc = encode_proc;
-    ber->ber_decode_translate_proc = decode_proc;
+		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;
+			break;
+
+		case 'O':	/* octet string - allocate & include length */
+			bvp = va_arg( ap, struct berval ** );
+			if ( *bvp ) {
+				ber_bvfree( *bvp );
+				*bvp = NULL;
+			}
+			break;
+
+		case 'B':	/* bit string - allocate storage as needed */
+			ss = va_arg( ap, char ** );
+			if ( *ss ) {
+				LBER_FREE( *ss );
+				*ss = NULL;
+			}
+			*(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */
+			break;
+
+		case 'v':	/* sequence of strings */
+		case 'V':	/* sequence of strings + lengths */
+		case 'W':	/* BerVarray */
+		case 'm':	/* berval in-place */
+		case 'M':	/* BVoff array in-place */
+		case 'n':	/* null */
+		case 'x':	/* skip the next element - whatever it is */
+		case '{':	/* begin sequence */
+		case '[':	/* begin set */
+		case '}':	/* end sequence */
+		case ']':	/* end set */
+			break;
+
+		default:
+			/* format should be good */
+			assert( 0 );
+		}
+	    }
+
+	    va_end( ap );
+	}
+
+	return rc;
 }
-#endif /* STR_TRANSLATION */
diff --git a/libraries/liblber/encode.c b/libraries/liblber/encode.c
index 50eb6b5f9234af5e596f6da5ab4a3c084cada359..fefad6d3ecc6061850a2a800153b940e22118032 100644
--- a/libraries/liblber/encode.c
+++ b/libraries/liblber/encode.c
@@ -812,8 +812,8 @@ ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... )
 		default:
 			if( ber->ber_debug ) {
 #ifdef NEW_LOGGING
-				LDAP_LOG(( "liblber", LDAP_LEVEL_ERR,
-					   "ber_printf: unknown fmt %c\n", *fmt ));
+				LDAP_LOG( BER, ERR, 
+					"ber_printf: unknown fmt %c\n", *fmt, 0, 0 );
 #else
 				ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
 					"ber_printf: unknown fmt %c\n", *fmt );
diff --git a/libraries/liblber/io.c b/libraries/liblber/io.c
index 6474acd56d4f3481d0d48882a35a522644b70145..4e3a1cebd84ad07bcf6a9e510b9cd39d2caa16ab 100644
--- a/libraries/liblber/io.c
+++ b/libraries/liblber/io.c
@@ -33,6 +33,7 @@
 #endif
 
 #include "lber-int.h"
+#include "ldap_log.h"
 
 ber_slen_t
 ber_read(
@@ -207,11 +208,14 @@ ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
 
 	if ( sb->sb_debug ) {
 #ifdef NEW_LOGGING
-		LDAP_LOG(( "liblber", LDAP_LEVEL_DETAIL1,
+		LDAP_LOG( BER, DETAIL1,
 			   "ber_flush: %ld bytes to sd %ld%s\n",
 			   towrite, (long)sb->sb_fd,
-			   ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" ));
-		BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
+			   ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" );
+
+		if(LDAP_LOGS_TEST(BER, DETAIL2))
+				BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
+
 #else
 		ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
 			"ber_flush: %ld bytes to sd %ld%s\n",
@@ -441,7 +445,7 @@ ber_get_next(
 	assert( LBER_VALID( ber ) );
 
 #ifdef NEW_LOGGING
-	LDAP_LOG(( "liblber", LDAP_LEVEL_ENTRY, "ber_get_next: enter\n" ));
+	LDAP_LOG( BER, ENTRY, "ber_get_next: enter\n", 0, 0, 0 );
 #else
 	ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
 		"ber_get_next\n" );
@@ -509,6 +513,8 @@ ber_get_next(
 			ber->ber_ptr = (char *)p;
 		}
 
+		if (i == 1) continue;
+
 		/* Now look for the length */
 		if (*ber->ber_ptr & 0x80) {	/* multi-byte */
 			int llen = *(unsigned char *)ber->ber_ptr++ & 0x7f;
@@ -548,9 +554,9 @@ ber_get_next(
 			return LBER_DEFAULT;
 		} else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
 #ifdef NEW_LOGGING
-			LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, 
+			LDAP_LOG( BER, ERR, 
 				"ber_get_next: sockbuf_max_incoming limit hit "
-				"(%d > %d)\n", ber->ber_len, sb->sb_max_incoming ));
+				"(%d > %d)\n", ber->ber_len, sb->sb_max_incoming, 0 );
 #else
 			ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
 				"ber_get_next: sockbuf_max_incoming limit hit "
@@ -616,10 +622,11 @@ done:
 		*len = ber->ber_len;
 		if ( ber->ber_debug ) {
 #ifdef NEW_LOGGING
-			LDAP_LOG(( "liblber", LDAP_LEVEL_DETAIL1,
-				"ber_get_next: tag 0x%lx len %ld\n",
-				ber->ber_tag, ber->ber_len ));
-			BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
+			LDAP_LOG( BER, DETAIL1, 
+				"ber_get_next: tag 0x%lx len %ld\n", 
+				ber->ber_tag, ber->ber_len, 0  );
+			if(LDAP_LOGS_TEST(BER, DETAIL2))
+					BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
 #else
 			ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
 				"ber_get_next: tag 0x%lx len %ld contents:\n",
diff --git a/libraries/liblber/lber-int.h b/libraries/liblber/lber-int.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d6ad83ba3a2bb841539d4910cd1f5c9b08a2ecb
--- /dev/null
+++ b/libraries/liblber/lber-int.h
@@ -0,0 +1,207 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* Portions
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#ifndef _LBER_INT_H
+#define _LBER_INT_H
+
+#include "lber.h"
+#include "ldap_log.h"
+#include "lber_pvt.h"
+#include "ldap_queue.h"
+
+LDAP_BEGIN_DECL
+
+typedef void (*BER_LOG_FN)(FILE *file,
+	const char *subsys, int level, const char *fmt, ... );
+
+LBER_V (BER_ERRNO_FN) ber_int_errno_fn;
+
+struct lber_options {
+	short lbo_valid;
+	unsigned short		lbo_options;
+	int			lbo_debug;
+	long		lbo_meminuse;
+};
+
+#ifdef NEW_LOGGING
+/*
+#    ifdef LDAP_DEBUG
+#        ifdef LDAP_LOG
+#            undef LDAP_LOG
+#        endif
+#        define LDAP_LOG(a) ber_pvt_log_output a
+ */
+#        define BER_DUMP(a) ber_output_dump a
+/*
+#    else
+#        define LDAP_LOG(a)
+#        define BER_DUMP(a)
+#    endif
+ */
+#endif
+
+LBER_F( int ) ber_pvt_log_output(
+	const char *subsystem,
+	int level,
+	const char *fmt, ... );
+
+#define LBER_UNINITIALIZED		0x0
+#define LBER_INITIALIZED		0x1
+#define LBER_VALID_BERELEMENT	0x2
+#define LBER_VALID_SOCKBUF		0x3
+
+LBER_V (struct lber_options) ber_int_options;
+#define ber_int_debug ber_int_options.lbo_debug
+
+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
+
+	/* Do not change the order of these 3 fields! see ber_get_next */
+	ber_tag_t	ber_tag;
+	ber_len_t	ber_len;
+	ber_tag_t	ber_usertag;
+
+	char		*ber_buf;
+	char		*ber_ptr;
+	char		*ber_end;
+
+	struct seqorset	*ber_sos;
+	char		*ber_rwptr;
+};
+#define LBER_VALID(ber)	((ber)->ber_valid==LBER_VALID_BERELEMENT)
+
+#define ber_pvt_ber_remaining(ber)	((ber)->ber_end - (ber)->ber_ptr)
+#define ber_pvt_ber_total(ber)		((ber)->ber_end - (ber)->ber_buf)
+#define ber_pvt_ber_write(ber)		((ber)->ber_ptr - (ber)->ber_buf)
+
+struct sockbuf {
+	struct lber_options sb_opts;
+	Sockbuf_IO_Desc		*sb_iod;		/* I/O functions */
+#define	sb_valid		sb_opts.lbo_valid
+#define	sb_options		sb_opts.lbo_options
+#define	sb_debug		sb_opts.lbo_debug
+	ber_socket_t		sb_fd;
+   	unsigned int		sb_trans_needs_read:1;
+   	unsigned int		sb_trans_needs_write:1;
+	ber_len_t			sb_max_incoming;
+};
+
+#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;
+};
+
+
+/*
+ * io.c
+ */
+LBER_F( int )
+ber_realloc LDAP_P((
+	BerElement *ber,
+	ber_len_t len ));
+
+/*
+ * bprint.c
+ */
+#define ber_log_printf ber_pvt_log_printf
+
+#ifdef NEW_LOGGING
+LBER_F( int )
+ber_output_dump LDAP_P((
+	const char *subsys,
+	int level,
+	BerElement *ber,
+	int inout ));
+#endif
+
+LBER_F( int )
+ber_log_bprint LDAP_P((
+	int errlvl,
+	int loglvl,
+	const char *data,
+	ber_len_t len ));
+
+LBER_F( int )
+ber_log_dump LDAP_P((
+	int errlvl,
+	int loglvl,
+	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;
+
+/* memory.c */
+	/* simple macros to realloc for now */
+LBER_V (BerMemoryFunctions *)	ber_int_memory_fns;
+LBER_F (char *)	ber_strndup( LDAP_CONST char *, ber_len_t );
+LBER_F (char *)	ber_strndup__( LDAP_CONST char *, size_t );
+
+#ifdef CSRIMALLOC
+#define LBER_MALLOC			malloc
+#define LBER_CALLOC			calloc
+#define LBER_REALLOC		realloc
+#define LBER_FREE			free
+#define LBER_VFREE			ber_memvfree
+#define LBER_STRDUP			strdup
+#define LBER_STRNDUP		ber_strndup__
+
+#else
+#define LBER_MALLOC(s)		ber_memalloc((s))
+#define LBER_CALLOC(n,s)	ber_memcalloc((n),(s))
+#define LBER_REALLOC(p,s)	ber_memrealloc((p),(s))
+#define LBER_FREE(p)		ber_memfree((p))	
+#define LBER_VFREE(v)		ber_memvfree((void**)(v))
+#define LBER_STRDUP(s)		ber_strdup((s))
+#define LBER_STRNDUP(s,l)	ber_strndup((s),(l))
+#endif
+
+/* sockbuf.c */
+
+LBER_F(	int )
+ber_int_sb_init LDAP_P(( Sockbuf *sb ));
+
+LBER_F( int )
+ber_int_sb_close LDAP_P(( Sockbuf *sb ));
+
+LBER_F(	int )
+ber_int_sb_destroy LDAP_P(( Sockbuf *sb ));
+
+LBER_F( ber_slen_t )
+ber_int_sb_read LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
+
+LBER_F( ber_slen_t )
+ber_int_sb_write LDAP_P(( Sockbuf *sb, void *buf, ber_len_t len ));
+
+LDAP_END_DECL
+
+#endif /* _LBER_INT_H */
diff --git a/libraries/liblber/liblber.dsp b/libraries/liblber/liblber.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..02c82831f9b532ef77b5df85d27acff675c27131
--- /dev/null
+++ b/libraries/liblber/liblber.dsp
@@ -0,0 +1,229 @@
+# Microsoft Developer Studio Project File - Name="liblber" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=liblber - Win32 DLL Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "liblber.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "liblber.mak" CFG="liblber - Win32 DLL Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "liblber - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblber - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblber - Win32 Single Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblber - Win32 Single Release" (based on\
+ "Win32 (x86) Static Library")
+!MESSAGE "liblber - Win32 DLL Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblber - Win32 DLL Release" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+
+!IF  "$(CFG)" == "liblber - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\Release"
+# PROP Intermediate_Dir "..\..\Release\liblber"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\Release\olber32.lib"
+
+!ELSEIF  "$(CFG)" == "liblber - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\Debug"
+# PROP Intermediate_Dir "..\..\Debug\liblber"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\Debug\olber32.lib"
+
+!ELSEIF  "$(CFG)" == "liblber - Win32 Single Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "liblber_"
+# PROP BASE Intermediate_Dir "liblber_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\Sdebug"
+# PROP Intermediate_Dir "..\..\SDebug\liblber"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\Debug\olber32.lib"
+# ADD LIB32 /nologo /out:"..\..\SDebug\olber32.lib"
+
+!ELSEIF  "$(CFG)" == "liblber - Win32 Single Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "liblber0"
+# PROP BASE Intermediate_Dir "liblber0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\SRelease"
+# PROP Intermediate_Dir "..\..\SRelease\liblber"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\Release\olber32.lib"
+# ADD LIB32 /nologo /out:"..\..\SRelease\olber32.lib"
+
+!ELSEIF  "$(CFG)" == "liblber - Win32 DLL Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "liblber_"
+# PROP BASE Intermediate_Dir "liblber_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\DLLDebug"
+# PROP Intermediate_Dir "..\..\DLLDebug\liblber"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\..\Debug\olber32.lib"
+# ADD LIB32 /nologo /out:"..\..\DLLDebug\olber32.lib"
+
+!ELSEIF  "$(CFG)" == "liblber - Win32 DLL Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "liblber0"
+# PROP BASE Intermediate_Dir "liblber0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "liblber0"
+# PROP Intermediate_Dir "liblber0"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\..\Release\olber32.lib"
+# ADD LIB32 /nologo /out:"..\..\Release\olber32.lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "liblber - Win32 Release"
+# Name "liblber - Win32 Debug"
+# Name "liblber - Win32 Single Debug"
+# Name "liblber - Win32 Single Release"
+# Name "liblber - Win32 DLL Debug"
+# Name "liblber - Win32 DLL Release"
+# Begin Source File
+
+SOURCE=.\bprint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\debug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\decode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\encode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\io.c
+# End Source File
+# Begin Source File
+
+SOURCE=".\lber-int.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lber.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lber_pvt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lber_types.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\memory.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\nt_err.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\options.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sockbuf.c
+# End Source File
+# End Target
+# End Project
diff --git a/libraries/libldap_r/thr_posix.c b/libraries/libldap_r/thr_posix.c
new file mode 100644
index 0000000000000000000000000000000000000000..fef18fe9cafc76bcf7c370a6df77d4b657568f7f
--- /dev/null
+++ b/libraries/libldap_r/thr_posix.c
@@ -0,0 +1,317 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, Redwood City, California, USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted only
+ * as authorized by the OpenLDAP Public License.  A copy of this
+ * license is available at http://www.OpenLDAP.org/license.html or
+ * in file LICENSE in the top-level directory of the distribution.
+ */
+
+/* thr_posix.c - wrapper around posix and posixish thread implementations.
+ */
+
+#include "portable.h"
+
+#if defined( HAVE_PTHREADS )
+
+#include <ac/errno.h>
+
+#include "ldap_pvt_thread.h"
+
+
+#if HAVE_PTHREADS_D4
+#  define LDAP_INT_THREAD_ATTR_DEFAULT		pthread_attr_default
+#  define LDAP_INT_THREAD_CONDATTR_DEFAULT	pthread_condattr_default
+#  define LDAP_INT_THREAD_MUTEXATTR_DEFAULT	pthread_mutexattr_default
+#else
+#  define LDAP_INT_THREAD_ATTR_DEFAULT		NULL
+#  define LDAP_INT_THREAD_CONDATTR_DEFAULT	NULL
+#  define LDAP_INT_THREAD_MUTEXATTR_DEFAULT	NULL
+#endif
+
+
+int
+ldap_int_thread_initialize( void )
+{
+	return 0;
+}
+
+int
+ldap_int_thread_destroy( void )
+{
+#ifdef HAVE_PTHREAD_KILL_OTHER_THREADS_NP
+	/* LinuxThreads: kill clones */
+	pthread_kill_other_threads_np();
+#endif
+	return 0;
+}
+
+#ifdef LDAP_THREAD_HAVE_SETCONCURRENCY
+int
+ldap_pvt_thread_set_concurrency(int n)
+{
+#ifdef HAVE_PTHREAD_SETCONCURRENCY
+	return pthread_setconcurrency( n );
+#elif HAVE_THR_SETCONCURRENCY
+	return thr_setconcurrency( n );
+#else
+	return 0;
+#endif
+}
+#endif
+
+#ifdef LDAP_THREAD_HAVE_GETCONCURRENCY
+int
+ldap_pvt_thread_get_concurrency(void)
+{
+#ifdef HAVE_PTHREAD_GETCONCURRENCY
+	return pthread_getconcurrency();
+#elif HAVE_THR_GETCONCURRENCY
+	return thr_getconcurrency();
+#else
+	return 0;
+#endif
+}
+#endif
+
+int 
+ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
+	int detach,
+	void *(*start_routine)( void * ),
+	void *arg)
+{
+	int rtn;
+#if defined( HAVE_PTHREADS_FINAL )
+	pthread_attr_t attr;
+	pthread_attr_init(&attr);
+
+#if defined( PTHREAD_CREATE_JOINABLE ) || defined( PTHREAD_UNDETACHED )
+	if (!detach) {
+#if defined( PTHREAD_CREATE_JOINABLE )
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+#else
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
+#endif
+#ifdef PTHREAD_CREATE_DETACHED
+	} else {
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+#elif HAVE_PTHREADS_OS390
+	} else {
+		int st = __DETACHED;
+		pthread_attr_setdetachstate(&attr, &st);
+#endif
+	}
+#endif
+
+#if defined(LDAP_PVT_THREAD_STACK_SIZE) && LDAP_PVT_THREAD_STACK_SIZE > 0
+	/* this should be tunable */
+	pthread_attr_setstacksize( &attr, LDAP_PVT_THREAD_STACK_SIZE );
+#endif
+
+	rtn = pthread_create( thread, &attr, start_routine, arg );
+#ifdef HAVE_PTHREADS_OS390
+	if ( rtn == -1 ) rtn = errno;
+#endif
+
+#if !defined( PTHREAD_CREATE_JOINABLE ) && !defined( PTHREAD_UNDETACHED )
+	if( detach ) {
+#ifdef HAVE_PTHREADS_OS390
+		(void) pthread_detach( thread );
+#else
+		(void) pthread_detach( *thread );
+#endif
+	}
+#endif
+	pthread_attr_destroy(&attr);
+
+#else
+	rtn = pthread_create( thread, LDAP_INT_THREAD_ATTR_DEFAULT,
+		start_routine, arg );
+
+	if( detach ) {
+		pthread_detach( thread );
+	}
+#endif
+
+	return rtn;
+}
+
+void 
+ldap_pvt_thread_exit( void *retval )
+{
+	pthread_exit( retval );
+}
+
+int 
+ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
+{
+#if !defined( HAVE_PTHREADS_FINAL )
+	void *dummy;
+	if (thread_return==NULL)
+	  thread_return=&dummy;
+#endif	
+#ifdef HAVE_PTHREADS_OS390
+	int st = pthread_join( thread, thread_return ); 
+	if ( st == -1 ) st = errno;
+	return st;
+#else
+	return pthread_join( thread, thread_return );
+#endif
+}
+
+int 
+ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
+{
+#ifdef HAVE_PTHREAD_KILL
+#ifdef HAVE_PTHREADS_OS390
+	int st = pthread_kill( thread, signo );
+	if ( st == -1 ) st = errno;
+	return st;
+#else
+	return pthread_kill( thread, signo );
+#endif
+#else
+	/* pthread package with DCE */
+	if (kill( getpid(), signo )<0)
+		return errno;
+	return 0;
+#endif
+}
+
+int 
+ldap_pvt_thread_yield( void )
+{
+#ifdef _POSIX_THREAD_IS_GNU_PTH
+	sched_yield();
+	return 0;
+
+#elif HAVE_SCHED_YIELD
+	return sched_yield();
+
+#elif HAVE_PTHREAD_YIELD
+#if HAVE_PTHREADS_OS390
+	pthread_yield(NULL);
+#else
+	pthread_yield();
+#endif
+	return 0;
+
+#elif HAVE_THR_YIELD
+	return thr_yield();
+
+#else
+	return 0;
+#endif   
+}
+
+int 
+ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
+{
+	return pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT );
+}
+
+int 
+ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
+{
+	return pthread_cond_destroy( cond );
+}
+	
+int 
+ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
+{
+	return pthread_cond_signal( cond );
+}
+
+int
+ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
+{
+	return pthread_cond_broadcast( cond );
+}
+
+int 
+ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, 
+		      ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_cond_wait( cond, mutex );
+}
+
+int 
+ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT );
+}
+
+int 
+ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_mutex_destroy( mutex );
+}
+
+int 
+ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_mutex_lock( mutex );
+}
+
+int 
+ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_mutex_trylock( mutex );
+}
+
+int 
+ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
+{
+	return pthread_mutex_unlock( mutex );
+}
+
+#ifdef LDAP_THREAD_HAVE_RDWR
+#ifdef HAVE_PTHREAD_RWLOCK_DESTROY
+int 
+ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_init( rw, NULL );
+}
+
+int 
+ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_destroy( rw );
+}
+
+int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_rdlock( rw );
+}
+
+int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_tryrdlock( rw );
+}
+
+int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_unlock( rw );
+}
+
+int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_wrlock( rw );
+}
+
+int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_trywrlock( rw );
+}
+
+int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
+{
+	return pthread_rwlock_unlock( rw );
+}
+
+#endif /* HAVE_PTHREAD_RDLOCK_DESTROY */
+#endif /* LDAP_THREAD_HAVE_RDWR */
+#endif /* HAVE_PTHREADS */
+
diff --git a/libraries/libldbm/ldbm.c b/libraries/libldbm/ldbm.c
index 6d15e4629e8a3f6881c4893eedc2c9eee6f79b57..112a54a9b43cfa9a4a2e7ca88dcc8f773f456490 100644
--- a/libraries/libldbm/ldbm.c
+++ b/libraries/libldbm/ldbm.c
@@ -1,52 +1,37 @@
 /* ldbm.c - ldap dbm compatibility routines */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
 
-#include <stdio.h>
-#include "ldbm.h"
-
-#ifdef LDBM_USE_GDBM
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-/*****************************************************************
- *                                                               *
- * use gdbm							 *
- *                                                               *
- *****************************************************************/
+/* Patched for Berkeley DB version 2.0; /KSp; 98/02/23
+ *   - DB version 2.6.4b   ; 1998/12/28, /KSp
+ *   - DB_DBT_MALLOC       ; 1998/03/22, /KSp
+ *   - basic implementation; 1998/02/23, /KSp
+ */
 
-LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
-{
-	LDBM		db;
-	struct stat	st;
+#include "portable.h"
 
-	if ( (db =  gdbm_open( name, 0, rw | GDBM_FAST, mode, 0 )) == NULL ) {
-		return( NULL );
-	}
-	if ( dbcachesize > 0 && stat( name, &st ) == 0 ) {
-		dbcachesize = (dbcachesize / st.st_blksize);
-		gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
-	}
+#ifdef SLAPD_LDBM
 
-	return( db );
-}
+#include <stdio.h>
 
-void
-ldbm_close( LDBM ldbm )
-{
-	gdbm_close( ldbm );
-}
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/errno.h>
 
-void
-ldbm_sync( LDBM ldbm )
-{
-	gdbm_sync( ldbm );
-}
+#include "ldbm.h"
+#include "ldap_pvt_thread.h"
 
 void
 ldbm_datum_free( LDBM ldbm, Datum data )
 {
-	free( data.dptr );
+	if ( data.dptr ) {
+		free( data.dptr );
+		memset( &data, '\0', sizeof( Datum ));
+		data.dptr = NULL;
+	}
 }
 
 Datum
@@ -54,6 +39,8 @@ ldbm_datum_dup( LDBM ldbm, Datum data )
 {
 	Datum	dup;
 
+	ldbm_datum_init( dup );
+
 	if ( data.dsize == 0 ) {
 		dup.dsize = 0;
 		dup.dptr = NULL;
@@ -61,58 +48,250 @@ ldbm_datum_dup( LDBM ldbm, Datum data )
 		return( dup );
 	}
 	dup.dsize = data.dsize;
-	if ( dup.dptr = (char *) malloc( data.dsize ) )
-		memcpy( dup.dptr, data.dptr, data.dsize );
+
+	if ( (dup.dptr = (char *) malloc( data.dsize )) != NULL ) {
+		AC_MEMCPY( dup.dptr, data.dptr, data.dsize );
+	}
 
 	return( dup );
 }
 
-Datum
-ldbm_fetch( LDBM ldbm, Datum key )
+static int ldbm_initialized = 0;
+
+#if defined( USE_BERKELEY_CDB )
+	/* not currently supported */
+#define LDBM_RWLOCK_INIT  ((void) 0)
+#define LDBM_RWLOCK_DESTROY ((void) 0)
+#define LDBM_WLOCK		((void) 0)
+#define LDBM_WUNLOCK	((void) 0)
+#define LDBM_RLOCK		((void) 0)
+#define LDBM_RUNLOCK	((void) 0)
+
+#elif defined( HAVE_BERKELEY_DB_THREAD )
+static ldap_pvt_thread_rdwr_t ldbm_big_rdwr;
+#define LDBM_RWLOCK_INIT (ldap_pvt_thread_rdwr_init( &ldbm_big_rdwr ))
+#define LDBM_RWLOCK_DESTROY (ldap_pvt_thread_rdwr_destroy( &ldbm_big_rdwr ))
+#define LDBM_WLOCK		(ldap_pvt_thread_rdwr_wlock(&ldbm_big_rdwr))
+#define LDBM_WUNLOCK	(ldap_pvt_thread_rdwr_wunlock(&ldbm_big_rdwr))
+#define LDBM_RLOCK		(ldap_pvt_thread_rdwr_rlock(&ldbm_big_rdwr))
+#define LDBM_RUNLOCK	(ldap_pvt_thread_rdwr_runlock(&ldbm_big_rdwr))
+
+#else
+static ldap_pvt_thread_mutex_t ldbm_big_mutex;
+#define LDBM_RWLOCK_INIT (ldap_pvt_thread_mutex_init( &ldbm_big_mutex ))
+#define LDBM_RWLOCK_DESTROY (ldap_pvt_thread_mutex_destroy( &ldbm_big_mutex ))
+#define LDBM_WLOCK		(ldap_pvt_thread_mutex_lock(&ldbm_big_mutex))
+#define LDBM_WUNLOCK	(ldap_pvt_thread_mutex_unlock(&ldbm_big_mutex))
+#define LDBM_RLOCK		LDBM_WLOCK
+#define LDBM_RUNLOCK	LDBM_WUNLOCK
+#endif
+
+#if !defined( HAVE_BERKELEY_DB ) || (DB_VERSION_MAJOR < 3)
+	/*  a dbEnv for BERKELEYv2  */
+DB_ENV *ldbm_Env = NULL;	/* real or fake, depending on db and version */
+#endif
+
+/*******************************************************************
+ *                                                                 *
+ *  Create some special functions to initialize Berkeley DB for    *
+ *  versions greater than 2.                                       *
+ *                                                                 *
+ *******************************************************************/
+#if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 2)
+
+void *
+ldbm_malloc( size_t size )
 {
-	return( gdbm_fetch( ldbm, key ) );
+	/* likely should use ber_mem* routines */
+	return( calloc( 1, size ) );
 }
 
-int
-ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+#ifdef LDAP_SYSLOG
+#include <ac/syslog.h>
+#endif
+
+static void
+ldbm_db_errcall( const char *prefix, char *message )
 {
-	int	rc;
+#ifdef LDAP_SYSLOG
+	syslog( LOG_INFO, "ldbm: %s %s", prefix, message );
+#endif
+}
 
-	rc = gdbm_store( ldbm, key, data, flags & ~LDBM_SYNC );
-	if ( flags & LDBM_SYNC )
-		gdbm_sync( ldbm );
-	return( rc );
+int ldbm_initialize( const char* home )
+{
+#if DB_VERSION_MAJOR < 3
+	int	err;
+	u_int32_t	envFlags;
+#endif
+
+	if(ldbm_initialized++) return 1;
+
+	{
+		char *version;
+		int major, minor, patch;
+		version = db_version( &major, &minor, &patch );
+
+		if( major != DB_VERSION_MAJOR ||
+			minor < DB_VERSION_MINOR )
+		{
+#ifdef LDAP_SYSLOG
+			syslog( LOG_INFO,
+				"ldbm_initialize(): version mismatch\nexpected: %s\ngot: %s\n",
+				DB_VERSION_STRING, version );
+#endif
+			return 1;
+		}
+	}
+
+#if DB_VERSION_MAJOR < 3
+	ldbm_Env = calloc( 1, sizeof( DB_ENV ));
+
+	if( ldbm_Env == NULL ) return 1;
+
+	ldbm_Env->db_errcall	= ldbm_db_errcall;
+	ldbm_Env->db_errpfx		= "==>";
+
+	envFlags = DB_CREATE | DB_USE_ENVIRON;
+
+	/* add optional flags */
+#ifdef DB_PRIVATE
+	envFlags |= DB_PRIVATE;
+#endif
+#ifdef HAVE_BERKELEY_DB_THREAD
+	envFlags |= DB_THREAD; 
+#endif
+
+	err = db_appinit( home, NULL, ldbm_Env, envFlags );
+
+	if ( err ) {
+#ifdef LDAP_SYSLOG
+		syslog( LOG_INFO, "ldbm_initialize(): "
+			"FATAL error (%d) in db_appinit()\n", err );
+#endif
+	 	return( 1 );
+	}
+#endif
+
+	LDBM_RWLOCK_INIT;
+
+	return 0;
 }
 
-int
-ldbm_delete( LDBM ldbm, Datum key )
+int ldbm_shutdown( void )
 {
-	int	rc;
+	if( !ldbm_initialized ) return 1;
 
-	rc = gdbm_delete( ldbm, key );
-	gdbm_sync( ldbm );
-	return( rc );
+#if DB_VERSION_MAJOR < 3
+	db_appexit( ldbm_Env );
+#endif
+
+	LDBM_RWLOCK_DESTROY;
+	return 0;
 }
 
-Datum
-ldbm_firstkey( LDBM ldbm )
+#else  /* some DB other than Berkeley V2 or greater */
+
+int ldbm_initialize( const char * home )
 {
-	return( gdbm_firstkey( ldbm ) );
+	if(ldbm_initialized++) return 1;
+
+	LDBM_RWLOCK_INIT;
+
+	return 0;
 }
 
-Datum
-ldbm_nextkey( LDBM ldbm, Datum key )
+int ldbm_shutdown( void )
 {
-	return( gdbm_nextkey( ldbm, key ) );
+	if( !ldbm_initialized ) return 1;
+
+	LDBM_RWLOCK_DESTROY;
+
+	return 0;
 }
 
-int
-ldbm_errno( LDBM ldbm )
+#endif /* HAVE_BERKELEY_DB */
+
+#if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 3)
+
+DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
 {
-	return( (int) gdbm_errno );
+	DB_ENV *env = NULL;    
+	int     err;
+	u_int32_t	envFlags;
+
+	err = db_env_create( &env, 0 );
+
+	if ( err ) {
+#ifdef LDAP_SYSLOG
+		syslog( LOG_INFO, "ldbm_initialize_env(): "
+			"FATAL error in db_env_create() : %s (%d)\n",
+			db_strerror( err ), err );
+#endif
+		return NULL;
+	}
+
+#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR >= 3
+	/* This interface appeared in 3.3 */
+	env->set_alloc( env, ldbm_malloc, NULL, NULL );
+#endif
+
+	env->set_errcall( env, ldbm_db_errcall );
+	env->set_errpfx( env, "==>" );
+	if (dbcachesize) {
+		env->set_cachesize( env, 0, dbcachesize, 0 );
+	}
+
+	envFlags = DB_CREATE | DB_INIT_MPOOL | DB_USE_ENVIRON;
+#ifdef DB_PRIVATE
+	envFlags |= DB_PRIVATE;
+#endif
+#ifdef DB_MPOOL_PRIVATE
+	envFlags |= DB_MPOOL_PRIVATE;
+#endif
+#ifdef HAVE_BERKELEY_DB_THREAD
+	envFlags |= DB_THREAD;
+#endif
+
+#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 0
+	err = env->open( env, home, envFlags, 0 );
+#else
+	/* 3.0.x requires an extra argument */
+	err = env->open( env, home, NULL, envFlags, 0 );
+#endif
+
+	if ( err != 0 ) {
+#ifdef LDAP_SYSLOG
+		syslog(	LOG_INFO, "ldbm_initialize_env(): "
+			"FATAL error in dbEnv->open() : %s (%d)\n",
+			db_strerror( err ), err );
+#endif
+		env->close( env, 0 );
+		return NULL;
+	}
+
+	*envdirok = 1;
+	return env;
+}
+
+void ldbm_shutdown_env(DB_ENV *env)
+{
+	env->close( env, 0 );
 }
 
 #else
+
+DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
+{
+	return ldbm_Env;
+}
+
+void ldbm_shutdown_env(DB_ENV *env)
+{
+}
+
+#endif
+
 #if defined( LDBM_USE_DBHASH ) || defined( LDBM_USE_DBBTREE )
 
 /*****************************************************************
@@ -122,9 +301,78 @@ ldbm_errno( LDBM ldbm )
  *****************************************************************/
 
 LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
 {
-	LDBM		ret;
+	LDBM		ret = NULL;
+#ifdef HAVE_EBCDIC
+	char n2[2048];
+#endif
+
+#if DB_VERSION_MAJOR >= 3
+	int err;
+
+	LDBM_WLOCK;
+
+	err = db_create( &ret, env, 0 );
+	if ( err != 0 ) {
+		(void)ret->close(ret, 0);
+		LDBM_WUNLOCK;
+
+		return NULL;
+	}
+
+#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3
+	ret->set_malloc( ret, ldbm_malloc );
+#endif
+
+	ret->set_pagesize( ret, DEFAULT_DB_PAGE_SIZE );
+
+	/* likely should use ber_mem* routines */
+
+#ifdef HAVE_EBCDIC
+	strncpy(n2, name, sizeof(n2)-1);
+	n2[sizeof(n2)-1] = '\0';
+	__atoe(n2);
+	name = n2;
+#endif
+	err = ret->open( ret, name, NULL, DB_TYPE, rw, mode);
+
+	if ( err != 0 ) {
+		int tmp = errno;
+		(void)ret->close(ret, 0);
+		errno = tmp;
+
+		LDBM_WUNLOCK;
+		return NULL;
+	}
+
+	LDBM_WUNLOCK;
+ 
+#elif DB_VERSION_MAJOR >= 2
+	DB_INFO dbinfo;
+
+	memset( &dbinfo, '\0', sizeof( dbinfo ));
+
+#if	DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 4
+	/*
+	 * BerkeleyDB 2.4 do not allow db_cachesize
+	 * to be specified if an DB_ENV is.
+	 */
+#else
+	/* set db_cachesize of MPOOL is NOT being used. */
+	if (( ldbm_Env == NULL ) || ( ldbm_Env->mp_info == NULL )) {
+		dbinfo.db_cachesize = dbcachesize;
+	}
+#endif
+
+	dbinfo.db_pagesize	= DEFAULT_DB_PAGE_SIZE;
+	dbinfo.db_malloc	= ldbm_malloc;
+
+	LDBM_WLOCK;
+	(void) db_open( name, DB_TYPE, rw, mode, ldbm_Env, &dbinfo, &ret );
+	LDBM_WUNLOCK;
+
+#else
 	void		*info;
 	BTREEINFO	binfo;
 	HASHINFO	hinfo;
@@ -140,44 +388,33 @@ ldbm_open( char *name, int rw, int mode, int dbcachesize )
 	} else {
 		info = NULL;
 	}
+
+	LDBM_WLOCK;
 	ret = dbopen( name, rw, mode, DB_TYPE, info );
-	return( ret );
+	LDBM_WUNLOCK;
+#endif
+
+	return ret;
 }
 
 void
 ldbm_close( LDBM ldbm )
 {
-	(*ldbm->close)( ldbm );
+	LDBM_WLOCK;
+#if DB_VERSION_MAJOR >= 2
+	ldbm->close( ldbm, 0 );
+#else
+	ldbm->close( ldbm );
+#endif
+	LDBM_WUNLOCK;
 }
 
 void
 ldbm_sync( LDBM ldbm )
 {
+	LDBM_WLOCK;
 	(*ldbm->sync)( ldbm, 0 );
-}
-
-void
-ldbm_datum_free( LDBM ldbm, Datum data )
-{
-	free( data.dptr );
-}
-
-Datum
-ldbm_datum_dup( LDBM ldbm, Datum data )
-{
-	Datum	dup;
-
-	if ( data.dsize == 0 ) {
-		dup.dsize = 0;
-		dup.dptr = NULL;
-
-		return( dup );
-	}
-	dup.dsize = data.dsize;
-	if ( dup.dptr = (char *) malloc( data.dsize ) )
-		memcpy( dup.dptr, data.dptr, data.dsize );
-
-	return( dup );
+	LDBM_WUNLOCK;
 }
 
 Datum
@@ -186,12 +423,30 @@ ldbm_fetch( LDBM ldbm, Datum key )
 	Datum	data;
 	int	rc;
 
-	if ( (rc = (*ldbm->get)( ldbm, &key, &data, 0 )) == 0 ) {
+	LDBM_RLOCK;
+
+#if DB_VERSION_MAJOR >= 2
+	ldbm_datum_init( data );
+
+	data.flags = DB_DBT_MALLOC;
+
+	if ( (rc = ldbm->get( ldbm, NULL, &key, &data, 0 )) != 0 ) {
+		ldbm_datum_free( ldbm, data );
+		data.dptr = NULL;
+		data.dsize = 0;
+	}
+#else
+	if ( (rc = ldbm->get( ldbm, &key, &data, 0 )) == 0 ) {
+		/* Berkeley DB 1.85 don't malloc the data for us */
+		/* duplicate it for to ensure reentrancy */
 		data = ldbm_datum_dup( ldbm, data );
 	} else {
 		data.dptr = NULL;
 		data.dsize = 0;
 	}
+#endif
+
+	LDBM_RUNLOCK;
 
 	return( data );
 }
@@ -201,9 +456,20 @@ ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
 {
 	int	rc;
 
-	rc = (*ldbm->put)( ldbm, &key, &data, flags & ~LDBM_SYNC );
+	LDBM_WLOCK;
+
+#if DB_VERSION_MAJOR >= 2
+	rc = ldbm->put( ldbm, NULL, &key, &data, flags & ~LDBM_SYNC );
+	rc = (-1) * rc;
+#else
+	rc = ldbm->put( ldbm, &key, &data, flags & ~LDBM_SYNC );
+#endif
+
 	if ( flags & LDBM_SYNC )
-		(*ldbm->sync)( ldbm, 0 );
+		ldbm->sync( ldbm, 0 );
+
+	LDBM_WUNLOCK;
+
 	return( rc );
 }
 
@@ -212,38 +478,107 @@ ldbm_delete( LDBM ldbm, Datum key )
 {
 	int	rc;
 
-	rc = (*ldbm->del)( ldbm, &key, 0 );
-	(*ldbm->sync)( ldbm, 0 );
+	LDBM_WLOCK;
+
+#if DB_VERSION_MAJOR >= 2
+	rc = ldbm->del( ldbm, NULL, &key, 0 );
+	rc = (-1) * rc;
+#else
+	rc = ldbm->del( ldbm, &key, 0 );
+#endif
+	ldbm->sync( ldbm, 0 );
+
+	LDBM_WUNLOCK;
+
 	return( rc );
 }
 
 Datum
-ldbm_firstkey( LDBM ldbm )
+ldbm_firstkey( LDBM ldbm, LDBMCursor **dbch )
 {
 	Datum	key, data;
 	int	rc;
 
-	if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_FIRST )) == 0 ) {
+#if DB_VERSION_MAJOR >= 2
+	LDBMCursor  *dbci;
+
+	ldbm_datum_init( key );
+	ldbm_datum_init( data );
+
+	key.flags = data.flags = DB_DBT_MALLOC;
+
+	LDBM_RLOCK;
+
+	/* acquire a cursor for the DB */
+# if DB_VERSION_MAJOR >= 3 || (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 5)
+	rc = ldbm->cursor( ldbm, NULL, &dbci, 0 );
+# else
+	rc = ldbm->cursor( ldbm, NULL, &dbci );
+# endif
+
+	if( rc ) {
+		key.dptr = NULL;
+	} else {
+		*dbch = dbci;
+		if ( dbci->c_get( dbci, &key, &data, DB_NEXT ) == 0 ) {
+			ldbm_datum_free( ldbm, data );
+		} else {
+			key.dptr = NULL;
+			key.dsize = 0;
+		}
+	}
+
+	LDBM_RUNLOCK;
+
+#else
+	LDBM_RLOCK;
+
+	rc = ldbm->seq( ldbm, &key, &data, R_FIRST );
+
+	if ( rc == 0 ) {
 		key = ldbm_datum_dup( ldbm, key );
 	} else {
 		key.dptr = NULL;
 		key.dsize = 0;
 	}
+
+	LDBM_RUNLOCK;
+#endif
+
 	return( key );
 }
 
 Datum
-ldbm_nextkey( LDBM ldbm, Datum key )
+ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
 {
-	Datum	data;
 	int	rc;
+	Datum	data;
+
+	LDBM_RLOCK;
+
+#if DB_VERSION_MAJOR >= 2
+	ldbm_datum_init( data );
+
+	ldbm_datum_free( ldbm, key );
+	key.flags = data.flags = DB_DBT_MALLOC;
 
-	if ( (rc = (*ldbm->seq)( ldbm, &key, &data, R_NEXT )) == 0 ) {
+	rc = dbcp->c_get( dbcp, &key, &data, DB_NEXT );
+	if ( rc == 0 ) {
+		ldbm_datum_free( ldbm, data );
+	} else
+#else
+	rc = ldbm->seq( ldbm, &key, &data, R_NEXT );
+
+	if ( rc == 0 ) {
 		key = ldbm_datum_dup( ldbm, key );
-	} else {
+	} else
+#endif
+	{
 		key.dptr = NULL;
 		key.dsize = 0;
 	}
+
+	LDBM_RUNLOCK;
 	return( key );
 }
 
@@ -253,96 +588,576 @@ ldbm_errno( LDBM ldbm )
 	return( errno );
 }
 
-#else
+/******************************************************************
+ *                                                                *
+ *         END Berkeley section                                   *
+ *                                                                *
+ ******************************************************************/
 
-#ifdef LDBM_USE_NDBM
+#elif defined( HAVE_GDBM )
+
+#ifdef HAVE_ST_BLKSIZE
+#include <sys/stat.h>
+#endif
 
 /*****************************************************************
  *                                                               *
- * if no gdbm, fall back to using ndbm, the standard unix thing  *
+ * use gdbm                                                      *
  *                                                               *
  *****************************************************************/
 
-/* ARGSUSED */
 LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
 {
-	return( dbm_open( name, rw, mode ) );
+	LDBM		db;
+#ifdef HAVE_ST_BLKSIZE
+		struct stat	st;
+#endif
+#ifdef HAVE_EBCDIC
+	char n2[2048];
+
+	strncpy(n2, name, sizeof(n2)-1);
+	n2[sizeof(n2)-1] = '\0';
+	__atoe(n2);
+	name = n2;
+#endif
+
+	LDBM_WLOCK;
+
+	if ( (db = gdbm_open( name, 0, rw | GDBM_FAST, mode, 0 )) == NULL ) {
+		LDBM_WUNLOCK;
+		return( NULL );
+	}
+
+#ifdef HAVE_ST_BLKSIZE
+	if ( dbcachesize > 0 && stat( name, &st ) == 0 ) {
+		dbcachesize /= st.st_blksize;
+		if( dbcachesize == 0 ) dbcachesize = 1;
+		gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
+	}
+#else
+	if ( dbcachesize > 0 ) {
+		dbcachesize /= 4096;
+		if( dbcachesize == 0 ) dbcachesize = 1;
+		gdbm_setopt( db, GDBM_CACHESIZE, &dbcachesize, sizeof(int) );
+	}
+#endif
+
+	LDBM_WUNLOCK;
+
+	return( db );
 }
 
 void
 ldbm_close( LDBM ldbm )
 {
-	dbm_close( ldbm );
+	LDBM_WLOCK;
+	gdbm_close( ldbm );
+	LDBM_WUNLOCK;
 }
 
-/* ARGSUSED */
 void
 ldbm_sync( LDBM ldbm )
 {
-	return;
+	LDBM_WLOCK;
+	gdbm_sync( ldbm );
+	LDBM_WUNLOCK;
+}
+
+Datum
+ldbm_fetch( LDBM ldbm, Datum key )
+{
+	Datum d;
+
+	LDBM_RLOCK;
+	d = gdbm_fetch( ldbm, key );
+	LDBM_RUNLOCK;
+
+	return d;
+}
+
+int
+ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+	int	rc;
+
+	LDBM_WLOCK;
+	rc = gdbm_store( ldbm, key, data, flags & ~LDBM_SYNC );
+	if ( flags & LDBM_SYNC )
+		gdbm_sync( ldbm );
+	LDBM_WUNLOCK;
+
+	return( rc );
+}
+
+int
+ldbm_delete( LDBM ldbm, Datum key )
+{
+	int	rc;
+
+	LDBM_WLOCK;
+	rc = gdbm_delete( ldbm, key );
+	gdbm_sync( ldbm );
+	LDBM_WUNLOCK;
+
+	return( rc );
+}
+
+Datum
+ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
+{
+	Datum d;
+
+	LDBM_RLOCK;
+	d = gdbm_firstkey( ldbm );
+	LDBM_RUNLOCK;
+
+	if ( d.dptr != NULL ) {
+		*dbcp = (Datum *) malloc( sizeof( Datum ) );
+		**dbcp = ldbm_datum_dup( ldbm, d );
+	}
+
+	return d;
+}
+
+Datum
+ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
+{
+	Datum d;
+
+	LDBM_RLOCK;
+	d = gdbm_nextkey( ldbm, *dbcp );
+	LDBM_RUNLOCK;
+
+	ldbm_datum_free( ldbm, *dbcp );
+
+	if ( d.dptr != NULL ) {
+		*dbcp = ldbm_datum_dup( ldbm, d );
+	} else {
+		free( dbcp );
+	}
+
+	return d;
+}
+
+int
+ldbm_errno( LDBM ldbm )
+{
+	int err;
+
+	LDBM_WLOCK;
+	err = gdbm_errno;
+	LDBM_WUNLOCK;
+
+	return( err );
+}
+
+#elif HAVE_MDBM
+
+/* MMAPED DBM HASHING DATABASE */
+
+#include <ac/string.h>
+
+/* #define MDBM_DEBUG */
+
+#ifdef MDBM_DEBUG
+#include <stdio.h>
+#endif
+
+#define NO_NULL_KEY
+/* #define MDBM_CHAIN */
+
+#ifdef MDBM_CHAIN
+
+/* Use chaining */
+
+#define mdbm_store	mdbm_chain_store
+#define mdbm_fetch	mdbm_chain_fetch
+#define mdbm_delete	mdbm_chain_delete
+#define mdbm_first	mdbm_chain_first
+#define mdbm_next	mdbm_chain_next
+
+#endif
+
+#define MDBM_PG_SZ	(4*1024)
+
+/*****************************************************************
+ *                                                               *
+ * use mdbm                                                      *
+ *                                                               *
+ *****************************************************************/
+
+LDBM
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
+{
+	LDBM		db;
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout,
+		 "==>(mdbm)ldbm_open(name=%s,rw=%x,mode=%x,cachesize=%d)\n",
+		 name ? name : "NULL", rw, mode, dbcachesize );
+	fflush( stdout );
+#endif
+
+	LDBM_WLOCK;	/* We need locking here, this is the only non-thread
+		* safe function we have.  */
+
+	if ( (db =  mdbm_open( name, rw, mode, MDBM_PG_SZ )) == NULL ) {
+		LDBM_WUNLOCK;
+#ifdef MDBM_DEBUG
+		fprintf( stdout, "<==(mdbm)ldbm_open(db=NULL)\n" );
+		fflush( stdout );
+#endif
+		return( NULL );
+	}
+
+#ifdef MDBM_CHAIN
+	(void)mdbm_set_chain(db);
+#endif
+
+	LDBM_WUNLOCK;
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout, "<==(mdbm)ldbm_open(db=%p)\n", db );
+	fflush( stdout );
+#endif
+
+	return( db );
 }
 
 void
-ldbm_datum_free( LDBM ldbm, Datum data )
+ldbm_close( LDBM ldbm )
 {
-	return;
+	/* Open and close are not reentrant so we need to use locks here */
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout,
+		 "==>(mdbm)ldbm_close(db=%p)\n", ldbm );
+	fflush( stdout );
+#endif
+
+	LDBM_WLOCK;
+	mdbm_close( ldbm );
+	LDBM_WUNLOCK;
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout, "<==(mdbm)ldbm_close()\n" );
+	fflush( stdout );
+#endif
 }
 
+void
+ldbm_sync( LDBM ldbm )
+{
+	/* XXX: Not sure if this is re-entrant need to check code, if so
+	 * you can leave LOCKS out.
+	 */
+
+	LDBM_WLOCK;
+	mdbm_sync( ldbm );
+	LDBM_WUNLOCK;
+}
+
+#define MAX_MDBM_RETRY	5
+
 Datum
-ldbm_datum_dup( LDBM ldbm, Datum data )
+ldbm_fetch( LDBM ldbm, Datum key )
 {
-	Datum	dup;
+	Datum	d;
+	kvpair	k;
+	int	retry = 0;
 
-	if ( data.dsize == 0 ) {
-		dup.dsize = 0;
-		dup.dptr = NULL;
+	/* This hack is needed because MDBM does not take keys
+	 * which begin with NULL when working in the chaining
+	 * mode.
+	 */
 
-		return( dup );
+#ifdef NO_NULL_KEY
+	k.key.dsize = key.dsize + 1;			
+	k.key.dptr = malloc(k.key.dsize);
+	*(k.key.dptr) = 'l';
+	AC_MEMCPY( (void *)(k.key.dptr + 1), key.dptr, key.dsize );	
+#else
+	k.key = key;
+#endif	
+
+	k.val.dptr = NULL;
+	k.val.dsize = 0;
+
+	/* LDBM_RLOCK; */
+	do {
+		d = mdbm_fetch( ldbm, k );
+
+		if ( d.dsize > 0 ) {
+			if ( k.val.dptr != NULL ) {
+				free( k.val.dptr );
+			}
+
+			if ( (k.val.dptr = malloc( d.dsize )) != NULL ) {
+				k.val.dsize = d.dsize;
+				d = mdbm_fetch( ldbm, k );
+
+			} else { 
+				d.dsize = 0;
+				break;
+			}
+		}/* if ( d.dsize > 0 ) */
+	} while ((d.dsize > k.val.dsize) && (++retry < MAX_MDBM_RETRY));
+	/* LDBM_RUNLOCK; */
+
+#ifdef NO_NULL_KEY
+	free(k.key.dptr);
+#endif
+
+	return d;
+}
+
+int
+ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+	int	rc;
+	Datum	int_key;	/* Internal key */
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout,
+		 "==>(mdbm)ldbm_store(db=%p, key(dptr=%p,sz=%d), data(dptr=%p,sz=%d), flags=%x)\n",
+		 ldbm, key.dptr, key.dsize, data.dptr, data.dsize, flags );
+	fflush( stdout );
+#endif
+
+	/* LDBM_WLOCK; */
+
+#ifdef NO_NULL_KEY
+	int_key.dsize = key.dsize + 1;
+	int_key.dptr = malloc( int_key.dsize );
+	*(int_key.dptr) = 'l';	/* Must not be NULL !*/
+	AC_MEMCPY( (void *)(int_key.dptr + 1), key.dptr, key.dsize );
+#else
+	int_key = key;
+#endif
+
+	rc = mdbm_store( ldbm, int_key, data, flags );
+	if ( flags & LDBM_SYNC ) {
+		mdbm_sync( ldbm );
 	}
-	dup.dsize = data.dsize;
-	if ( dup.dptr = (char *) malloc( data.dsize ) )
-		memcpy( dup.dptr, data.dptr, data.dsize );
 
-	return( dup );
+	/* LDBM_WUNLOCK; */
+
+#ifdef MDBM_DEBUG
+	fprintf( stdout, "<==(mdbm)ldbm_store(rc=%d)\n", rc );
+	fflush( stdout );
+#endif
+
+#ifdef NO_NULL_KEY
+	free(int_key.dptr);
+#endif
+
+	return( rc );
+}
+
+int
+ldbm_delete( LDBM ldbm, Datum key )
+{
+	int	rc;
+	Datum	int_key;
+
+	/* LDBM_WLOCK; */
+
+#ifdef NO_NULL_KEY
+	int_key.dsize = key.dsize + 1;
+	int_key.dptr = malloc(int_key.dsize);
+	*(int_key.dptr) = 'l';
+	AC_MEMCPY( (void *)(int_key.dptr + 1), key.dptr, key.dsize );	
+#else
+	int_key = key;
+#endif
+	
+	rc = mdbm_delete( ldbm, int_key );
+
+	/* LDBM_WUNLOCK; */
+#ifdef NO_NULL_KEY
+	free(int_key.dptr);
+#endif
+
+	return( rc );
+}
+
+static Datum
+ldbm_get_next( LDBM ldbm, kvpair (*fptr)(MDBM *, kvpair) ) 
+{
+	kvpair	out;
+	kvpair	in;
+	Datum	ret;
+	size_t	sz = MDBM_PAGE_SIZE(ldbm);
+#ifdef NO_NULL_KEY
+	int	delta = 1;
+#else
+	int	delta = 0;
+#endif
+
+	/* LDBM_RLOCK; */
+
+	in.key.dsize = sz;	/* Assume first key in one pg */
+	in.key.dptr = malloc(sz);
+	
+	in.val.dptr = NULL;	/* Don't need data just key */ 
+	in.val.dsize = 0;
+
+	ret.dptr = NULL;
+	ret.dsize = NULL;
+
+	out = fptr( ldbm, in );
+
+	if (out.key.dsize > 0) {
+		ret.dsize = out.key.dsize - delta;
+
+		if ((ret.dptr = (char *)malloc(ret.dsize)) == NULL) { 
+			ret.dsize = 0;
+			ret.dptr = NULL;
+
+		} else {
+			AC_MEMCPY(ret.dptr, (void *)(out.key.dptr + delta),
+				ret.dsize );
+	    }
+	}
+
+	/* LDBM_RUNLOCK; */
+	
+	free(in.key.dptr);
+	return ret;
+}
+
+Datum
+ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
+{
+	return ldbm_get_next( ldbm, mdbm_first );
+}
+
+Datum
+ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
+{
+	/* XXX:
+	 * don't know if this will affect the LDAP server operation 
+	 * but mdbm cannot take and input key.
+	 */
+
+	return ldbm_get_next( ldbm, mdbm_next );
+}
+
+int
+ldbm_errno( LDBM ldbm )
+{
+	/* XXX: best we can do with current  mdbm interface */
+	return( errno );
+}
+
+#elif defined( HAVE_NDBM )
+
+/*****************************************************************
+ *                                                               *
+ * if no gdbm or mdbm, fall back to using ndbm, the standard unix thing  *
+ *                                                               *
+ *****************************************************************/
+
+/* ARGSUSED */
+LDBM
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
+{
+	LDBM ldbm;
+
+	LDBM_WLOCK;
+	ldbm = dbm_open( name, rw, mode );
+	LDBM_WUNLOCK;
+
+	return( ldbm );
+}
+
+void
+ldbm_close( LDBM ldbm )
+{
+	LDBM_WLOCK;
+	dbm_close( ldbm );
+	LDBM_WUNLOCK;
+}
+
+/* ARGSUSED */
+void
+ldbm_sync( LDBM ldbm )
+{
+	return;
 }
 
 Datum
 ldbm_fetch( LDBM ldbm, Datum key )
 {
-	return( ldbm_datum_dup( ldbm, dbm_fetch( ldbm, key ) ) );
+	Datum d;
+
+	LDBM_RLOCK;
+	d = ldbm_datum_dup( ldbm, dbm_fetch( ldbm, key ) );
+	LDBM_RUNLOCK;
+
+	return d;
 }
 
 int
 ldbm_store( LDBM ldbm, Datum key, Datum data, int flags )
 {
-	return( dbm_store( ldbm, key, data, flags ) );
+	int rc;
+
+	LDBM_WLOCK;
+	rc = dbm_store( ldbm, key, data, flags );
+	LDBM_WUNLOCK;
+
+	return rc;
 }
 
 int
 ldbm_delete( LDBM ldbm, Datum key )
 {
-	return( dbm_delete( ldbm, key ) );
+	int rc;
+
+	LDBM_WLOCK;
+	rc = dbm_delete( ldbm, key );
+	LDBM_WUNLOCK;
+
+	return rc;
 }
 
 Datum
-ldbm_firstkey( LDBM ldbm )
+ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
 {
-	return( dbm_firstkey( ldbm ) );
+	Datum d;
+
+	LDBM_RLOCK;
+	d = dbm_firstkey( ldbm );
+	LDBM_RUNLOCK;
+
+	return d;
 }
 
 Datum
-ldbm_nextkey( LDBM ldbm, Datum key )
+ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
 {
-	return( dbm_nextkey( ldbm ) );
+	Datum d;
+
+	LDBM_RLOCK;
+	d = dbm_nextkey( ldbm );
+	LDBM_RUNLOCK;
+
+	return d;
 }
 
 int
 ldbm_errno( LDBM ldbm )
 {
-	return( dbm_error( ldbm ) );
+	int err;
+
+	LDBM_WLOCK;
+	err = dbm_error( ldbm );
+	LDBM_WUNLOCK;
+
+	return err;
 }
 
 #endif /* ndbm */
-#endif /* db */
-#endif /* gdbm */
+#endif /* ldbm */
diff --git a/libraries/liblunicode/Makefile.in b/libraries/liblunicode/Makefile.in
index 5316d023aeb252fdbc19b5eb0cae7476039d55d4..ef2e3614a0b31f3ac7d4e1b22059486e376f5791 100644
--- a/libraries/liblunicode/Makefile.in
+++ b/libraries/liblunicode/Makefile.in
@@ -14,6 +14,7 @@ SRCS	= ucstr.c
 OBJS	= ucdata.o ure.o urestubs.o ucstr.o
 
 XLIB = $(LIBRARY)
+XLIBS = $(LDAP_LIBLUTIL_A)
 PROGRAMS = ucgendat
 
 LDAP_INCDIR= ../../include       
diff --git a/libraries/liblunicode/ucdata/ucdata.c b/libraries/liblunicode/ucdata/ucdata.c
index beb4184f03f55a5339dab12854dda44596018b22..151e0ac1057f3c260aff7b1f42eac2a51a84bc25 100644
--- a/libraries/liblunicode/ucdata/ucdata.c
+++ b/libraries/liblunicode/ucdata/ucdata.c
@@ -30,6 +30,7 @@
 #include "ldap_config.h"
 
 #include <stdio.h>
+#include <ac/bytes.h>
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/unistd.h>
@@ -44,11 +45,11 @@
  **************************************************************************/
 
 typedef struct {
-    unsigned short bom;
-    unsigned short cnt;
+    ac_uint2 bom;
+    ac_uint2 cnt;
     union {
-        unsigned long bytes;
-        unsigned short len[2];
+        ac_uint4 bytes;
+        ac_uint2 len[2]; 
     } size;
 } _ucheader_t;
 
diff --git a/libraries/liblunicode/ucdata/ucgendat.c b/libraries/liblunicode/ucdata/ucgendat.c
index 2daee8a4c339656ccbde77a93be410a5e3f55262..11f32f9cb2b1173d21af17b9d48a17d7ee3a1a12 100644
--- a/libraries/liblunicode/ucdata/ucgendat.c
+++ b/libraries/liblunicode/ucdata/ucgendat.c
@@ -30,6 +30,7 @@
 #include "ldap_config.h"
 
 #include <stdio.h>
+#include <ac/bytes.h>
 #include <ac/stdlib.h>
 #include <ac/string.h>
 #include <ac/unistd.h>
@@ -804,8 +805,8 @@ read_cdata(FILE *in)
     char line[512], *s, *e;
 
     lineno = skip = 0;
-    while (!feof(in)) {
-		if( fscanf(in, "%[^\n]\n", line) != 1) break;
+    while (fgets(line, sizeof(line), in)) {
+	if( (s=strchr(line, '\n')) ) *s = '\0';
         lineno++;
 
         /*
@@ -1163,8 +1164,8 @@ read_compexdata(FILE *in)
 
     (void) memset((char *) compexs, 0, sizeof(unsigned long) << 11);
 
-    while (!feof(in)) {
-		if( fscanf(in, "%[^\n]\n", line) != 1) break;
+    while (fgets(line, sizeof(line), in)) {
+	if( (s=strchr(line, '\n')) ) *s = '\0';
         /*
          * Skip blank lines and lines that start with a '#'.
          */
@@ -1216,7 +1217,8 @@ static void
 write_cdata(char *opath)
 {
     FILE *out;
-    unsigned long i, idx, bytes, nprops;
+	ac_uint4 bytes;
+    unsigned long i, idx, nprops;
     unsigned short casecnt[2];
     char path[BUFSIZ];
 
@@ -1229,7 +1231,7 @@ write_cdata(char *opath)
     /*
      * Open the ctype.dat file.
      */
-    sprintf(path, "%s%sctype.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "ctype.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1268,7 +1270,7 @@ write_cdata(char *opath)
     /*
      * Write the header.
      */
-    fwrite((char *) hdr, sizeof(unsigned short), 2, out);
+    fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
 
     /*
      * Write the byte count.
@@ -1300,7 +1302,7 @@ write_cdata(char *opath)
     /*
      * Open the case.dat file.
      */
-    sprintf(path, "%s%scase.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "case.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1355,7 +1357,7 @@ write_cdata(char *opath)
     /*
      * Open the comp.dat file.
      */
-    sprintf(path, "%s%scomp.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "comp.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
 	return;
     
@@ -1393,7 +1395,7 @@ write_cdata(char *opath)
     /*
      * Open the decomp.dat file.
      */
-    sprintf(path, "%s%sdecomp.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "decomp.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1447,7 +1449,7 @@ write_cdata(char *opath)
     /*
      * Open the kdecomp.dat file.
      */
-    sprintf(path, "%s%skdecomp.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "kdecomp.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1507,7 +1509,7 @@ write_cdata(char *opath)
     /*
      * Open the cmbcl.dat file.
      */
-    sprintf(path, "%s%scmbcl.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "cmbcl.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1545,7 +1547,7 @@ write_cdata(char *opath)
     /*
      * Open the num.dat file.
      */
-    sprintf(path, "%s%snum.dat", opath, LDAP_DIRSEP);
+    snprintf(path, sizeof path, "%s" LDAP_DIRSEP "num.dat", opath);
     if ((out = fopen(path, "wb")) == 0)
       return;
 
@@ -1598,10 +1600,7 @@ main(int argc, char *argv[])
     FILE *in;
     char *prog, *opath;
 
-    if ((prog = strrchr(argv[0], *LDAP_DIRSEP)) != 0)
-      prog++;
-    else
-      prog = argv[0];
+    prog = lutil_progname( "ucgendat", argc, argv );
 
     opath = 0;
     in = stdin;
diff --git a/libraries/liblutil/Makefile.in b/libraries/liblutil/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..ba9f3ec5e7737c1e1e128a94a58b22914393aedc
--- /dev/null
+++ b/libraries/liblutil/Makefile.in
@@ -0,0 +1,36 @@
+# $OpenLDAP$
+## Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+## COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+##
+## Makefile for -llutil
+##
+
+LIBRARY	= liblutil.a
+
+NT_SRCS = ntservice.c
+NT_OBJS = ntservice.o slapdmsg.res
+
+UNIX_SRCS = detach.c
+UNIX_OBJS = detach.o
+
+SRCS	= base64.c csn.c entropy.c sasl.c signal.c hash.c \
+	md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \
+	@LIBSRCS@ $(@PLAT@_SRCS)
+
+OBJS	= base64.o csn.o entropy.o sasl.o signal.o hash.o \
+	md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \
+	@LIBOBJS@ $(@PLAT@_OBJS)
+
+LDAP_INCDIR= ../../include       
+LDAP_LIBDIR= ../../libraries
+
+# These rules are for a Mingw32 build, specifically.
+# It's ok for them to be here because the clean rule is harmless, and
+# slapdmsg.res won't get built unless it's declared in OBJS.
+
+slapdmsg.res: slapdmsg.rc slapdmsg.bin
+	windres $< -O coff -o $@
+
+clean-local:
+	$(RM) *.res
+
diff --git a/libraries/liblutil/getopt.c b/libraries/liblutil/getopt.c
new file mode 100644
index 0000000000000000000000000000000000000000..137944ab6f7d2552305e311af20fadaa53e6bd8a
--- /dev/null
+++ b/libraries/liblutil/getopt.c
@@ -0,0 +1,126 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/*
+	getopt.c
+
+	modified public-domain AT&T getopt(3)
+	modified by Kurt Zeilenga for inclusion into OpenLDAP
+*/
+
+#include "portable.h"
+
+#ifndef HAVE_GETOPT
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include "lutil.h"
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char * optarg;
+
+#ifdef HAVE_EBCDIC
+extern int _trans_argv;
+#endif
+
+static void ERR (char * const argv[], const char * s, char c)
+{
+#ifdef DF_TRACE_DEBUG
+printf("DF_TRACE_DEBUG: 	static void ERR () in getopt.c\n");
+#endif
+	if (opterr)
+	{
+		char *ptr, outbuf[4096];
+
+		ptr = lutil_strncopy(outbuf, argv[0], sizeof(outbuf) - 2);
+		ptr = lutil_strncopy(ptr, s, sizeof(outbuf)-2 -(ptr-outbuf));
+		*ptr++ = c;
+		*ptr++ = '\n';
+#ifdef HAVE_EBCDIC
+		__atoe_l(outbuf, ptr - outbuf);
+#endif
+		(void) write(STDERR_FILENO,outbuf,ptr - outbuf);
+	}
+}
+
+int getopt (int argc, char * const argv [], const char * opts)
+{
+	static int sp = 1, error = (int) '?';
+	static char sw = '-', eos = '\0', arg = ':';
+	register char c, * cp;
+
+#ifdef DF_TRACE_DEBUG
+printf("DF_TRACE_DEBUG: 	int getopt () in getopt.c\n");
+#endif
+
+#ifdef HAVE_EBCDIC
+	if (_trans_argv) {
+		int i;
+		for (i=0; i<argc; i++) __etoa(argv[i]);
+		_trans_argv = 0;
+	}
+#endif
+	if (sp == 1)
+	{
+		if (optind >= argc || argv[optind][0] != sw
+		|| argv[optind][1] == eos)
+			return EOF;
+		else if (strcmp(argv[optind],"--") == 0)
+		{
+			optind++;
+			return EOF;
+		}
+	}
+	c = argv[optind][sp];
+	optopt = (int) c;
+	if (c == arg || (cp = strchr(opts,c)) == NULL)
+	{
+		ERR(argv,": illegal option--",c);
+		if (argv[optind][++sp] == eos)
+		{
+			optind++;
+			sp = 1;
+		}
+		return error;
+	}
+	else if (*++cp == arg)
+	{
+		if (argv[optind][sp + 1] != eos)
+			optarg = &argv[optind++][sp + 1];
+		else if (++optind >= argc)
+		{
+			ERR(argv,": option requires an argument--",c);
+			sp = 1;
+			return error;
+		}
+		else
+			optarg = argv[optind++];
+		sp = 1;
+	}
+	else
+	{
+		if (argv[optind][++sp] == eos)
+		{
+			sp = 1;
+			optind++;
+		}
+		optarg = NULL;
+	}
+	return (int) c;
+}
+#endif /* HAVE_GETOPT */
diff --git a/libraries/liblutil/liblutil.dsp b/libraries/liblutil/liblutil.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..436a6981bf7aeef502b0301375bfec07d163a915
--- /dev/null
+++ b/libraries/liblutil/liblutil.dsp
@@ -0,0 +1,297 @@
+# Microsoft Developer Studio Project File - Name="liblutil" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=liblutil - Win32 Single Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "liblutil.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "liblutil.mak" CFG="liblutil - Win32 Single Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "liblutil - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblutil - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE "liblutil - Win32 Single Debug" (based on\
+ "Win32 (x86) Static Library")
+!MESSAGE "liblutil - Win32 Single Release" (based on\
+ "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+
+!IF  "$(CFG)" == "liblutil - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\Release"
+# PROP Intermediate_Dir "..\..\Release\liblutil"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\Release\olutil32.lib"
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\Debug"
+# PROP Intermediate_Dir "..\..\Debug\liblutil"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\Debug\olutil32.lib"
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Single Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "liblutil"
+# PROP BASE Intermediate_Dir "liblutil"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\SDebug"
+# PROP Intermediate_Dir "..\..\SDebug\liblutil"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\Debug\olutil32.lib"
+# ADD LIB32 /nologo /out:"..\..\SDebug\olutil32.lib"
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Single Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "libluti0"
+# PROP BASE Intermediate_Dir "libluti0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\SRelease"
+# PROP Intermediate_Dir "..\..\SRelease\liblutil"
+# PROP Target_Dir ""
+RSC=rc.exe
+# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo /out:"..\Release\olutil32.lib"
+# ADD LIB32 /nologo /out:"..\..\SRelease\olutil32.lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "liblutil - Win32 Release"
+# Name "liblutil - Win32 Debug"
+# Name "liblutil - Win32 Single Debug"
+# Name "liblutil - Win32 Single Release"
+# Begin Source File
+
+SOURCE=.\authpasswd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\ac\bytes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\csn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\entropy.c
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\include\getopt-compat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\getopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\hash.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\ldap_cdefs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\lockf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil_hash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil_ldap.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil_lockf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\lutil_sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ntservice.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\passwd.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\portable.h
+# End Source File
+# Begin Source File
+
+SOURCE="..\..\include\queue-compat.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\sasl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sha1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\slapdmsg.mc
+
+!IF  "$(CFG)" == "liblutil - Win32 Release"
+
+# Begin Custom Build - Building slapd message file
+IntDir=.\..\..\Release\liblutil
+InputPath=.\slapdmsg.mc
+
+"slapdmsg.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	mkdir $(IntDir) 
+	mc -v slapdmsg.mc -r $(IntDir) 
+	rc /v /r $(IntDir)\slapdmsg.rc 
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Debug"
+
+# Begin Custom Build - Building slapd message file
+IntDir=.\..\..\Debug\liblutil
+InputPath=.\slapdmsg.mc
+
+"slapdmsg.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	mkdir $(IntDir) 
+	mc -v slapdmsg.mc -r $(IntDir) 
+	rc /v /r $(IntDir)\slapdmsg.rc 
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Single Debug"
+
+# Begin Custom Build - Building slapd message file
+IntDir=.\..\..\SDebug\liblutil
+InputPath=.\slapdmsg.mc
+
+"slapdmsg.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	mkdir $(IntDir) 
+	mc -v slapdmsg.mc -r $(IntDir) 
+	rc /v /r $(IntDir)\slapdmsg.rc 
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "liblutil - Win32 Single Release"
+
+# Begin Custom Build - Building slapd message file
+IntDir=.\..\..\SRelease\liblutil
+InputPath=.\slapdmsg.mc
+
+"slapdmsg.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	mkdir $(IntDir) 
+	mc -v slapdmsg.mc -r $(IntDir) 
+	rc /v /r $(IntDir)\slapdmsg.rc 
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\sockpair.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\uuid.c
+# End Source File
+# End Target
+# End Project
diff --git a/libraries/liblutil/ntservice.c b/libraries/liblutil/ntservice.c
new file mode 100644
index 0000000000000000000000000000000000000000..9bd27b7065837dfaab261b7564f97324eb8cdaf2
--- /dev/null
+++ b/libraries/liblutil/ntservice.c
@@ -0,0 +1,513 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+/*
+ * NT Service manager utilities for OpenLDAP services
+ *	these should NOT be slapd specific, but are
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_NT_SERVICE_MANAGER
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+
+#include <stdio.h>
+
+#include <windows.h>
+#include <winsvc.h>
+
+#include <ldap.h>
+
+/*
+ * The whole debug implementation is a bit of a hack.
+ * We have to define this LDAP_SLAPD_V macro here since the slap.h
+ * header file isn't included (and really shouldn't be).
+ * TODO: re-implement debug functions so that the debug level can
+ * be passed around instead of having to count on the existence of
+ * ldap_debug, slap_debug, etc.
+ */
+#define ldap_debug slap_debug
+LDAP_SLAPD_V (int) slap_debug;
+
+#include "ldap_log.h"
+#include "ldap_pvt_thread.h"
+
+
+#include "ldap_defaults.h"
+
+#include "slapdmsg.h"
+
+#define SCM_NOTIFICATION_INTERVAL	5000
+#define THIRTY_SECONDS				(30 * 1000)
+
+int	  is_NT_Service = 1;	/* assume this is an NT service until determined that */
+							/* startup was from the command line */
+
+SERVICE_STATUS			SLAPDServiceStatus;
+SERVICE_STATUS_HANDLE	hSLAPDServiceStatus;
+
+ldap_pvt_thread_cond_t	started_event,		stopped_event;
+ldap_pvt_thread_t		start_status_tid,	stop_status_tid;
+
+void (*stopfunc)(int);
+
+static char *GetLastErrorString( void );
+
+int srv_install(LPCTSTR lpszServiceName, LPCTSTR lpszDisplayName,
+		LPCTSTR lpszBinaryPathName, BOOL auto_start)
+{
+	HKEY		hKey;
+	DWORD		dwValue, dwDisposition;
+	SC_HANDLE	schSCManager, schService;
+
+	fprintf( stderr, "The install path is %s.\n", lpszBinaryPathName );
+	if ((schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE ) ) != NULL )
+	{
+	 	if ((schService = CreateService( 
+							schSCManager, 
+							lpszServiceName, 
+							lpszDisplayName, 
+							SERVICE_ALL_ACCESS, 
+							SERVICE_WIN32_OWN_PROCESS, 
+							auto_start ? SERVICE_AUTO_START : SERVICE_DEMAND_START, 
+							SERVICE_ERROR_NORMAL, 
+							lpszBinaryPathName, 
+							NULL, NULL, NULL, NULL, NULL)) != NULL)
+		{
+			char regpath[132];
+			CloseServiceHandle(schService);
+			CloseServiceHandle(schSCManager);
+
+			snprintf( regpath, sizeof regpath,
+				"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
+				lpszServiceName );
+			/* Create the registry key for event logging to the Windows NT event log. */
+			if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE, 
+				regpath, 0, 
+				"REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, 
+				&dwDisposition) != ERROR_SUCCESS)
+			{
+				fprintf( stderr, "RegCreateKeyEx() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+				RegCloseKey(hKey);
+				return(0);
+			}
+			if ( RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, lpszBinaryPathName, strlen(lpszBinaryPathName) + 1) != ERROR_SUCCESS)
+			{
+				fprintf( stderr, "RegSetValueEx(EventMessageFile) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+				RegCloseKey(hKey);
+				return(0);
+			}
+
+			dwValue = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+			if ( RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(DWORD)) != ERROR_SUCCESS) 
+			{
+				fprintf( stderr, "RegCreateKeyEx(TypesSupported) failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+				RegCloseKey(hKey);
+				return(0);
+			}
+			RegCloseKey(hKey);
+			return(1);
+		}
+		else
+		{
+			fprintf( stderr, "CreateService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+			CloseServiceHandle(schSCManager);
+			return(0);
+		}
+	}
+	else
+		fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+	return(0);
+}
+
+
+int srv_remove(LPCTSTR lpszServiceName, LPCTSTR lpszBinaryPathName)
+{
+	SC_HANDLE schSCManager, schService;
+
+	fprintf( stderr, "The installed path is %s.\n", lpszBinaryPathName );
+	if ((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE)) != NULL ) 
+	{
+	 	if ((schService = OpenService(schSCManager, lpszServiceName, DELETE)) != NULL) 
+		{
+			if ( DeleteService(schService) == TRUE) 
+			{
+				CloseServiceHandle(schService);
+				CloseServiceHandle(schSCManager);
+				return(1);
+			} else {
+				fprintf( stderr, "DeleteService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+				fprintf( stderr, "The %s service has not been removed.\n", lpszBinaryPathName);
+				CloseServiceHandle(schService);
+				CloseServiceHandle(schSCManager);
+				return(0);
+			}
+		} else {
+			fprintf( stderr, "OpenService() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+			CloseServiceHandle(schSCManager);
+			return(0);
+		}
+	}
+	else
+		fprintf( stderr, "OpenSCManager() failed. GetLastError=%lu (%s)\n", GetLastError(), GetLastErrorString() );
+	return(0);
+}
+
+
+DWORD
+svc_installed (LPTSTR lpszServiceName, LPTSTR lpszBinaryPathName)
+{
+	char buf[256];
+	HKEY key;
+	DWORD rc;
+	DWORD type;
+	long len;
+
+	strcpy(buf, TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
+	strcat(buf, lpszServiceName);
+	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
+		return(-1);
+
+	rc = 0;
+	if (lpszBinaryPathName) {
+		len = sizeof(buf);
+		if (RegQueryValueEx(key, "ImagePath", NULL, &type, buf, &len) == ERROR_SUCCESS) {
+			if (strcmp(lpszBinaryPathName, buf))
+				rc = -1;
+		}
+	}
+	RegCloseKey(key);
+	return(rc);
+}
+
+
+DWORD
+svc_running (LPTSTR lpszServiceName)
+{
+	SC_HANDLE service;
+	SC_HANDLE scm;
+	DWORD rc;
+	SERVICE_STATUS ss;
+
+	if (!(scm = OpenSCManager(NULL, NULL, GENERIC_READ)))
+		return(GetLastError());
+
+	rc = 1;
+	service = OpenService(scm, lpszServiceName, SERVICE_QUERY_STATUS);
+	if (service) {
+		if (!QueryServiceStatus(service, &ss))
+			rc = GetLastError();
+		else if (ss.dwCurrentState != SERVICE_STOPPED)
+			rc = 0;
+		CloseServiceHandle(service);
+	}
+	CloseServiceHandle(scm);
+	return(rc);
+}
+
+
+static void *start_status_routine( void *ptr )
+{
+	DWORD	wait_result;
+	int		done = 0;
+
+	while ( !done )
+	{
+		wait_result = WaitForSingleObject( started_event, SCM_NOTIFICATION_INTERVAL );
+		switch ( wait_result )
+		{
+			case WAIT_ABANDONED:
+			case WAIT_OBJECT_0:
+				/* the object that we were waiting for has been destroyed (ABANDONED) or
+				 * signalled (TIMEOUT_0). We can assume that the startup process is
+				 * complete and tell the Service Control Manager that we are now runnng */
+				SLAPDServiceStatus.dwCurrentState	= SERVICE_RUNNING;
+				SLAPDServiceStatus.dwWin32ExitCode	= NO_ERROR;
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint		= 1000;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+				done = 1;
+				break;
+			case WAIT_TIMEOUT:
+				/* We've waited for the required time, so send an update to the Service Control 
+				 * Manager saying to wait again. */
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+				break;
+			case WAIT_FAILED:
+				/* theres been some problem with WaitForSingleObject so tell the Service
+				 * Control Manager to wait 30 seconds before deploying its assasin and 
+				 * then leave the thread. */
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+				done = 1;
+				break;
+		}
+	}
+	ldap_pvt_thread_exit(NULL);
+	return NULL;
+}
+
+
+
+static void *stop_status_routine( void *ptr )
+{
+	DWORD	wait_result;
+	int		done = 0;
+
+	while ( !done )
+	{
+		wait_result = WaitForSingleObject( stopped_event, SCM_NOTIFICATION_INTERVAL );
+		switch ( wait_result )
+		{
+			case WAIT_ABANDONED:
+			case WAIT_OBJECT_0:
+				/* the object that we were waiting for has been destroyed (ABANDONED) or
+				 * signalled (TIMEOUT_0). The shutting down process is therefore complete 
+				 * and the final SERVICE_STOPPED message will be sent to the service control
+				 * manager prior to the process terminating. */
+				done = 1;
+				break;
+			case WAIT_TIMEOUT:
+				/* We've waited for the required time, so send an update to the Service Control 
+				 * Manager saying to wait again. */
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+				break;
+			case WAIT_FAILED:
+				/* theres been some problem with WaitForSingleObject so tell the Service
+				 * Control Manager to wait 30 seconds before deploying its assasin and 
+				 * then leave the thread. */
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+				done = 1;
+				break;
+		}
+	}
+	ldap_pvt_thread_exit(NULL);
+	return NULL;
+}
+
+
+
+void WINAPI SLAPDServiceCtrlHandler( IN DWORD Opcode)
+{
+	switch (Opcode)
+	{
+	case SERVICE_CONTROL_STOP:
+	case SERVICE_CONTROL_SHUTDOWN:
+
+		Debug( LDAP_DEBUG_TRACE, "Service Shutdown ordered\n", 0, 0, 0 );
+		SLAPDServiceStatus.dwCurrentState	= SERVICE_STOP_PENDING;
+		SLAPDServiceStatus.dwCheckPoint++;
+		SLAPDServiceStatus.dwWaitHint		= SCM_NOTIFICATION_INTERVAL * 2;
+		SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+
+		ldap_pvt_thread_cond_init( &stopped_event );
+		if ( stopped_event == NULL )
+		{
+			/* the event was not created. We will ask the service control manager for 30
+			 * seconds to shutdown */
+			SLAPDServiceStatus.dwCheckPoint++;
+			SLAPDServiceStatus.dwWaitHint		= THIRTY_SECONDS;
+			SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+		}
+		else
+		{
+			/* start a thread to report the progress to the service control manager 
+			 * until the stopped_event is fired. */
+			if ( ldap_pvt_thread_create( &stop_status_tid, 0, stop_status_routine, NULL ) == 0 )
+			{
+				
+			}
+			else {
+				/* failed to create the thread that tells the Service Control Manager that the
+				 * service stopping is proceeding. 
+				 * tell the Service Control Manager to wait another 30 seconds before deploying its
+				 * assasin.  */
+				SLAPDServiceStatus.dwCheckPoint++;
+				SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
+				SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+			}
+		}
+		stopfunc( -1 );
+		break;
+
+	case SERVICE_CONTROL_INTERROGATE:
+		SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+		break;
+	}
+	return;
+}
+
+void *getRegParam( char *svc, char *value )
+{
+	HKEY hkey;
+	char path[255];
+	DWORD vType;
+	static char vValue[1024];
+	DWORD valLen = sizeof( vValue );
+
+	if ( svc != NULL )
+		snprintf ( path, sizeof path, "SOFTWARE\\%s", svc );
+	else
+		snprintf ( path, sizeof path, "SOFTWARE\\OpenLDAP\\Parameters" );
+	
+	if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
+	{
+		/*Debug( LDAP_DEBUG_ANY, "RegOpenKeyEx() %s\n", GetLastErrorString(), 0, 0); */
+		return NULL;
+	}
+
+	if ( RegQueryValueEx( hkey, value, NULL, &vType, vValue, &valLen ) != ERROR_SUCCESS )
+	{
+		/*Debug( LDAP_DEBUG_ANY, "RegQueryValueEx() %s\n", GetLastErrorString(), 0, 0 );*/
+		RegCloseKey( hkey );
+		return NULL;
+	}
+	RegCloseKey( hkey );
+	
+	switch ( vType )
+	{
+	case REG_BINARY:
+	case REG_DWORD:
+		return (void*)&vValue;
+	case REG_SZ:
+		return (void*)&vValue;
+	}
+	return (void*)NULL;
+}
+
+void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, char *urls )
+{
+	char *Inserts[5];
+	WORD i = 0, j;
+	HANDLE hEventLog;
+	
+	hEventLog = RegisterEventSource( NULL, svc );
+
+	Inserts[i] = (char *)malloc( 20 );
+	itoa( slap_debug, Inserts[i++], 10 );
+	Inserts[i++] = strdup( configfile );
+	Inserts[i++] = strdup( urls ? urls : "ldap:///" );
+	Inserts[i++] = strdup( is_NT_Service ? "svc" : "cmd" );
+
+	ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0,
+		MSG_SLAPD_STARTED, NULL, i, 0, (LPCSTR *) Inserts, NULL );
+
+	for ( j = 0; j < i; j++ )
+		ldap_memfree( Inserts[j] );
+	DeregisterEventSource( hEventLog );
+}
+
+
+
+void LogSlapdStoppedEvent( char *svc )
+{
+	HANDLE hEventLog;
+	
+	hEventLog = RegisterEventSource( NULL, svc );
+	ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0,
+		MSG_SLAPD_STOPPED, NULL, 0, 0, NULL, NULL );
+	DeregisterEventSource( hEventLog );
+}
+
+
+void CommenceStartupProcessing( LPCTSTR lpszServiceName,
+							   void (*stopper)(int) )
+{
+	hSLAPDServiceStatus = RegisterServiceCtrlHandler( lpszServiceName, (LPHANDLER_FUNCTION)SLAPDServiceCtrlHandler);
+
+	stopfunc = stopper;
+
+	/* initialize the Service Status structure */
+	SLAPDServiceStatus.dwServiceType				= SERVICE_WIN32_OWN_PROCESS;
+	SLAPDServiceStatus.dwCurrentState				= SERVICE_START_PENDING;
+	SLAPDServiceStatus.dwControlsAccepted			= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+	SLAPDServiceStatus.dwWin32ExitCode				= NO_ERROR;
+	SLAPDServiceStatus.dwServiceSpecificExitCode	= 0;
+	SLAPDServiceStatus.dwCheckPoint					= 1;
+	SLAPDServiceStatus.dwWaitHint					= SCM_NOTIFICATION_INTERVAL * 2;
+
+	SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+
+	/* start up a thread to keep sending SERVICE_START_PENDING to the Service Control Manager
+	 * until the slapd listener is completed and listening. Only then should we send 
+	 * SERVICE_RUNNING to the Service Control Manager. */
+	ldap_pvt_thread_cond_init( &started_event );
+	if ( started_event == NULL)
+	{
+		/* failed to create the event to determine when the startup process is complete so
+		 * tell the Service Control Manager to wait another 30 seconds before deploying its
+		 * assasin  */
+		SLAPDServiceStatus.dwCheckPoint++;
+		SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
+		SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+	}
+	else
+	{
+		/* start a thread to report the progress to the service control manager 
+		 * until the started_event is fired.  */
+		if ( ldap_pvt_thread_create( &start_status_tid, 0, start_status_routine, NULL ) == 0 )
+		{
+			
+		}
+		else {
+			/* failed to create the thread that tells the Service Control Manager that the
+			 * service startup is proceeding. 
+			 * tell the Service Control Manager to wait another 30 seconds before deploying its
+			 * assasin.  */
+			SLAPDServiceStatus.dwCheckPoint++;
+			SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
+			SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+		}
+	}
+}
+
+void ReportSlapdShutdownComplete(  )
+{
+	if ( is_NT_Service )
+	{
+		/* stop sending SERVICE_STOP_PENDING messages to the Service Control Manager */
+		ldap_pvt_thread_cond_signal( &stopped_event );
+		ldap_pvt_thread_cond_destroy( &stopped_event );
+
+		/* wait for the thread sending the SERVICE_STOP_PENDING messages to the Service Control Manager to die.
+		 * if the wait fails then put ourselves to sleep for half the Service Control Manager update interval */
+		if (ldap_pvt_thread_join( stop_status_tid, (void *) NULL ) == -1)
+			ldap_pvt_thread_sleep( SCM_NOTIFICATION_INTERVAL / 2 );
+
+		SLAPDServiceStatus.dwCurrentState = SERVICE_STOPPED;
+		SLAPDServiceStatus.dwCheckPoint++;
+		SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL;
+		SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
+	}
+}
+
+static char *GetErrorString( int err )
+{
+	static char msgBuf[1024];
+
+	FormatMessage(
+		FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL,
+		err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		msgBuf, 1024, NULL );
+
+	return msgBuf;
+}
+
+static char *GetLastErrorString( void )
+{
+	return GetErrorString( GetLastError() );
+}
+#endif
diff --git a/libraries/liblutil/sasl.c b/libraries/liblutil/sasl.c
new file mode 100644
index 0000000000000000000000000000000000000000..a1308a8018deb8cd52e6a1a89ad02a14b7f6e8fa
--- /dev/null
+++ b/libraries/liblutil/sasl.c
@@ -0,0 +1,206 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 2000-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#ifdef HAVE_CYRUS_SASL
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#ifdef HAVE_SASL_SASL_H
+#include <sasl/sasl.h>
+#else
+#include <sasl.h>
+#endif
+
+#include <ldap.h>
+#include "lutil_ldap.h"
+
+
+typedef struct lutil_sasl_defaults_s {
+	char *mech;
+	char *realm;
+	char *authcid;
+	char *passwd;
+	char *authzid;
+} lutilSASLdefaults;
+
+
+void *
+lutil_sasl_defaults(
+	LDAP *ld,
+	char *mech,
+	char *realm,
+	char *authcid,
+	char *passwd,
+	char *authzid )
+{
+	lutilSASLdefaults *defaults;
+	
+	defaults = ber_memalloc( sizeof( lutilSASLdefaults ) );
+
+	if( defaults == NULL ) return NULL;
+
+	defaults->mech = mech;
+	defaults->realm = realm;
+	defaults->authcid = authcid;
+	defaults->passwd = passwd;
+	defaults->authzid = authzid;
+
+	if( defaults->mech == NULL ) {
+		ldap_get_option( ld, LDAP_OPT_X_SASL_MECH, &defaults->mech );
+	}
+	if( defaults->realm == NULL ) {
+		ldap_get_option( ld, LDAP_OPT_X_SASL_REALM, &defaults->realm );
+	}
+	if( defaults->authcid == NULL ) {
+		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHCID, &defaults->authcid );
+	}
+	if( defaults->authzid == NULL ) {
+		ldap_get_option( ld, LDAP_OPT_X_SASL_AUTHZID, &defaults->authzid );
+	}
+
+	return defaults;
+}
+
+static int interaction(
+	unsigned flags,
+	sasl_interact_t *interact,
+	lutilSASLdefaults *defaults )
+{
+	const char *dflt = interact->defresult;
+	char input[1024];
+
+	int noecho=0;
+	int challenge=0;
+
+	switch( interact->id ) {
+	case SASL_CB_GETREALM:
+		if( defaults ) dflt = defaults->realm;
+		break;
+	case SASL_CB_AUTHNAME:
+		if( defaults ) dflt = defaults->authcid;
+		break;
+	case SASL_CB_PASS:
+		if( defaults ) dflt = defaults->passwd;
+		noecho = 1;
+		break;
+	case SASL_CB_USER:
+		if( defaults ) dflt = defaults->authzid;
+		break;
+	case SASL_CB_NOECHOPROMPT:
+		noecho = 1;
+		challenge = 1;
+		break;
+	case SASL_CB_ECHOPROMPT:
+		challenge = 1;
+		break;
+	}
+
+	if( dflt && !*dflt ) dflt = NULL;
+
+	if( flags != LDAP_SASL_INTERACTIVE &&
+		( dflt || interact->id == SASL_CB_USER ) )
+	{
+		goto use_default;
+	}
+
+	if( flags == LDAP_SASL_QUIET ) {
+		/* don't prompt */
+		return LDAP_OTHER;
+	}
+
+	if( challenge ) {
+		if( interact->challenge ) {
+			fprintf( stderr, "Challenge: %s\n", interact->challenge );
+		}
+	}
+
+	if( dflt ) {
+		fprintf( stderr, "Default: %s\n", dflt );
+	}
+
+	snprintf( input, sizeof input, "%s: ",
+		interact->prompt ? interact->prompt : "Interact" );
+
+	if( noecho ) {
+		interact->result = (char *) getpassphrase( input );
+		interact->len = interact->result
+			? strlen( interact->result ) : 0;
+
+	} else {
+		/* prompt user */
+		fputs( input, stderr );
+
+		/* get input */
+		interact->result = fgets( input, sizeof(input), stdin );
+
+		if( interact->result == NULL ) {
+			interact->len = 0;
+			return LDAP_UNAVAILABLE;
+		}
+
+		/* len of input */
+		interact->len = strlen(input); 
+
+		if( interact->len > 0 && input[interact->len - 1] == '\n' ) {
+			/* input includes '\n', trim it */
+			interact->len--;
+			input[interact->len] = '\0';
+		}
+	}
+
+
+	if( interact->len > 0 ) {
+		/* duplicate */
+		char *p = (char *)interact->result;
+		interact->result = strdup( p );
+
+		/* zap */
+		memset( p, '\0', interact->len );
+
+	} else {
+use_default:
+		/* input must be empty */
+		interact->result = strdup( (dflt && *dflt) ? dflt : "" );
+		interact->len = interact->result
+			? strlen( interact->result ) : 0;
+	}
+
+	if( defaults && defaults->passwd && interact->id == SASL_CB_PASS ) {
+		/* zap password after first use */
+		memset( defaults->passwd, '\0', strlen(defaults->passwd) );
+		defaults->passwd = NULL;
+	}
+
+	return LDAP_SUCCESS;
+}
+
+int lutil_sasl_interact(
+	LDAP *ld,
+	unsigned flags,
+	void *defaults,
+	void *in )
+{
+	sasl_interact_t *interact = in;
+
+	if( flags == LDAP_SASL_INTERACTIVE ) {
+		fputs( "SASL Interaction\n", stderr );
+	}
+
+	while( interact->id != SASL_CB_LIST_END ) {
+		int rc = interaction( flags, interact, defaults );
+
+		if( rc )  return rc;
+		interact++;
+	}
+	
+	return LDAP_SUCCESS;
+}
+#endif
diff --git a/libraries/liblutil/stdio.c b/libraries/liblutil/stdio.c
new file mode 100644
index 0000000000000000000000000000000000000000..adf41871851a401e5a7fe9447d9f8138818638ec
--- /dev/null
+++ b/libraries/liblutil/stdio.c
@@ -0,0 +1,228 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/stdarg.h>
+#include <ac/string.h>
+
+#include <lutil.h>
+
+#ifndef HAVE_VSNPRINTF
+/* Write at most n characters to the buffer in str, return the
+ * number of chars written or -1 if the buffer would have been
+ * overflowed.
+ *
+ * This is portable to any POSIX-compliant system. We use pipe()
+ * to create a valid file descriptor, and then fdopen() it to get
+ * a valid FILE pointer. The user's buffer and size are assigned
+ * to the FILE pointer using setvbuf. Then we close the read side
+ * of the pipe to invalidate the descriptor.
+ *
+ * If the write arguments all fit into size n, the write will
+ * return successfully. If the write is too large, the stdio
+ * buffer will need to be flushed to the underlying file descriptor.
+ * The flush will fail because it is attempting to write to a
+ * broken pipe, and the write will be terminated.
+ * -- hyc, 2002-07-19
+ */
+#ifndef HAVE_EBCDIC
+/* This emulation uses vfprintf; on OS/390 we're also emulating
+ * that function so it's more efficient just to have a separate
+ * version of vsnprintf there.
+ */
+#include <ac/signal.h>
+int vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
+{
+	int fds[2], res;
+	FILE *f;
+	RETSIGTYPE (*sig)();
+
+	if (pipe( fds )) return -1;
+
+	f = fdopen( fds[1], "w" );
+	if ( !f ) {
+		close( fds[1] );
+		close( fds[0] );
+		return -1;
+	}
+	setvbuf( f, str, _IOFBF, n );
+	sig = signal( SIGPIPE, SIG_IGN );
+	close( fds[0] );
+
+	res = vfprintf( f, fmt, ap );
+
+	fclose( f );
+	signal( SIGPIPE, sig );
+	return res;
+}
+#endif
+
+int snprintf( char *str, size_t n, const char *fmt, ... )
+{
+	va_list ap;
+	int res;
+
+	va_start( ap, fmt );
+	res = vsnprintf( str, n, fmt, ap );
+	va_end( ap );
+	return res;
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifdef HAVE_EBCDIC
+/* stdio replacements with ASCII/EBCDIC translation for OS/390.
+ * The OS/390 port depends on the CONVLIT compiler option being
+ * used to force character and string literals to be compiled in
+ * ISO8859-1, and the __LIBASCII cpp symbol to be defined to use the
+ * OS/390 ASCII-compatibility library. This library only supplies
+ * an ASCII version of sprintf, so other needed functions are
+ * provided here.
+ *
+ * All of the internal character manipulation is done in ASCII,
+ * but file I/O is EBCDIC, so we catch any stdio reading/writing
+ * of files here and do the translations.
+ */
+
+#undef fputs
+#undef fgets
+
+char *lutil_fgets( char *s, int n, FILE *fp )
+{
+	s = (char *)fgets( s, n, fp );
+	if ( s ) __etoa( s );
+	return s;
+}
+
+int lutil_fputs( const char *str, FILE *fp )
+{
+	char buf[8192];
+
+	strncpy( buf, str, sizeof(buf) );
+	__atoe( buf );
+	return fputs( buf, fp );
+}
+
+/* The __LIBASCII doesn't include a working vsprintf, so we make do
+ * using just sprintf. This is a very simplistic parser that looks for
+ * format strings and uses sprintf to process them one at a time.
+ * Literal text is just copied straight to the destination.
+ * The result is appended to the destination string. The parser
+ * recognizes field-width specifiers and the 'l' qualifier; it
+ * may need to be extended to recognize other qualifiers but so
+ * far this seems to be enough.
+ */
+int vsnprintf( char *str, size_t n, const char *fmt, va_list ap )
+{
+	char *ptr, *pct, *s2, *f2, *end;
+	char fm2[64];
+	int len, rem;
+
+	ptr = (char *)fmt;
+	s2 = str;
+	fm2[0] = '%';
+	if (n)
+		end = str + n;
+	else
+		end = NULL;
+
+	for (pct = strchr(ptr, '%'); pct; pct = strchr(ptr, '%')) {
+		len = pct-ptr;
+		if (end) {
+			rem = end-s2;
+			if (rem < 1) return -1;
+			if (rem < len) len = rem;
+		}
+		s2 = lutil_strncopy( s2, ptr, len );
+		/* Did we cheat the length above? If so, bail out */
+		if (len < pct-ptr) return -1;
+		for (pct++, f2 = fm2+1; isdigit(*pct);) *f2++ = *pct++;
+		if (*pct == 'l') *f2++ = *pct++;
+		if (*pct == '%') *s2++ = '%';
+		else {
+			*f2++ = *pct;
+			*f2 = '\0';
+			if (*pct == 's') {
+				char *ss = va_arg(ap, char *);
+				/* Attempt to limit sprintf output. This
+				 * may be thrown off if field widths were
+				 * specified for this string.
+				 *
+				 * If it looks like the string is too
+				 * long for the remaining buffer, bypass
+				 * sprintf and just copy what fits, then
+				 * quit.
+				 */
+				if (end && strlen(ss) > (rem=end-s2)) {
+					strncpy(s2, ss, rem);
+					return -1;
+				} else {
+					s2 += sprintf(s2, fm2, ss);
+				}
+			} else
+				s2 += sprintf(s2, fm2, va_arg(ap, int));
+		}
+		ptr = pct + 1;
+	}
+	if (end) {
+		rem = end-s2;
+		if (rem > 0) {
+			len = strlen(ptr);
+			s2 = lutil_strncopy( s2, ptr, rem );
+			rem -= len;
+		}
+		if (rem < 0) return -1;
+	} else {
+		s2 = lutil_strcopy( s2, ptr );
+	}
+	return s2 - str;
+}
+
+int lutil_vsprintf( char *str, const char *fmt, va_list ap )
+{
+	return vsnprintf( str, 0, fmt, ap );
+}
+
+/* The fixed buffer size here is a problem, we don't know how
+ * to flush the buffer and keep printing if the msg is too big. 
+ * Hopefully we never try to write something bigger than this
+ * in a log msg...
+ */
+int lutil_vfprintf( FILE *fp, const char *fmt, va_list ap )
+{
+	char buf[8192];
+	int res;
+
+	vsnprintf( buf, sizeof(buf), fmt, ap );
+	__atoe( buf );
+	res = fputs( buf, fp );
+	if (res == EOF) res = -1;
+	return res;
+}
+
+int lutil_printf( const char *fmt, ... )
+{
+	va_list ap;
+	int res;
+
+	va_start( ap, fmt );
+	res = lutil_vfprintf( stdout, fmt, ap );
+	va_end( ap );
+	return res;
+}
+
+int lutil_fprintf( FILE *fp, const char *fmt, ... )
+{
+	va_list ap;
+	int res;
+
+	va_start( ap, fmt );
+	res = lutil_vfprintf( fp, fmt, ap );
+	va_end( ap );
+	return res;
+}
+#endif
diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..973406f21ebde25448f840517aba226129c7b79b
--- /dev/null
+++ b/libraries/liblutil/utils.c
@@ -0,0 +1,109 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+#include <ac/time.h>
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <lutil.h>
+#include <ldap_defaults.h>
+
+#ifdef HAVE_EBCDIC
+int _trans_argv = 1;
+#endif
+
+char* lutil_progname( const char* name, int argc, char *argv[] )
+{
+	char *progname;
+
+	if(argc == 0) {
+		return (char *)name;
+	}
+
+#ifdef HAVE_EBCDIC
+	if (_trans_argv) {
+		int i;
+		for (i=0; i<argc; i++) __etoa(argv[i]);
+		_trans_argv = 0;
+	}
+#endif
+	progname = strrchr ( argv[0], *LDAP_DIRSEP );
+	progname = progname ? &progname[1] : argv[0];
+
+	return progname;
+}
+
+size_t lutil_gentime( char *s, size_t max, const struct tm *tm )
+{
+	size_t ret;
+#ifdef HAVE_EBCDIC
+/* We've been compiling in ASCII so far, but we want EBCDIC now since
+ * strftime only understands EBCDIC input.
+ */
+#pragma convlit(suspend)
+#endif
+	ret = strftime( s, max, "%Y%m%d%H%M%SZ", tm );
+#ifdef HAVE_EBCDIC
+#pragma convlit(resume)
+	__etoa( s );
+#endif
+	return ret;
+}
+
+/* strcopy is like strcpy except it returns a pointer to the trailing NUL of
+ * the result string. This allows fast construction of catenated strings
+ * without the overhead of strlen/strcat.
+ */
+char *
+lutil_strcopy(
+	char *a,
+	const char *b
+)
+{
+	if (!a || !b)
+		return a;
+	
+	while ((*a++ = *b++)) ;
+	return a-1;
+}
+
+/* strncopy is like strcpy except it returns a pointer to the trailing NUL of
+ * the result string. This allows fast construction of catenated strings
+ * without the overhead of strlen/strcat.
+ */
+char *
+lutil_strncopy(
+	char *a,
+	const char *b,
+	size_t n
+)
+{
+	if (!a || !b || n == 0)
+		return a;
+	
+	while ((*a++ = *b++) && n-- > 0) ;
+	return a-1;
+}
+
+#ifndef HAVE_MKSTEMP
+int mkstemp( char * template )
+{
+#ifdef HAVE_MKTEMP
+	return open ( mktemp ( template ), O_RDWR|O_CREAT|O_EXCL, 0600 );
+#else
+	return -1;
+#endif
+}
+#endif
diff --git a/libraries/librewrite/map.c b/libraries/librewrite/map.c
index 8db54af13711b89701804bb6fdcf5a214cf20012..19389dff45ffa80718476d90d4242bae0487310e 100644
--- a/libraries/librewrite/map.c
+++ b/libraries/librewrite/map.c
@@ -24,6 +24,8 @@
 
 #include <portable.h>
 
+#include <stdio.h>
+
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
@@ -541,6 +543,7 @@ rewrite_xmap_apply(
 			break;
 		}
 
+#ifdef HAVE_PW_GECOS
 		if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) {
 			int l = strlen( pwd->pw_gecos );
 			
@@ -555,7 +558,9 @@ rewrite_xmap_apply(
 				break;
 			}
 			val->bv_len = l;
-		} else {
+		} else
+#endif /* HAVE_PW_GECOS */
+		{
 			val->bv_val = strdup( key->bv_val );
 			val->bv_len = key->bv_len;
 		}
diff --git a/libraries/librewrite/parse.c b/libraries/librewrite/parse.c
index bc83e0594e575a6a0cc61c4ce12ec07ef05e0452..42b0180ba38e7740c1db2a31270a71cbb956fcc4 100644
--- a/libraries/librewrite/parse.c
+++ b/libraries/librewrite/parse.c
@@ -24,6 +24,8 @@
 
 #include <portable.h>
 
+#include <stdio.h>
+
 #include "rewrite-int.h"
 
 static int
diff --git a/libraries/librewrite/rewrite.c b/libraries/librewrite/rewrite.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac301b7a51c0b106f920fb4b410145577d55c95a
--- /dev/null
+++ b/libraries/librewrite/rewrite.c
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
+ * All rights reserved.
+ *
+ * Permission is granted to anyone to use this software for any purpose
+ * on any computer system, and to alter it and redistribute it, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission.  Since few users ever read sources,
+ * credits should appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.  Since few users
+ * ever read sources, credits should appear in the documentation.
+ * 
+ * 4. This notice may not be removed or altered.
+ *
+ ******************************************************************************/
+
+#include <portable.h>
+
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/syslog.h>
+#include <ac/regex.h>
+#include <ac/socket.h>
+#include <ac/unistd.h>
+#include <ac/ctype.h>
+#include <ac/string.h>
+#include <stdio.h>
+
+#include <rewrite.h>
+
+int ldap_debug;
+int ldap_syslog;
+int ldap_syslog_level;
+
+char *
+apply( 
+		FILE *fin, 
+		const char *rewriteContext,
+		const char *arg
+)
+{
+	struct rewrite_info *info;
+	char *string, *sep, *result = NULL;
+	int rc;
+	void *cookie = &info;
+
+	info = rewrite_info_init(REWRITE_MODE_ERR);
+
+	if ( rewrite_read( fin, info ) != 0 ) {
+		exit( EXIT_FAILURE );
+	}
+
+	rewrite_param_set( info, "prog", "rewrite" );
+
+	rewrite_session_init( info, cookie );
+
+	string = strdup( arg );
+	for ( sep = strchr( rewriteContext, ',' );
+			rewriteContext != NULL;
+			rewriteContext = sep,
+			sep ? sep = strchr( rewriteContext, ',' ) : NULL ) {
+		if ( sep != NULL ) {
+			sep[ 0 ] = '\0';
+			sep++;
+		}
+		/* rc = rewrite( info, rewriteContext, string, &result ); */
+		rc = rewrite_session( info, rewriteContext, string,
+				cookie, &result );
+		
+		fprintf( stdout, "%s -> %s\n", string, 
+				( result ? result : "unwilling to perform" ) );
+		if ( result == NULL ) {
+			break;
+		}
+		free( string );
+		string = result;
+	}
+
+	rewrite_session_delete( info, cookie );
+
+	return result;
+}
+
+int
+main( int argc, char *argv[] )
+{
+	FILE *fin = NULL;
+	char *rewriteContext = REWRITE_DEFAULT_CONTEXT;
+
+	while ( 1 ) {
+		int opt = getopt( argc, argv, "f:hr:" );
+
+		if ( opt == EOF ) {
+			break;
+		}
+
+		switch ( opt ) {
+		case 'f':
+			fin = fopen( optarg, "r" );
+			if ( fin == NULL ) {
+				fprintf( stderr, "unable to open file '%s'\n",
+						optarg );
+				exit( EXIT_FAILURE );
+			}
+			break;
+			
+		case 'h':
+			fprintf( stderr, 
+	"usage: rewrite [options] string\n"
+	"\n"
+	"\t\t-f file\t\tconfiguration file\n"
+	"\t\t-r rule[s]\tlist of comma-separated rules\n"
+	"\n"
+	"\tsyntax:\n"
+	"\t\trewriteEngine\t{on|off}\n"
+	"\t\trewriteContext\tcontextName [alias aliasedContextName]\n"
+	"\t\trewriteRule\tpattern subst [flags]\n"
+	"\n" 
+				);
+			exit( EXIT_SUCCESS );
+			
+		case 'r':
+			rewriteContext = strdup( optarg );
+			break;
+		}
+	}
+	
+	if ( optind >= argc ) {
+		return -1;
+	}
+
+	apply( ( fin ? fin : stdin ), rewriteContext, argv[ optind ] );
+
+	return 0;
+}
+