From 1833df239736ea84d1b16cc27ab49710af16d042 Mon Sep 17 00:00:00 2001
From: Kurt Zeilenga <kurt@openldap.org>
Date: Sun, 28 Jul 2002 21:04:29 +0000
Subject: [PATCH] progname, etc.

---
 clients/tools/ldapcompare.c | 715 ++++++++++++++++++++++++++++++
 clients/tools/ldapdelete.c  | 835 +++++++++++++++++++++++++++++++-----
 clients/tools/ldapmodify.c  |  11 +-
 clients/tools/ldapmodrdn.c  | 782 ++++++++++++++++++++++++++++-----
 clients/tools/ldappasswd.c  |   4 +-
 clients/tools/ldapsearch.c  |  15 +-
 clients/tools/ldapwhoami.c  |   4 +-
 7 files changed, 2143 insertions(+), 223 deletions(-)
 create mode 100644 clients/tools/ldapcompare.c

diff --git a/clients/tools/ldapcompare.c b/clients/tools/ldapcompare.c
new file mode 100644
index 0000000000..3b731f9346
--- /dev/null
+++ b/clients/tools/ldapcompare.c
@@ -0,0 +1,715 @@
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+#include <ac/errno.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#include <ldap.h>
+
+#include "ldif.h"
+#include "lutil.h"
+#include "lutil_ldap.h"
+#include "ldap_defaults.h"
+
+static void
+usage( const char *s )
+{
+	fprintf( stderr,
+"usage: %s [options] DN <attr:value|attr::b64value>\n"
+"where:\n"
+"  DN\tDistinguished Name\n"
+"  attr\tassertion attribute\n"
+"  value\tassertion value\n"
+"  b64value\tbase64 encoding of assertion value\n"
+
+"Common options:\n"
+"  -d level   set LDAP debugging level to `level'\n"
+"  -D binddn  bind DN\n"
+"  -h host    LDAP server\n"
+"  -H URI     LDAP Uniform Resource Indentifier(s)\n"
+"  -I         use SASL Interactive mode\n"
+"  -k         use Kerberos authentication\n"
+"  -K         like -k, but do only step 1 of the Kerberos bind\n"
+"  -M         enable Manage DSA IT control (-MM to make critical)\n"
+"  -n         show what would be done but don't actually compare\n"
+"  -O props   SASL security properties\n"
+"  -p port    port on LDAP server\n"
+"  -P version procotol version (default: 3)\n"
+"  -z         Quiet mode, don't print anything, use return values\n"
+"  -Q         use SASL Quiet mode\n"
+"  -R realm   SASL realm\n"
+"  -U authcid SASL authentication identity\n"
+"  -v         run in verbose mode (diagnostics to standard output)\n"
+"  -w passwd  bind passwd (for simple authentication)\n"
+"  -W         prompt for bind passwd\n"
+"  -x         Simple authentication\n"
+"  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
+"  -Y mech    SASL mechanism\n"
+"  -Z         Start TLS request (-ZZ to require successful response)\n"
+, s );
+
+	exit( EXIT_FAILURE );
+}
+
+static int docompare LDAP_P((
+	LDAP *ld,
+	char *dn,
+	char *attr,
+	struct berval *bvalue,
+	int quiet,
+	LDAPControl **sctrls,
+	LDAPControl **cctrls));
+
+static char *prog = NULL;
+static char	*binddn = NULL;
+static struct berval passwd = { 0, NULL };
+static char	*ldaphost = NULL;
+static char *ldapuri = NULL;
+static int	ldapport = 0;
+#ifdef HAVE_CYRUS_SASL
+static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
+static char	*sasl_realm = NULL;
+static char	*sasl_authc_id = NULL;
+static char	*sasl_authz_id = NULL;
+static char	*sasl_mech = NULL;
+static char	*sasl_secprops = NULL;
+#endif
+static int	use_tls = 0;
+static int	verbose, not;
+
+int
+main( int argc, char **argv )
+{
+	char	*compdn = NULL, *attrs = NULL;
+	char	*sep;
+	int		rc, i, manageDSAit, quiet;
+	int		referrals, debug;
+	int		authmethod, version, want_bindpw;
+	LDAP	*ld = NULL;
+	struct berval bvalue = { 0, NULL };
+
+	debug = verbose = not = referrals =
+		manageDSAit = want_bindpw = quiet = 0;
+
+	version = -1;
+
+	authmethod = -1;
+
+	prog = lutil_progname( "ldapcompare", argc, argv );
+
+	while (( i = getopt( argc, argv,
+		"Cd:D:h:H:IkKMnO:p:P:qQR:U:vw:WxX:Y:zZ")) != EOF )
+	{
+		switch( i ) {
+
+		/* Common Options */
+		case 'C':
+			referrals++;
+			break;
+		case 'd':
+			debug |= atoi( optarg );
+			break;
+		case 'D':	/* bind DN */
+			if( binddn != NULL ) {
+				fprintf( stderr, "%s: -D previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			binddn = strdup( optarg );
+			break;
+		case 'h':	/* ldap host */
+			if( ldapuri != NULL ) {
+				fprintf( stderr, "%s: -h incompatible with -H\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( ldaphost != NULL ) {
+				fprintf( stderr, "%s: -h previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			ldaphost = strdup( optarg );
+			break;
+		case 'H':	/* ldap URI */
+			if( ldaphost != NULL ) {
+				fprintf( stderr, "%s: -H incompatible with -h\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( ldapport ) {
+				fprintf( stderr, "%s: -H incompatible with -p\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( ldapuri != NULL ) {
+				fprintf( stderr, "%s: -H previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			ldapuri = strdup( optarg );
+			break;
+		case 'I':
+#ifdef HAVE_CYRUS_SASL
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -I incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible previous "
+					"authentication choice\n",
+					prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_flags = LDAP_SASL_INTERACTIVE;
+			break;
+#else
+			fprintf( stderr, "%s: was not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+		case 'k':	/* kerberos bind */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+			if( version > LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+
+			if( authmethod != -1 ) {
+				fprintf( stderr, "%s: -k incompatible with previous "
+					"authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+
+			authmethod = LDAP_AUTH_KRBV4;
+#else
+			fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+			return EXIT_FAILURE;
+#endif
+			break;
+		case 'K':	/* kerberos bind, part one only */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+			if( version > LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 ) {
+				fprintf( stderr, "%s: incompatible with previous "
+					"authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+
+			authmethod = LDAP_AUTH_KRBV41;
+#else
+			fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		case 'M':
+			/* enable Manage DSA IT */
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			manageDSAit++;
+			version = LDAP_VERSION3;
+			break;
+		case 'n':	/* print compares, don't actually do them */
+			++not;
+			break;
+		case 'O':
+#ifdef HAVE_CYRUS_SASL
+			if( sasl_secprops != NULL ) {
+				fprintf( stderr, "%s: -O previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible previous "
+					"authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_secprops = strdup( optarg );
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		case 'p':
+			if( ldapport ) {
+				fprintf( stderr, "%s: -p previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			ldapport = atoi( optarg );
+			break;
+		case 'P':
+			switch( atoi(optarg) ) {
+			case 2:
+				if( version == LDAP_VERSION3 ) {
+					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+						prog, version );
+					return EXIT_FAILURE;
+				}
+				version = LDAP_VERSION2;
+				break;
+			case 3:
+				if( version == LDAP_VERSION2 ) {
+					fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+						prog, version );
+					return EXIT_FAILURE;
+				}
+				version = LDAP_VERSION3;
+				break;
+			default:
+				fprintf( stderr, "%s: protocol version should be 2 or 3\n",
+					prog );
+				usage( prog );
+				return( EXIT_FAILURE );
+			} break;
+		case 'Q':
+#ifdef HAVE_CYRUS_SASL
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -Q incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible previous "
+					"authentication choice\n",
+					prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_flags = LDAP_SASL_QUIET;
+			break;
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+		case 'R':
+#ifdef HAVE_CYRUS_SASL
+			if( sasl_realm != NULL ) {
+				fprintf( stderr, "%s: -R previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -R incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible previous "
+					"authentication choice\n",
+					prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_realm = strdup( optarg );
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+	case 'U':
+#ifdef HAVE_CYRUS_SASL
+			if( sasl_authc_id != NULL ) {
+				fprintf( stderr, "%s: -U previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -U incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible previous "
+					"authentication choice\n",
+					prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_authc_id = strdup( optarg );
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		case 'v':	/* verbose mode */
+			verbose++;
+			break;
+		case 'w':	/* password */
+			passwd.bv_val = strdup( optarg );
+			{
+				char* p;
+
+				for( p = optarg; *p != '\0'; p++ ) {
+					*p = '\0';
+				}
+			}
+			passwd.bv_len = strlen( passwd.bv_val );
+			break;
+		case 'W':
+			want_bindpw++;
+			break;
+		case 'Y':
+#ifdef HAVE_CYRUS_SASL
+			if( sasl_mech != NULL ) {
+				fprintf( stderr, "%s: -Y previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -Y incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_mech = strdup( optarg );
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		case 'x':
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
+				fprintf( stderr, "%s: incompatible with previous "
+					"authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SIMPLE;
+			break;
+		case 'X':
+#ifdef HAVE_CYRUS_SASL
+			if( sasl_authz_id != NULL ) {
+				fprintf( stderr, "%s: -X previously specified\n", prog );
+				return EXIT_FAILURE;
+			}
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+				fprintf( stderr, "%s: -X incompatible with "
+					"authentication choice\n", prog );
+				return EXIT_FAILURE;
+			}
+			authmethod = LDAP_AUTH_SASL;
+			version = LDAP_VERSION3;
+			sasl_authz_id = strdup( optarg );
+#else
+			fprintf( stderr, "%s: not compiled with SASL support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		case 'z':
+			quiet++;
+			break;
+		case 'Z':
+#ifdef HAVE_TLS
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -Z incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			version = LDAP_VERSION3;
+			use_tls++;
+#else
+			fprintf( stderr, "%s: not compiled with TLS support\n",
+				prog );
+			return( EXIT_FAILURE );
+#endif
+			break;
+		default:
+			fprintf( stderr, "%s: unrecognized option -%c\n",
+				prog, optopt );
+			usage( argv[0] );
+		}
+	}
+
+	if (version == -1) {
+		version = LDAP_VERSION3;
+	}
+	if (authmethod == -1 && version > LDAP_VERSION2) {
+#ifdef HAVE_CYRUS_SASL
+		authmethod = LDAP_AUTH_SASL;
+#else
+		authmethod = LDAP_AUTH_SIMPLE;
+#endif
+	}
+
+	if ( argc - optind != 2 ) {
+		usage( argv[ 0 ] );
+	}
+
+	compdn = argv[optind++];
+	attrs = argv[optind++];
+
+	/* user passed in only 2 args, the last one better be in
+	 * the form attr:value or attr::b64value
+	 */
+	sep = strchr(attrs, ':');
+	if (!sep) {
+		usage( argv[ 0 ] );
+	}
+
+	*sep++='\0';
+	if ( *sep != ':' ) {
+		bvalue.bv_val = strdup( sep );
+		bvalue.bv_len = strlen( bvalue.bv_val );
+
+	} else {
+		/* it's base64 encoded. */
+		bvalue.bv_val = malloc( strlen( &sep[1] ));
+		bvalue.bv_len = lutil_b64_pton( &sep[1],
+			bvalue.bv_val, strlen( &sep[1] ));
+
+		if (bvalue.bv_len == -1) {
+			fprintf(stderr, "base64 decode error\n");
+			exit(-1);
+		}
+	}
+
+	if ( debug ) {
+		if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug )
+			!= LBER_OPT_SUCCESS )
+		{
+			fprintf( stderr,
+				"Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+		if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
+			!= LDAP_OPT_SUCCESS )
+		{
+			fprintf( stderr,
+				"Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+		ldif_debug = debug;
+	}
+
+#ifdef SIGPIPE
+	(void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
+	if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_init( %s, %d )\n",
+				ldaphost != NULL ? ldaphost : "<DEFAULT>",
+				ldapport );
+		}
+
+		ld = ldap_init( ldaphost, ldapport );
+		if( ld == NULL ) {
+			perror("ldapcompare: ldap_init");
+			return EXIT_FAILURE;
+		}
+
+	} else {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_initialize( %s )\n",
+				ldapuri != NULL ? ldapuri : "<DEFAULT>" );
+		}
+
+		rc = ldap_initialize( &ld, ldapuri );
+		if( rc != LDAP_SUCCESS ) {
+			fprintf( stderr,
+				"Could not create LDAP session handle (%d): %s\n",
+				rc, ldap_err2string(rc) );
+			return EXIT_FAILURE;
+		}
+	}
+
+
+	/* referrals */
+	if (ldap_set_option( ld, LDAP_OPT_REFERRALS,
+		referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
+			referrals ? "on" : "off" );
+		return EXIT_FAILURE;
+	}
+
+	if (version == -1 ) {
+		version = LDAP_VERSION3;
+	}
+
+	if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
+		!= LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
+			version );
+		return EXIT_FAILURE;
+	}
+
+	if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
+		ldap_perror( ld, "ldap_start_tls" );
+		if ( use_tls > 1 ) {
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (want_bindpw) {
+		passwd.bv_val = getpassphrase("Enter LDAP Password: ");
+		passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
+	}
+
+	if ( authmethod == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+		void *defaults;
+
+		if( sasl_secprops != NULL ) {
+			rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
+				(void *) sasl_secprops );
+
+			if( rc != LDAP_OPT_SUCCESS ) {
+				fprintf( stderr,
+					"Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
+					sasl_secprops );
+				return EXIT_FAILURE;
+			}
+		}
+
+		defaults = lutil_sasl_defaults( ld,
+			sasl_mech,
+			sasl_realm,
+			sasl_authc_id,
+			passwd.bv_val,
+			sasl_authz_id );
+
+		rc = ldap_sasl_interactive_bind_s( ld, binddn,
+			sasl_mech, NULL, NULL,
+			sasl_flags, lutil_sasl_interact, defaults );
+
+		if( rc != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
+			return EXIT_FAILURE;
+		}
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog, argv[0] );
+		return EXIT_FAILURE;
+#endif
+	} else {
+		if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
+				!= LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_bind" );
+			return EXIT_FAILURE;
+		}
+	}
+
+	if ( manageDSAit ) {
+		int err;
+		LDAPControl c;
+		LDAPControl *ctrls[2];
+		ctrls[0] = &c;
+		ctrls[1] = NULL;
+
+		c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
+		c.ldctl_value.bv_val = NULL;
+		c.ldctl_value.bv_len = 0;
+		c.ldctl_iscritical = manageDSAit > 1;
+
+		err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
+
+		if( err != LDAP_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
+				c.ldctl_iscritical ? "critical " : "" );
+			if( c.ldctl_iscritical ) {
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	if ( verbose ) {
+		fprintf( stderr, "DN:%s, attr:%s, value:%s\n",
+			compdn, attrs, sep );
+	}
+
+	rc = docompare( ld, compdn, attrs, &bvalue, quiet, NULL, NULL );
+
+	free( bvalue.bv_val );
+
+	ldap_unbind( ld );
+
+	return rc;
+}
+
+
+static int docompare(
+	LDAP *ld,
+	char *dn,
+	char *attr,
+	struct berval *bvalue,
+	int quiet,
+	LDAPControl **sctrls,
+	LDAPControl **cctrls )
+{
+	int			rc;
+
+	if ( not ) {
+		return LDAP_SUCCESS;
+	}
+
+	rc = ldap_compare_ext_s( ld, dn, attr, bvalue,
+		sctrls, cctrls );
+
+	if ( rc == -1 ) {
+		ldap_perror( ld, "ldap_result" );
+		return( rc );
+	}
+
+	/* if we were told to be quiet, use the return value. */
+	if ( !quiet ) {
+		if ( rc == LDAP_COMPARE_TRUE ) {
+			rc = 0;
+			printf("TRUE\n");
+		} else if ( rc == LDAP_COMPARE_FALSE ) {
+			rc = 0;
+			printf("FALSE\n");
+		} else {
+			ldap_perror( ld, "ldap_compare" );
+		}
+	}
+
+	return( rc );
+}
+
diff --git a/clients/tools/ldapdelete.c b/clients/tools/ldapdelete.c
index 3054cfb54f..bc04de2b5b 100644
--- a/clients/tools/ldapdelete.c
+++ b/clients/tools/ldapdelete.c
@@ -1,156 +1,797 @@
 /* ldapdelete.c - simple program to delete an entry using LDAP */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
 
 #include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <lber.h>
-#include <ldap.h>
 
-#include "ldapconfig.h"
+#include <ac/stdlib.h>
+#include <ac/ctype.h>
 
-static char	*binddn = LDAPDELETE_BINDDN;
-static char	*base = LDAPDELETE_BASE;
-static char	*passwd = NULL;
-static char	*ldaphost = LDAPHOST;
-static int	ldapport = LDAP_PORT;
-static int	not, verbose, contoper;
-static LDAP	*ld;
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include <ldap.h>
+#include "lutil.h"
+#include "lutil_ldap.h"
+#include "ldap_defaults.h"
 
-#ifdef LDAP_DEBUG
-extern int ldap_debug, lber_debug;
-#endif /* LDAP_DEBUG */
+static char	*prog;
+static char	*binddn = NULL;
+static struct berval passwd = { 0, NULL };
+static char *ldapuri = NULL;
+static char	*ldaphost = NULL;
+static int	ldapport = 0;
+static int	prune = 0;
+#ifdef HAVE_CYRUS_SASL
+static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
+static char	*sasl_mech = NULL;
+static char *sasl_realm = NULL;
+static char	*sasl_authc_id = NULL;
+static char	*sasl_authz_id = NULL;
+static char	*sasl_secprops = NULL;
+#endif
+static int	use_tls = 0;
+static int	not, verbose, contoper;
+static LDAP	*ld = NULL;
 
-#define safe_realloc( ptr, size )	( ptr == NULL ? malloc( size ) : \
-					 realloc( ptr, size ))
+static int dodelete LDAP_P((
+    LDAP *ld,
+    const char *dn));
 
+static int deletechildren LDAP_P((
+	LDAP *ld,
+	const char *dn ));
 
-main( argc, argv )
-    int		argc;
-    char	**argv;
+static void
+usage( const char *s )
 {
-    char		*usage = "usage: %s [-n] [-v] [-k] [-d debug-level] [-f file] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [dn]...\n";
-    char		*p, buf[ 4096 ];
-    FILE		*fp;
-    int			i, rc, kerberos, linenum, authmethod;
+	fprintf( stderr,
+"Delete entries from an LDAP server\n\n"
+"usage: %s [options] [dn]...\n"
+"	dn: list of DNs to delete. If not given, it will be readed from stdin\n"
+"	    or from the file specified with \"-f file\".\n"
+"Delete Options:\n"
+"  -r         delete recursively\n"
 
-    extern char	*optarg;
-    extern int	optind;
+"Common options:\n"
+"  -d level   set LDAP debugging level to `level'\n"
+"  -D binddn  bind DN\n"
+"  -f file    read operations from `file'\n"
+"  -h host    LDAP server\n"
+"  -H URI     LDAP Uniform Resource Indentifier(s)\n"
+"  -I         use SASL Interactive mode\n"
+"  -k         use Kerberos authentication\n"
+"  -K         like -k, but do only step 1 of the Kerberos bind\n"
+"  -M         enable Manage DSA IT control (-MM to make critical)\n"
+"  -n         show what would be done but don't actually do it\n"
+"  -O props   SASL security properties\n"
+"  -p port    port on LDAP server\n"
+"  -P version procotol version (default: 3)\n"
+"  -Q         use SASL Quiet mode\n"
+"  -R realm   SASL realm\n"
+"  -U authcid SASL authentication identity\n"
+"  -v         run in verbose mode (diagnostics to standard output)\n"
+"  -w passwd  bind passwd (for simple authentication)\n"
+"  -W         prompt for bind passwd\n"
+"  -x         Simple authentication\n"
+"  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
+"  -Y mech    SASL mechanism\n"
+"  -Z         Start TLS request (-ZZ to require successful response)\n"
+,		s );
+
+	exit( EXIT_FAILURE );
+}
 
-    kerberos = not = verbose = contoper = 0;
+
+int
+main( int argc, char **argv )
+{
+	char		buf[ 4096 ];
+	FILE		*fp;
+	int		i, rc, authmethod, referrals, want_bindpw, version, debug, manageDSAit;
+
+    not = verbose = contoper = want_bindpw = debug = manageDSAit = referrals = 0;
     fp = NULL;
+    authmethod = -1;
+	version = -1;
+
+    prog = lutil_progname( "ldapdelete", argc, argv );
 
-    while (( i = getopt( argc, argv, "nvkKch:p:D:w:d:f:" )) != EOF ) {
+    while (( i = getopt( argc, argv, "cf:r"
+		"Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF )
+	{
 	switch( i ) {
-	case 'k':	/* kerberos bind */
-	    kerberos = 2;
-	    break;
-	case 'K':	/* kerberos bind, part one only */
-	    kerberos = 1;
-	    break;
+	/* Delete Specific Options */
 	case 'c':	/* continuous operation mode */
 	    ++contoper;
 	    break;
-	case 'h':	/* ldap host */
-	    ldaphost = strdup( optarg );
-	    break;
-	case 'D':	/* bind DN */
-	    binddn = strdup( optarg );
-	    break;
-	case 'w':	/* password */
-	    passwd = strdup( optarg );
-	    break;
 	case 'f':	/* read DNs from a file */
+		if( fp != NULL ) {
+			fprintf( stderr, "%s: -f previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
 	    if (( fp = fopen( optarg, "r" )) == NULL ) {
 		perror( optarg );
-		exit( 1 );
+		exit( EXIT_FAILURE );
 	    }
 	    break;
+	case 'r':
+		prune = 1;
+		break;
+
+	/* Common Options */
+	case 'C':
+		referrals++;
+		break;
 	case 'd':
-#ifdef LDAP_DEBUG
-	    ldap_debug = lber_debug = atoi( optarg );	/* */
-#else /* LDAP_DEBUG */
-	    fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
-#endif /* LDAP_DEBUG */
+	    debug |= atoi( optarg );
 	    break;
-	case 'p':
-	    ldapport = atoi( optarg );
+	case 'D':	/* bind DN */
+		if( binddn != NULL ) {
+			fprintf( stderr, "%s: -D previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    binddn = strdup( optarg );
 	    break;
+	case 'h':	/* ldap host */
+		if( ldapuri != NULL ) {
+			fprintf( stderr, "%s: -h incompatible with -H\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldaphost != NULL ) {
+			fprintf( stderr, "%s: -h previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldaphost = strdup( optarg );
+	    break;
+	case 'H':	/* ldap URI */
+		if( ldaphost != NULL ) {
+			fprintf( stderr, "%s: -H incompatible with -h\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldapport ) {
+			fprintf( stderr, "%s: -H incompatible with -p\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldapuri != NULL ) {
+			fprintf( stderr, "%s: -H previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldapuri = strdup( optarg );
+	    break;
+	case 'I':
+#ifdef HAVE_CYRUS_SASL
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -I incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_flags = LDAP_SASL_INTERACTIVE;
+		break;
+#else
+		fprintf( stderr, "%s: was not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	case 'k':	/* kerberos bind */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+		if( version > LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+
+		if( authmethod != -1 ) {
+			fprintf( stderr, "%s: -k incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+			
+		authmethod = LDAP_AUTH_KRBV4;
+#else
+		fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+		return EXIT_FAILURE;
+#endif
+	    break;
+	case 'K':	/* kerberos bind, part one only */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+		if( version > LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 ) {
+			fprintf( stderr, "%s: incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+
+		authmethod = LDAP_AUTH_KRBV41;
+#else
+		fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+		return( EXIT_FAILURE );
+#endif
+	    break;
+	case 'M':
+		/* enable Manage DSA IT */
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		manageDSAit++;
+		version = LDAP_VERSION3;
+		break;
 	case 'n':	/* print deletes, don't actually do them */
 	    ++not;
 	    break;
+	case 'O':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_secprops != NULL ) {
+			fprintf( stderr, "%s: -O previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_secprops = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'p':
+		if( ldapport ) {
+			fprintf( stderr, "%s: -p previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldapport = atoi( optarg );
+	    break;
+	case 'P':
+		switch( atoi(optarg) ) {
+		case 2:
+			if( version == LDAP_VERSION3 ) {
+				fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			version = LDAP_VERSION2;
+			break;
+		case 3:
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			version = LDAP_VERSION3;
+			break;
+		default:
+			fprintf( stderr, "%s: protocol version should be 2 or 3\n",
+				prog );
+			usage( prog );
+			return( EXIT_FAILURE );
+		} break;
+	case 'Q':
+#ifdef HAVE_CYRUS_SASL
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Q incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_flags = LDAP_SASL_QUIET;
+		break;
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	case 'R':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_realm != NULL ) {
+			fprintf( stderr, "%s: -R previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -R incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_realm = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'U':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_authc_id != NULL ) {
+			fprintf( stderr, "%s: -U previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -U incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_authc_id = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
 	case 'v':	/* verbose mode */
 	    verbose++;
 	    break;
+	case 'w':	/* password */
+	    passwd.bv_val = strdup( optarg );
+		{
+			char* p;
+
+			for( p = optarg; *p != '\0'; p++ ) {
+				*p = '\0';
+			}
+		}
+		passwd.bv_len = strlen( passwd.bv_val );
+	    break;
+	case 'W':
+		want_bindpw++;
+		break;
+	case 'Y':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_mech != NULL ) {
+			fprintf( stderr, "%s: -Y previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Y incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_mech = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'x':
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
+			fprintf( stderr, "%s: incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SIMPLE;
+		break;
+	case 'X':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_authz_id != NULL ) {
+			fprintf( stderr, "%s: -X previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: -X incompatible with "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_authz_id = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'Z':
+#ifdef HAVE_TLS
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Z incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		version = LDAP_VERSION3;
+		use_tls++;
+#else
+		fprintf( stderr, "%s: not compiled with TLS support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
 	default:
-	    fprintf( stderr, usage, argv[0] );
-	    exit( 1 );
+		fprintf( stderr, "%s: unrecognized option -%c\n",
+			prog, optopt );
+		usage( prog );
+		return( EXIT_FAILURE );
 	}
     }
 
+	if (version == -1) {
+		version = LDAP_VERSION3;
+	}
+	if (authmethod == -1 && version > LDAP_VERSION2) {
+#ifdef HAVE_CYRUS_SASL
+		authmethod = LDAP_AUTH_SASL;
+#else
+		authmethod = LDAP_AUTH_SIMPLE;
+#endif
+	}
+
     if ( fp == NULL ) {
 	if ( optind >= argc ) {
 	    fp = stdin;
 	}
     }
 
-    if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
-	perror( "ldap_open" );
-	exit( 1 );
-    }
+	if ( debug ) {
+		if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+		if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+	}
 
-    ld->ld_deref = LDAP_DEREF_NEVER;	/* prudent, but probably unnecessary */
+#ifdef SIGPIPE
+	(void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
 
-    if ( !kerberos ) {
-	authmethod = LDAP_AUTH_SIMPLE;
-    } else if ( kerberos == 1 ) {
-	authmethod = LDAP_AUTH_KRBV41;
-    } else {
-	authmethod = LDAP_AUTH_KRBV4;
-    }
-    if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
-	ldap_perror( ld, "ldap_bind" );
-	exit( 1 );
-    }
+	if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_init( %s, %d )\n",
+				ldaphost != NULL ? ldaphost : "<DEFAULT>",
+				ldapport );
+		}
 
-    if ( fp == NULL ) {
-	for ( ; optind < argc; ++optind ) {
-	    rc = dodelete( ld, argv[ optind ] );
+		ld = ldap_init( ldaphost, ldapport );
+		if( ld == NULL ) {
+			perror("ldapdelete: ldap_init");
+			return EXIT_FAILURE;
+		}
+
+	} else {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_initialize( %s )\n",
+				ldapuri != NULL ? ldapuri : "<DEFAULT>" );
+		}
+
+		rc = ldap_initialize( &ld, ldapuri );
+		if( rc != LDAP_SUCCESS ) {
+			fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
+				rc, ldap_err2string(rc) );
+			return EXIT_FAILURE;
+		}
+	}
+
+	{
+		/* this seems prudent for searches below */
+		int deref = LDAP_DEREF_NEVER;
+		ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
+	}
+
+	/* chase referrals */
+	if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
+		referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
+			referrals ? "on" : "off" );
+		return EXIT_FAILURE;
 	}
-    } else {
+
+	if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
+		!= LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
+			version );
+		return EXIT_FAILURE;
+	}
+
+	if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
+		ldap_perror( ld, "ldap_start_tls" );
+		if ( use_tls > 1 ) {
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (want_bindpw) {
+		passwd.bv_val = getpassphrase("Enter LDAP Password: ");
+		passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
+	}
+
+	if ( authmethod == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+		void *defaults;
+
+		if( sasl_secprops != NULL ) {
+			rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
+				(void *) sasl_secprops );
+			
+			if( rc != LDAP_OPT_SUCCESS ) {
+				fprintf( stderr,
+					"Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
+					sasl_secprops );
+				return( EXIT_FAILURE );
+			}
+		}
+		
+		defaults = lutil_sasl_defaults( ld,
+			sasl_mech,
+			sasl_realm,
+			sasl_authc_id,
+			passwd.bv_val,
+			sasl_authz_id );
+
+		rc = ldap_sasl_interactive_bind_s( ld, binddn,
+			sasl_mech, NULL, NULL,
+			sasl_flags, lutil_sasl_interact, defaults );
+
+		if( rc != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
+			return( EXIT_FAILURE );
+		}
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	}
+	else {
+		if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
+				!= LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_bind" );
+			return( EXIT_FAILURE );
+		}
+	}
+
+	if ( manageDSAit ) {
+		int err;
+		LDAPControl c;
+		LDAPControl *ctrls[2];
+		ctrls[0] = &c;
+		ctrls[1] = NULL;
+
+		c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
+		c.ldctl_value.bv_val = NULL;
+		c.ldctl_value.bv_len = 0;
+		c.ldctl_iscritical = manageDSAit > 1;
+
+		err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
+
+		if( err != LDAP_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
+				c.ldctl_iscritical ? "critical " : "" );
+			if( c.ldctl_iscritical ) {
+				exit( EXIT_FAILURE );
+			}
+		}
+	}
+
 	rc = 0;
-	while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
-	    buf[ strlen( buf ) - 1 ] = '\0';	/* remove trailing newline */
-	    if ( *buf != '\0' ) {
-		rc = dodelete( ld, buf );
-	    }
+
+    if ( fp == NULL ) {
+		for ( ; optind < argc; ++optind ) {
+			rc = dodelete( ld, argv[ optind ] );
+
+			/* Stop on error and no -c option */
+			if( rc != 0 && contoper == 0) break;
+		}
+	} else {
+		while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
+			buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */
+
+			if ( *buf != '\0' ) {
+				rc = dodelete( ld, buf );
+			}
+		}
 	}
-    }
 
     ldap_unbind( ld );
 
-    exit( rc );
+	return( rc );
 }
 
 
-dodelete( ld, dn )
-    LDAP	*ld;
-    char	*dn;
+static int dodelete(
+    LDAP	*ld,
+    const char	*dn)
 {
-    int	rc;
+	int id;
+	int	rc, code;
+	char *matcheddn = NULL, *text = NULL, **refs = NULL;
+	LDAPMessage *res;
 
-    if ( verbose ) {
-	printf( "%sdeleting entry %s\n", not ? "!" : "", dn );
-    }
-    if ( not ) {
-	rc = LDAP_SUCCESS;
-    } else {
-	if (( rc = ldap_delete_s( ld, dn )) != LDAP_SUCCESS ) {
-	    ldap_perror( ld, "ldap_delete" );
-	} else if ( verbose ) {
-	    printf( "entry removed\n" );
+	if ( verbose ) {
+		printf( "%sdeleting entry \"%s\"\n",
+			(not ? "!" : ""), dn );
+	}
+
+	if ( not ) {
+		return LDAP_SUCCESS;
+	}
+
+	/* If prune is on, remove a whole subtree.  Delete the children of the
+	 * DN recursively, then the DN requested.
+	 */
+	if ( prune ) deletechildren( ld, dn );
+
+	rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
+	if ( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
+			prog, ldap_err2string( rc ), rc );
+		return rc;
+	}
+
+	rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
+	if ( rc < 0 ) {
+		ldap_perror( ld, "ldapdelete: ldap_result" );
+		return rc;
+	}
+
+	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 );
+
+	if( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
+			prog, ldap_err2string( rc ), rc );
+		return rc;
+	}
+
+	if( verbose || code != LDAP_SUCCESS ||
+		(matcheddn && *matcheddn) || (text && *text) || (refs && *refs) )
+	{
+		printf( "Delete Result: %s (%d)\n", ldap_err2string( code ), code );
+
+		if( text && *text ) {
+			printf( "Additional info: %s\n", text );
+		}
+
+		if( matcheddn && *matcheddn ) {
+			printf( "Matched DN: %s\n", matcheddn );
+		}
+
+		if( refs ) {
+			int i;
+			for( i=0; refs[i]; i++ ) {
+				printf("Referral: %s\n", refs[i] );
+			}
+		}
+	}
+
+	ber_memfree( text );
+	ber_memfree( matcheddn );
+	ber_memvfree( (void **) refs );
+
+	return code;
+}
+
+/*
+ * Delete all the children of an entry recursively until leaf nodes are reached.
+ *
+ */
+static int deletechildren(
+	LDAP *ld,
+	const char *dn )
+{
+	LDAPMessage *res, *e;
+	int entries;
+	int rc;
+	static char *attrs[] = { "1.1", NULL };
+
+	if ( verbose ) printf ( "deleting children of: %s\n", dn );
+	/*
+	 * Do a one level search at dn for children.  For each, delete its children.
+	 */
+
+	rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
+		NULL, NULL, NULL, -1, &res );
+	if ( rc != LDAP_SUCCESS ) {
+		ldap_perror( ld, "ldap_search" );
+		return( rc );
+	}
+
+	entries = ldap_count_entries( ld, res );
+
+	if ( entries > 0 ) {
+		int i;
+
+		for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
+			e = ldap_next_entry( ld, e ), i++ )
+		{
+			char *dn = ldap_get_dn( ld, e );
+
+			if( dn == NULL ) {
+				ldap_perror( ld, "ldap_prune" );
+				ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &rc );
+				ber_memfree( dn );
+				return rc;
+			}
+
+			rc = deletechildren( ld, dn );
+			if ( rc == -1 ) {
+				ldap_perror( ld, "ldap_prune" );
+				ber_memfree( dn );
+				return rc;
+			}
+
+			if ( verbose ) {
+				printf( "\tremoving %s\n", dn );
+			}
+
+			rc = ldap_delete_s( ld, dn );
+			if ( rc == -1 ) {
+				ldap_perror( ld, "ldap_delete" );
+				ber_memfree( dn );
+				return rc;
+
+			}
+			
+			if ( verbose ) {
+				printf( "\t%s removed\n", dn );
+			}
+
+			ber_memfree( dn );
+		}
 	}
-    }
 
-    return( rc );
+	ldap_msgfree( res );
+	return rc;
 }
diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c
index 427952c5fa..ed73a57b29 100644
--- a/clients/tools/ldapmodify.c
+++ b/clients/tools/ldapmodify.c
@@ -29,6 +29,7 @@
 
 #include <ldap.h>
 
+#include "lutil.h"
 #include "lutil_ldap.h"
 #include "ldif.h"
 #include "ldap_defaults.h"
@@ -146,11 +147,7 @@ main( int argc, char **argv )
 	int		rc, i, authmethod, version, want_bindpw, debug, manageDSAit, referrals;
 	int count, len;
 
-    if (( prog = strrchr( argv[ 0 ], *LDAP_DIRSEP )) == NULL ) {
-	prog = argv[ 0 ];
-    } else {
-	++prog;
-    }
+    prog = lutil_progname( "ldapmodify", argc, argv );
 
     /* Print usage when no parameters */
     if( argc < 2 ) usage( prog );
@@ -582,10 +579,6 @@ main( int argc, char **argv )
 	(void) SIGNAL( SIGPIPE, SIG_IGN );
 #endif
 
-#ifdef NEW_LOGGING
-    lutil_log_initialize( argc, argv );
-#endif
-
     if ( !not ) {
 	if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
 		if ( verbose ) {
diff --git a/clients/tools/ldapmodrdn.c b/clients/tools/ldapmodrdn.c
index 69d99e7f5a..b5d2d59283 100644
--- a/clients/tools/ldapmodrdn.c
+++ b/clients/tools/ldapmodrdn.c
@@ -1,144 +1,671 @@
-/* ldapmodrdn.c - generic program to modify an entry's RDN using LDAP */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+/* ldapmodrdn.c - generic program to modify an entry's RDN using LDAP.
+ *
+ * Support for MODIFYDN REQUEST V3 (newSuperior) by:
+ * 
+ * Copyright 1999, Juan C. Gomez, All rights reserved.
+ * This software is not subject to any license of Silicon Graphics 
+ * Inc. or Purdue University.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * without restriction or fee of any kind as long as this notice
+ * is preserved.
+ *
+ */
+
+#include "portable.h"
 
 #include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <lber.h>
-#include <ldap.h>
 
-#include "ldapconfig.h"
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
+#include <ac/signal.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+
+#include <ldap.h>
+#include "lutil.h"
+#include "lutil_ldap.h"
+#include "ldap_defaults.h"
 
-static char	*binddn = LDAPMODRDN_BINDDN;
-static char	*base = LDAPMODRDN_BASE;
-static char	*passwd = NULL;
-static char	*ldaphost = LDAPHOST;
-static int	ldapport = LDAP_PORT;
+static char *prog = NULL;
+static char	*binddn = NULL;
+static struct berval passwd = { 0, NULL };
+static char	*ldapuri = NULL;
+static char	*ldaphost = NULL;
+static int	ldapport = 0;
+#ifdef HAVE_CYRUS_SASL
+static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
+static char *sasl_realm = NULL;
+static char	*sasl_authc_id = NULL;
+static char	*sasl_authz_id = NULL;
+static char	*sasl_mech = NULL;
+static char	*sasl_secprops = NULL;
+#endif
+static int	use_tls = 0;
 static int	not, verbose, contoper;
-static LDAP	*ld;
+static LDAP	*ld = NULL;
 
-#ifdef LDAP_DEBUG
-extern int ldap_debug, lber_debug;
-#endif /* LDAP_DEBUG */
+static int domodrdn(
+    LDAP	*ld,
+    char	*dn,
+    char	*rdn,
+    char	*newSuperior,
+    int		remove );	/* flag: remove old RDN */
 
-#define safe_realloc( ptr, size )	( ptr == NULL ? malloc( size ) : \
-					 realloc( ptr, size ))
+static void
+usage( const char *s )
+{
+	fprintf( stderr,
+"Rename LDAP entries\n\n"
+"usage: %s [options] [dn rdn]\n"
+"	dn rdn: If given, rdn will replace the RDN of the entry specified by DN\n"
+"		If not given, the list of modifications is read from stdin or\n"
+"		from the file specified by \"-f file\" (see man page).\n"
+"Rename options:\n"
+"  -c         continuous operation mode (do not stop on errors)\n"
+"  -f file    read operations from `file'\n"
+"  -r         remove old RDN\n"
+"  -s newsup  new superior entry\n"
+
+"Common options:\n"
+"  -d level   set LDAP debugging level to `level'\n"
+"  -D binddn  bind DN\n"
+"  -f file    read operations from `file'\n"
+"  -h host    LDAP server\n"
+"  -H URI     LDAP Uniform Resource Indentifier(s)\n"
+"  -I         use SASL Interactive mode\n"
+"  -k         use Kerberos authentication\n"
+"  -K         like -k, but do only step 1 of the Kerberos bind\n"
+"  -M         enable Manage DSA IT control (-MM to make critical)\n"
+"  -n         show what would be done but don't actually update\n"
+"  -O props   SASL security properties\n"
+"  -p port    port on LDAP server\n"
+"  -P version procotol version (default: 3)\n"
+"  -Q         use SASL Quiet mode\n"
+"  -R realm   SASL realm\n"
+"  -U authzid SASL authentication identity\n"
+"  -v         run in verbose mode (diagnostics to standard output)\n"
+"  -w passwd  bind passwd (for simple authentication)\n"
+"  -W         prompt for bind passwd\n"
+"  -x         Simple authentication\n"
+"  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
+"  -Y mech    SASL mechanism\n"
+"  -Z         Start TLS request (-ZZ to require successful response)\n"
+,		s );
 
+	exit( EXIT_FAILURE );
+}
 
-main( argc, argv )
-    int		argc;
-    char	**argv;
+int
+main(int argc, char **argv)
 {
-    char		*usage = "usage: %s [-nvkc] [-d debug-level] [-h ldaphost] [-p ldapport] [-D binddn] [-w passwd] [ -f file | < entryfile | dn newrdn ]\n";
-    char		*myname,*infile, *p, *entrydn, *rdn, buf[ 4096 ];
+    char		*infile, *entrydn = NULL, *rdn = NULL, buf[ 4096 ];
     FILE		*fp;
-    int			rc, i, kerberos, remove, havedn, authmethod;
-    LDAPMod		**pmods;
-
-    extern char	*optarg;
-    extern int	optind;
+	int		rc, i, remove, havedn, authmethod, version, want_bindpw, debug, manageDSAit;
+	int		referrals;
+    char	*newSuperior=NULL;
 
     infile = NULL;
-    kerberos = not = contoper = verbose = remove = 0;
+    not = contoper = verbose = remove = want_bindpw =
+		debug = manageDSAit = referrals = 0;
+    authmethod = -1;
+	version = -1;
 
-    myname = (myname = strrchr(argv[0], '/')) == NULL ? argv[0] : ++myname;
+    prog = lutil_progname( "ldapmodrdn", argc, argv );
 
-    while (( i = getopt( argc, argv, "kKcnvrh:p:D:w:d:f:" )) != EOF ) {
+    while (( i = getopt( argc, argv, "cf:rs:"
+		"Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF )
+	{
 	switch( i ) {
-	case 'k':	/* kerberos bind */
-	    kerberos = 2;
+	/* Modrdn Options */
+	case 'c':
+		contoper++;
+		break;
+	case 'f':	/* read from file */
+		if( infile != NULL ) {
+			fprintf( stderr, "%s: -f previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    infile = strdup( optarg );
 	    break;
-	case 'K':	/* kerberos bind, part one only */
-	    kerberos = 1;
+	case 'r':	/* remove old RDN */
+	    remove++;
 	    break;
-	case 'c':	/* continuous operation mode */
-	    ++contoper;
+	case 's':	/* newSuperior */
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+	    newSuperior = strdup( optarg );
+	    version = LDAP_VERSION3;
 	    break;
-	case 'h':	/* ldap host */
-	    ldaphost = strdup( optarg );
+
+	/* Common Options */
+	case 'C':
+		referrals++;
+		break;
+	case 'd':
+	    debug |= atoi( optarg );
 	    break;
 	case 'D':	/* bind DN */
+		if( binddn != NULL ) {
+			fprintf( stderr, "%s: -D previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
 	    binddn = strdup( optarg );
 	    break;
-	case 'w':	/* password */
-	    passwd = strdup( optarg );
+	case 'h':	/* ldap host */
+		if( ldapuri != NULL ) {
+			fprintf( stderr, "%s: -h incompatible with -H\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldaphost != NULL ) {
+			fprintf( stderr, "%s: -h previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldaphost = strdup( optarg );
 	    break;
-	case 'd':
-#ifdef LDAP_DEBUG
-	    ldap_debug = lber_debug = atoi( optarg );	/* */
-#else /* LDAP_DEBUG */
-	    fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
-#endif /* LDAP_DEBUG */
+	case 'H':	/* ldap URI */
+		if( ldaphost != NULL ) {
+			fprintf( stderr, "%s: -H incompatible with -h\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldapport ) {
+			fprintf( stderr, "%s: -H incompatible with -p\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( ldapuri != NULL ) {
+			fprintf( stderr, "%s: -H previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldapuri = strdup( optarg );
 	    break;
-	case 'f':	/* read from file */
-	    infile = strdup( optarg );
+	case 'I':
+#ifdef HAVE_CYRUS_SASL
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -I incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_flags = LDAP_SASL_INTERACTIVE;
+		break;
+#else
+		fprintf( stderr, "%s: was not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	case 'k':	/* kerberos bind */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+		if( version > LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+
+		if( authmethod != -1 ) {
+			fprintf( stderr, "%s: -k incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+			
+		authmethod = LDAP_AUTH_KRBV4;
+#else
+		fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+		return EXIT_FAILURE;
+#endif
 	    break;
-	case 'p':
-	    ldapport = atoi( optarg );
+	case 'K':	/* kerberos bind, part one only */
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
+		if( version > LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 ) {
+			fprintf( stderr, "%s: incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+
+		authmethod = LDAP_AUTH_KRBV41;
+#else
+		fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
+		return( EXIT_FAILURE );
+#endif
 	    break;
-	case 'n':	/* print adds, don't actually do them */
+	case 'M':
+		/* enable Manage DSA IT */
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		manageDSAit++;
+		version = LDAP_VERSION3;
+		break;
+	case 'n':	/* print deletes, don't actually do them */
 	    ++not;
 	    break;
+	case 'O':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_secprops != NULL ) {
+			fprintf( stderr, "%s: -O previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_secprops = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'p':
+		if( ldapport ) {
+			fprintf( stderr, "%s: -p previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+	    ldapport = atoi( optarg );
+	    break;
+	case 'P':
+		switch( atoi(optarg) ) {
+		case 2:
+			if( version == LDAP_VERSION3 ) {
+				fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			version = LDAP_VERSION2;
+			break;
+		case 3:
+			if( version == LDAP_VERSION2 ) {
+				fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
+					prog, version );
+				return EXIT_FAILURE;
+			}
+			version = LDAP_VERSION3;
+			break;
+		default:
+			fprintf( stderr, "%s: protocol version should be 2 or 3\n",
+				prog );
+			usage( prog );
+			return( EXIT_FAILURE );
+		} break;
+	case 'Q':
+#ifdef HAVE_CYRUS_SASL
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Q incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_flags = LDAP_SASL_QUIET;
+		break;
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	case 'R':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_realm != NULL ) {
+			fprintf( stderr, "%s: -R previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -R incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_realm = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'U':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_authc_id != NULL ) {
+			fprintf( stderr, "%s: -U previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -U incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible previous "
+				"authentication choice\n",
+				prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_authc_id = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
 	case 'v':	/* verbose mode */
 	    verbose++;
 	    break;
-	case 'r':	/* remove old RDN */
-	    remove++;
+	case 'w':	/* password */
+	    passwd.bv_val = strdup( optarg );
+		{
+			char* p;
+
+			for( p = optarg; *p != '\0'; p++ ) {
+				*p = '\0';
+			}
+		}
+		passwd.bv_len = strlen( passwd.bv_val );
 	    break;
+	case 'W':
+		want_bindpw++;
+		break;
+	case 'Y':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_mech != NULL ) {
+			fprintf( stderr, "%s: -Y previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Y incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_mech = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'x':
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
+			fprintf( stderr, "%s: incompatible with previous "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SIMPLE;
+		break;
+	case 'X':
+#ifdef HAVE_CYRUS_SASL
+		if( sasl_authz_id != NULL ) {
+			fprintf( stderr, "%s: -X previously specified\n", prog );
+			return EXIT_FAILURE;
+		}
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
+			fprintf( stderr, "%s: -X incompatible with "
+				"authentication choice\n", prog );
+			return EXIT_FAILURE;
+		}
+		authmethod = LDAP_AUTH_SASL;
+		version = LDAP_VERSION3;
+		sasl_authz_id = strdup( optarg );
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
+	case 'Z':
+#ifdef HAVE_TLS
+		if( version == LDAP_VERSION2 ) {
+			fprintf( stderr, "%s: -Z incompatible with version %d\n",
+				prog, version );
+			return EXIT_FAILURE;
+		}
+		version = LDAP_VERSION3;
+		use_tls++;
+#else
+		fprintf( stderr, "%s: not compiled with TLS support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+		break;
 	default:
-	    fprintf( stderr, usage, argv[0] );
-	    exit( 1 );
+		fprintf( stderr, "%s: unrecognized option -%c\n",
+			prog, optopt );
+	    usage( prog );
+	    return( EXIT_FAILURE );
 	}
     }
 
+	if (version == -1) {
+		version = LDAP_VERSION3;
+	}
+	if (authmethod == -1 && version > LDAP_VERSION2) {
+#ifdef HAVE_CYRUS_SASL
+		authmethod = LDAP_AUTH_SASL;
+#else
+		authmethod = LDAP_AUTH_SIMPLE;
+#endif
+	}
+
     havedn = 0;
     if (argc - optind == 2) {
 	if (( rdn = strdup( argv[argc - 1] )) == NULL ) {
 	    perror( "strdup" );
-	    exit( 1 );
+	    return( EXIT_FAILURE );
 	}
         if (( entrydn = strdup( argv[argc - 2] )) == NULL ) {
 	    perror( "strdup" );
-	    exit( 1 );
+	    return( EXIT_FAILURE );
         }
 	++havedn;
     } else if ( argc - optind != 0 ) {
-	fprintf( stderr, "%s: invalid number of arguments, only two allowed\n", myname);
-	fprintf( stderr, usage, argv[0] );
-	exit( 1 );
+	fprintf( stderr, "%s: invalid number of arguments (%d), "
+		"only two allowed\n", prog, argc-optind );
+	usage( prog );
+	return( EXIT_FAILURE );
     }
 
     if ( infile != NULL ) {
 	if (( fp = fopen( infile, "r" )) == NULL ) {
 	    perror( infile );
-	    exit( 1 );
+	    return( EXIT_FAILURE );
 	}
     } else {
 	fp = stdin;
     }
 
-    if (( ld = ldap_open( ldaphost, ldapport )) == NULL ) {
-	perror( "ldap_open" );
-	exit( 1 );
-    }
+	if ( debug ) {
+		if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+		if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
+		}
+	}
 
-    ld->ld_deref = LDAP_DEREF_NEVER;	/* this seems prudent */
+#ifdef SIGPIPE
+	(void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
 
-    if ( !kerberos ) {
-	authmethod = LDAP_AUTH_SIMPLE;
-    } else if ( kerberos == 1 ) {
-	authmethod = LDAP_AUTH_KRBV41;
-    } else {
-	authmethod = LDAP_AUTH_KRBV4;
-    }
-    if ( ldap_bind_s( ld, binddn, passwd, authmethod ) != LDAP_SUCCESS ) {
-	ldap_perror( ld, "ldap_bind" );
-	exit( 1 );
-    }
+	if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_init( %s, %d )\n",
+				ldaphost != NULL ? ldaphost : "<DEFAULT>",
+				ldapport );
+		}
+
+		ld = ldap_init( ldaphost, ldapport );
+		if( ld == NULL ) {
+			perror("ldapmodify: ldap_init");
+			return EXIT_FAILURE;
+		}
+
+	} else {
+		if ( verbose ) {
+			fprintf( stderr, "ldap_initialize( %s )\n",
+				ldapuri != NULL ? ldapuri : "<DEFAULT>" );
+		}
+
+		rc = ldap_initialize( &ld, ldapuri );
+		if( rc != LDAP_SUCCESS ) {
+			fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
+				rc, ldap_err2string(rc) );
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* referrals */
+	if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
+		referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
+			referrals ? "on" : "off" );
+		return EXIT_FAILURE;
+	}
+
+	if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
+		!= LDAP_OPT_SUCCESS )
+	{
+		fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
+			version );
+		return EXIT_FAILURE;
+	}
+
+	if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
+		ldap_perror( ld, "ldap_start_tls" );
+		if ( use_tls > 1 ) {
+			return( EXIT_FAILURE );
+		}
+	}
+
+	if (want_bindpw) {
+		passwd.bv_val = getpassphrase("Enter LDAP Password: ");
+		passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
+	}
+
+	if ( authmethod == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+		void *defaults;
+
+		if( sasl_secprops != NULL ) {
+			rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
+				(void *) sasl_secprops );
+			
+			if( rc != LDAP_OPT_SUCCESS ) {
+				fprintf( stderr,
+					"Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
+					sasl_secprops );
+				return( EXIT_FAILURE );
+			}
+		}
+		
+		defaults = lutil_sasl_defaults( ld,
+			sasl_mech,
+			sasl_realm,
+			sasl_authc_id,
+			passwd.bv_val,
+			sasl_authz_id );
+
+		rc = ldap_sasl_interactive_bind_s( ld, binddn,
+			sasl_mech, NULL, NULL,
+			sasl_flags, lutil_sasl_interact, defaults );
+
+		if( rc != LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
+			return( EXIT_FAILURE );
+		}
+#else
+		fprintf( stderr, "%s: not compiled with SASL support\n",
+			prog );
+		return( EXIT_FAILURE );
+#endif
+	}
+	else {
+		if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
+				!= LDAP_SUCCESS ) {
+			ldap_perror( ld, "ldap_bind" );
+			return( EXIT_FAILURE );
+		}
+	}
+
+	if ( manageDSAit ) {
+		int err;
+		LDAPControl c;
+		LDAPControl *ctrls[2];
+		ctrls[0] = &c;
+		ctrls[1] = NULL;
+
+		c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
+		c.ldctl_value.bv_val = NULL;
+		c.ldctl_value.bv_len = 0;
+		c.ldctl_iscritical = manageDSAit > 1;
+
+		err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
+
+		if( err != LDAP_OPT_SUCCESS ) {
+			fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
+				c.ldctl_iscritical ? "critical " : "" );
+			if( c.ldctl_iscritical ) {
+				exit( EXIT_FAILURE );
+			}
+		}
+	}
 
     rc = 0;
     if (havedn)
-	rc = domodrdn(ld, entrydn, rdn, remove);
+	rc = domodrdn( ld, entrydn, rdn, newSuperior, remove );
     else while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
 	if ( *buf != '\0' ) {	/* blank lines optional, skip */
 	    buf[ strlen( buf ) - 1 ] = '\0';	/* remove nl */
@@ -146,14 +673,14 @@ main( argc, argv )
 	    if ( havedn ) {	/* have DN, get RDN */
 		if (( rdn = strdup( buf )) == NULL ) {
                     perror( "strdup" );
-                    exit( 1 );
+                    return( EXIT_FAILURE );
 		}
-		rc = domodrdn(ld, entrydn, rdn, remove);
+		rc = domodrdn(ld, entrydn, rdn, newSuperior, remove );
 		havedn = 0;
 	    } else if ( !havedn ) {	/* don't have DN yet */
 	        if (( entrydn = strdup( buf )) == NULL ) {
 		    perror( "strdup" );
-		    exit( 1 );
+		    return( EXIT_FAILURE );
 	        }
 		++havedn;
 	    }
@@ -162,35 +689,80 @@ main( argc, argv )
 
     ldap_unbind( ld );
 
-    exit( rc );
+	/* UNREACHABLE */
+	return( rc );
 }
 
-domodrdn( ld, dn, rdn, remove )
-    LDAP	*ld;
-    char	*dn;
-    char	*rdn;
-    int		remove;	/* flag: remove old RDN */
+static int domodrdn(
+    LDAP	*ld,
+    char	*dn,
+    char	*rdn,
+    char	*newSuperior,
+    int		remove ) /* flag: remove old RDN */
 {
-    int	i;
+	int rc, code, id;
+	char *matcheddn=NULL, *text=NULL, **refs=NULL;
+	LDAPMessage *res;
 
     if ( verbose ) {
-	printf( "modrdn %s:\n\t%s\n", dn, rdn );
-	if (remove)
-	    printf("removing old RDN\n");
-	else
-	    printf("keeping old RDN\n");
-    }
+		printf( "Renaming \"%s\"\n", dn );
+		printf( "\tnew rdn=\"%s\" (%s old rdn)\n",
+			rdn, remove ? "delete" : "keep" );
+		if( newSuperior != NULL ) {
+			printf("\tnew parent=\"%s\"\n", newSuperior);
+		}
+	}
+
+	if( not ) return LDAP_SUCCESS;
 
-    if ( !not ) {
-	i = ldap_modrdn2_s( ld, dn, rdn, remove );
-	if ( i != LDAP_SUCCESS ) {
-	    ldap_perror( ld, "ldap_modrdn2_s" );
-	} else if ( verbose ) {
-	    printf( "modrdn complete\n" );
+	rc = ldap_rename( ld, dn, rdn, newSuperior, remove,
+		NULL, NULL, &id );
+
+	if ( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "%s: ldap_rename: %s (%d)\n",
+			prog, ldap_err2string( rc ), rc );
+		return rc;
 	}
-    } else {
-	i = LDAP_SUCCESS;
-    }
 
-    return( i );
+	rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
+	if ( rc < 0 ) {
+		ldap_perror( ld, "ldapmodrdn: ldap_result" );
+		return rc;
+	}
+
+	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 );
+
+	if( rc != LDAP_SUCCESS ) {
+		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
+			prog, ldap_err2string( rc ), rc );
+		return rc;
+	}
+
+	if( verbose || code != LDAP_SUCCESS ||
+		(matcheddn && *matcheddn) || (text && *text) || (refs && *refs) )
+	{
+		printf( "Rename Result: %s (%d)\n",
+			ldap_err2string( code ), code );
+
+		if( text && *text ) {
+			printf( "Additional info: %s\n", text );
+		}
+
+		if( matcheddn && *matcheddn ) {
+			printf( "Matched DN: %s\n", matcheddn );
+		}
+
+		if( refs ) {
+			int i;
+			for( i=0; refs[i]; i++ ) {
+				printf("Referral: %s\n", refs[i] );
+			}
+		}
+	}
+
+	ber_memfree( text );
+	ber_memfree( matcheddn );
+	ber_memvfree( (void **) refs );
+
+	return code;
 }
diff --git a/clients/tools/ldappasswd.c b/clients/tools/ldappasswd.c
index 838eb0288e..f78d5ce5c4 100644
--- a/clients/tools/ldappasswd.c
+++ b/clients/tools/ldappasswd.c
@@ -18,7 +18,7 @@
 #include <ac/unistd.h>
 
 #include <ldap.h>
-
+#include "lutil.h"
 #include "lutil_ldap.h"
 #include "ldap_defaults.h"
 
@@ -107,7 +107,7 @@ main( int argc, char *argv[] )
 	char	*retoid = NULL;
 	struct berval *retdata = NULL;
 
-    prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1;
+    prog = lutil_progname( "ldappasswd", argc, argv );
 
 	while( (i = getopt( argc, argv, "Aa:Ss:"
 		"Cd:D:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF )
diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c
index 1ab31acdaa..0b3393e3c6 100644
--- a/clients/tools/ldapsearch.c
+++ b/clients/tools/ldapsearch.c
@@ -167,10 +167,8 @@ urlize(char *url)
 {
 	char *p;
 
-	if (*LDAP_DIRSEP != '/')
-	{
-		for (p = url; *p; p++)
-		{
+	if (*LDAP_DIRSEP != '/') {
+		for (p = url; *p; p++) {
 			if (*p == *LDAP_DIRSEP)
 				*p = '/';
 		}
@@ -196,6 +194,8 @@ main( int argc, char **argv )
 	debug = verbose = not = vals2tmp = referrals = valuesReturnFilter =
 		attrsonly = manageDSAit = ldif = want_bindpw = 0;
 
+	prog = lutil_progname( "ldapsearch", argc, argv );
+
 	lutil_log_initialize(argc, argv);
 
 	deref = sizelimit = timelimit = version = -1;
@@ -225,8 +225,6 @@ main( int argc, char **argv )
 
 	urlize( def_urlpre );
 
-    prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1;
-
 	while (( i = getopt( argc, argv, "Aa:b:E:F:f:Ll:S:s:T:tuz:"
 		"Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z")) != EOF )
 	{
@@ -1193,7 +1191,8 @@ print_entry(
 				{
 					int tmpfd;
 					/* write value to file */
-					sprintf( tmpfname, "%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX",
+					snprintf( tmpfname, sizeof tmpfname,
+						"%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX",
 						tmpdir, a );
 					tmpfp = NULL;
 
@@ -1219,7 +1218,7 @@ print_entry(
 
 					fclose( tmpfp );
 
-					sprintf( url, "%s%s", urlpre,
+					snprintf( url, sizeof url, "%s%s", urlpre,
 						&tmpfname[strlen(tmpdir) + sizeof(LDAP_DIRSEP) - 1] );
 
 					urlize( url );
diff --git a/clients/tools/ldapwhoami.c b/clients/tools/ldapwhoami.c
index d69e35faa4..58d926fb34 100644
--- a/clients/tools/ldapwhoami.c
+++ b/clients/tools/ldapwhoami.c
@@ -18,7 +18,7 @@
 #include <ac/unistd.h>
 
 #include <ldap.h>
-
+#include "lutil.h"
 #include "lutil_ldap.h"
 #include "ldap_defaults.h"
 
@@ -100,7 +100,7 @@ main( int argc, char *argv[] )
 	char	*retoid = NULL;
 	struct berval *retdata = NULL;
 
-    prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1;
+	prog = lutil_progname( "ldapwhoami", argc, argv );
 
 	while( (i = getopt( argc, argv, "Aa:Ss:"
 		"Cd:D:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF )
-- 
GitLab