]> git.sur5r.net Git - openldap/blobdiff - clients/tools/ldappasswd.c
Update copyright statements
[openldap] / clients / tools / ldappasswd.c
index fad4c106db3ceb0f63d142c340757122fd2f9c89..a5cfa4aa387892a01e125eb24a79162919c94def 100644 (file)
+/* $OpenLDAP$ */
 /*
- *     Copyright 1998, David E. Storey, All rights reserved.
- *     This software is not subject to any license of The Murphy Group, Inc.
- *     or George Mason University.
- *
- *     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.
- *
- *     ldappasswd.c - program to modify passwords in an LDAP tree
- *
- *     Author: David E. Storey <dave@tamos.net>
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
 #include "portable.h"
 
-#include <ctype.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
 
+#include <ac/stdlib.h>
+
+#include <ac/ctype.h>
 #include <ac/signal.h>
+#include <ac/socket.h>
 #include <ac/string.h>
+#include <ac/time.h>
 #include <ac/unistd.h>
 
-#include <lber.h>
 #include <ldap.h>
-#include <lutil.h>
-#include <lutil_md5.h>
-#include <lutil_sha1.h>
-
-#include "ldapconfig.h"
-
-/* local macros */
-#define CEILING(x)     ((double)(x) > (int)(x) ? (int)(x) + 1 : (int)(x))
-#define STRDUP(x)      ((x) ? strcpy(malloc(strlen(x) + 1), x) : NULL)
 
-#define LDAP_PASSWD_ATTRIB "userPassword"
-#define LDAP_PASSWD_CONF   DEFAULT_SYSCONFDIR"/passwd.conf"
+#include "lutil_ldap.h"
+#include "ldap_defaults.h"
 
-#define HS_NONE  0
-#define HS_PLAIN 1
-#define HS_CONV  2
+static int     verbose = 0;
 
-typedef enum
+static void
+usage(const char *s)
 {
-       HASHTYPE_NONE,
-       HASHTYPE_CRYPT,
-       HASHTYPE_MD5,
-       HASHTYPE_SMD5,
-       HASHTYPE_SHA1,
-       HASHTYPE_SSHA1
+       fprintf(stderr,
+"Change password of an LDAP user\n\n"
+"usage: %s [options] [user]\n"
+"  user: the autentication identity, commonly a DN\n"
+"Password change options:\n"
+"  -a secret  old password\n"
+"  -A         prompt for old password\n"
+"  -s secret  new password\n"
+"  -S         prompt for new password\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(s)\n"
+"  -H URI     LDAP Uniform Resource Indentifier(s)\n"
+"  -I         use SASL Interactive mode\n"
+"  -n         show what would be done but don't actually search\n"
+"  -O props   SASL security properties\n"
+"  -p port    port on LDAP server\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 );
 }
-HashTypes;
 
-typedef struct salt_t
+int
+main( int argc, char *argv[] )
 {
-       unsigned char  *salt;
-       unsigned int    len;
-}
-Salt;
+       int rc;
+       char    *prog = NULL;
+       char    *ldaphost = NULL;
+       char    *ldapuri = NULL;
 
-typedef struct hash_t
-{
-       char           *name;
-       unsigned int    namesz;
-       char           *(*func) (const char *, Salt *);
-       unsigned char   takes_salt;
-       HashTypes       type;
-       HashTypes       type_salted;
-       unsigned int    default_salt_len;
-}
-Hash;
+       char    *user = NULL;
+       char    *binddn = NULL;
 
-static int     noupdates = 0;
-static int     verbose = 0;
-static int     want_entryhash = 0;
-static int     auto_gen_pw = 0;
+       struct berval passwd = { 0, NULL };
+       char    *newpw = NULL;
+       char    *oldpw = NULL;
 
-/*** functions ***/
+       int             want_bindpw = 0;
+       int             want_newpw = 0;
+       int             want_oldpw = 0;
 
-/*
- * pw_encode() essentially base64 encodes a password and its salt
- */
+       int             not = 0;
+       int             i;
+       int             ldapport = 0;
+       int             debug = 0;
+       int             version = -1;
+       int             authmethod = -1;
+       int             manageDSAit = 0;
+#ifdef HAVE_CYRUS_SASL
+       unsigned        sasl_flags = LDAP_SASL_AUTOMATIC;
+       char            *sasl_realm = NULL;
+       char            *sasl_authc_id = NULL;
+       char            *sasl_authz_id = NULL;
+       char            *sasl_mech = NULL;
+       char            *sasl_secprops = NULL;
+#endif
+       int             use_tls = 0;
+       int             referrals = 0;
+       LDAP           *ld = NULL;
+       struct berval *bv = NULL;
 
-char *
-pw_encode (unsigned char *passwd, Salt * salt, unsigned int len)
-{
-       int             salted = salt && salt->salt && salt->len;
-       int             b64_len = 0;
-       char           *base64digest = NULL;
-       unsigned char  *npasswd = passwd;
+       int id, code;
+       LDAPMessage *res;
+       char *matcheddn = NULL, *text = NULL, **refs = NULL;
+       char    *retoid = NULL;
+       struct berval *retdata = NULL;
 
-       if (salted)
-       {
-               npasswd = (unsigned char *)malloc (len + salt->len);
-               memcpy (npasswd, passwd, len);
-               memcpy (&npasswd[len], salt->salt, salt->len);
-               len += salt->len;
-       }
+    prog = (prog = strrchr(argv[0], *LDAP_DIRSEP)) == NULL ? argv[0] : prog + 1;
 
-       b64_len = CEILING (len / 3) * 4 + 1;
-       base64digest = (char *)malloc (b64_len);
-       if (lutil_b64_ntop (npasswd, len, base64digest, b64_len) < 0)
+       while( (i = getopt( argc, argv, "Aa:Ss:"
+               "Cd:D:h:H:InO:p:QR:U:vw:WxX:Y:Z" )) != EOF )
        {
-               free (base64digest);
-               base64digest = NULL;
-       }
-
-       if (salted)
-               free (npasswd);
-
-       return (base64digest);
-}
-
-/*
- * if you'd like to write a better salt generator, please, be my guest.
- */
-
-void
-make_salt (Salt * salt, unsigned int len)
-{
-       struct timeval  tv;
-
-       if (!salt)
-               return;
-
-       /* seed random number generator */
-       gettimeofday (&tv, NULL);
-       srand (tv.tv_usec);
+               switch (i) {
+               /* Password Options */
+               case 'A':       /* prompt for old password */
+                       want_oldpw++;
+                       break;
 
-       salt->len = len;
-       salt->salt = (unsigned char *)malloc (len);
+               case 'a':       /* old password (secret) */
+                       oldpw = strdup (optarg);
 
-       for (len = 0; len < salt->len; len++)
-               salt->salt[len] = (tv.tv_usec ^ rand ()) & 0xff;
-}
-
-/*
- * password generator
- */
+                       {
+                               char* p;
 
-char *
-gen_pass (unsigned int len)
-{
-       static const unsigned char autogen[] =
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.,";
-       unsigned int i;
-       Salt            salt;
+                               for( p = optarg; *p != '\0'; p++ ) {
+                                       *p = '\0';
+                               }
+                       }
+                       break;
 
-       salt.salt = NULL;
-       salt.len = 0;
+               case 'S':       /* prompt for user password */
+                       want_newpw++;
+                       break;
 
-       make_salt (&salt, len);
-       for (i = 0; i < len; i++)
-               salt.salt[i] = autogen[salt.salt[i] % (sizeof (autogen) - 1)];
+               case 's':       /* new password (secret) */
+                       newpw = strdup (optarg);
+                       {
+                               char* p;
 
-       return ((char *)salt.salt);
-}
+                               for( p = optarg; *p != '\0'; p++ ) {
+                                       *p = '\0';
+                               }
+                       }
+                       break;
 
-#ifdef SLAPD_CLEARTEXT
-char *
-hash_none (const char *pw_in, Salt * salt)
-{
-       return (STRDUP (pw_in));
-}
+       /* Common Options (including options we don't use) */
+       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;
+               }
 
-#ifdef SLAPD_CRYPT
-char *
-hash_crypt (const char *pw_in, Salt * salt)
-{
-       static const unsigned char crypt64[] =
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
-       char   *crypted_pw = NULL;
-       Salt    lsalt;
-
-       if (salt && salt->salt && strlen ((char *)salt->salt) >= 2)
-       {
-               /* sanity check */
-               if (!(isalnum(salt->salt[0]) || salt->salt[0] == '.' || salt->salt[0] == '/'))
-                       salt->salt[0] = crypt64[salt->salt[0] % (sizeof (crypt64) - 1)];
-               if (!(isalnum(salt->salt[1]) || salt->salt[1] == '.' || salt->salt[1] == '/'))
-                       salt->salt[1] = crypt64[salt->salt[1] % (sizeof (crypt64) - 1)];
-
-               crypted_pw = crypt (pw_in, (char *)salt->salt);
-       }
-       else
-       {
-               make_salt (&lsalt, 2);
-               lsalt.salt[0] = crypt64[lsalt.salt[0] % (sizeof (crypt64) - 1)];
-               lsalt.salt[1] = crypt64[lsalt.salt[1] % (sizeof (crypt64) - 1)];
-               crypted_pw = crypt (pw_in, (char *)lsalt.salt);
-               free (lsalt.salt);
-       }
-       return (STRDUP (crypted_pw));
-}
+               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;
+               }
 
-char *
-hash_md5 (const char *pw_in, Salt * salt)
-{
-       lutil_MD5_CTX   MD5context;
-       unsigned char   MD5digest[16];
-
-       lutil_MD5Init (&MD5context);
-       lutil_MD5Update (&MD5context,
-                        (const unsigned char *)pw_in, strlen(pw_in));
-       if (salt && salt->salt && salt->len)
-               lutil_MD5Update (&MD5context, salt->salt, salt->len);
-       lutil_MD5Final (MD5digest, &MD5context);
-
-       return (pw_encode (MD5digest, salt, sizeof (MD5digest)));
-}
-
-char *
-hash_sha1 (const char *pw_in, Salt * salt)
-{
-       lutil_SHA1_CTX  SHA1context;
-       unsigned char   SHA1digest[20];
-
-       lutil_SHA1Init (&SHA1context);
-       lutil_SHA1Update (&SHA1context,
-                         (const unsigned char *)pw_in, strlen(pw_in));
-       if (salt && salt->salt && salt->len)
-               lutil_SHA1Update (&SHA1context, salt->salt, salt->len);
-       lutil_SHA1Final (SHA1digest, &SHA1context);
-
-       return (pw_encode (SHA1digest, salt, sizeof (SHA1digest)));
-}
+               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;
 
-static Hash hashes[] =
-{
-#ifdef SLAPD_CLEARTEXT
-       {"none",  4, hash_none,  0, HASHTYPE_NONE,  HASHTYPE_NONE,  0},
+                       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
-#ifdef SLAPD_CRYPT
-       {"crypt", 5, hash_crypt, 1, HASHTYPE_CRYPT, HASHTYPE_CRYPT, 2},
+               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
-       {"md5",   3, hash_md5,   0, HASHTYPE_MD5,   HASHTYPE_SMD5,  0},
-       {"smd5",  4, hash_md5,   1, HASHTYPE_SMD5,  HASHTYPE_SMD5,  4},
-       {"sha",   3, hash_sha1,  0, HASHTYPE_SHA1,  HASHTYPE_SSHA1, 0},
-       {"ssha",  4, hash_sha1,  1, HASHTYPE_SSHA1, HASHTYPE_SSHA1, 4},
-       {NULL,    0, NULL,       0, HASHTYPE_NONE,  HASHTYPE_NONE,  0}
-};
+               break;
 
-int
-modify_dn (LDAP * ld, char *targetdn, char *pwattr, char *oldpw,
-          char *newpw, HashTypes htype, Salt * salt)
-{
-       int             ret = 0;
-       int             salted = salt->salt ? 1 : 0;
-       int             want_salt = salt->len && !salted;
-       char           *buf = NULL;
-       char           *hashed_pw = NULL;
-       char           *strvals[2];
-       LDAPMod         mod, *mods[2];
-
-       if (!ld || !targetdn || !newpw)
-               return (1);
-
-       /* auto-generate password */
-       if (auto_gen_pw)
-               newpw = gen_pass (auto_gen_pw);
-
-       /* handle salt */
-       if (want_salt)
-       {
-               make_salt (salt, salt->len);
-               htype = hashes[htype].type_salted;
-       }
-       else if (hashes[htype].default_salt_len)
-       {
-               /* user chose a salted hash and needs a salt */
-               if (!salted)
-               {
-                       want_salt++;
-                       salt->len = hashes[htype].default_salt_len;
-                       make_salt (salt, salt->len);
+
+               default:
+                       fprintf( stderr, "%s: unrecognized option -%c\n",
+                               prog, optopt );
+                       usage (prog);
                }
        }
 
-       /* hash password */
-       hashed_pw = hashes[htype].func (newpw, salt->len ? salt : NULL);
+       if (authmethod == -1) {
+#ifdef HAVE_CYRUS_SASL
+               authmethod = LDAP_AUTH_SASL;
+#else
+               authmethod = LDAP_AUTH_SIMPLE;
+#endif
+       }
 
-       /* return salt back to its original state */
-       if (want_salt)
-       {
-               free (salt->salt);
-               salt->salt = NULL;
+       if( argc - optind > 1 ) {
+               usage( prog );
+       } else if ( argc - optind == 1 ) {
+               user = strdup( argv[optind] );
+       } else {
+               user = NULL;
        }
 
-       buf = (char *)malloc (hashes[htype].namesz + 3 + strlen (hashed_pw));
-       if (htype)
-               sprintf (buf, "{%s}%s", hashes[htype].name, hashed_pw);
-       else
-               sprintf (buf, "%s", hashed_pw);
+       if( want_oldpw && oldpw == NULL ) {
+               /* prompt for old password */
+               char *ckoldpw;
+               oldpw = strdup(getpassphrase("Old password: "));
+               ckoldpw = getpassphrase("Re-enter old password: ");
 
-       if (verbose > 0)
-       {
-               printf ("%s", targetdn);
-               if (verbose > 1)
+               if( oldpw== NULL || ckoldpw == NULL ||
+                       strcmp( oldpw, ckoldpw ))
                {
-                       printf (":%s", buf);
-                       if (verbose > 2)
-                               printf (":%s", newpw);
+                       fprintf( stderr, "passwords do not match\n" );
+                       return EXIT_FAILURE;
                }
-               printf ("\n");
        }
 
-       strvals[0] = buf;
-       strvals[1] = NULL;
-       mod.mod_vals.modv_strvals = strvals;
-       mod.mod_type = pwattr;
-       mod.mod_op = LDAP_MOD_REPLACE;
-       mods[0] = &mod;
-       mods[1] =NULL;
-
-       if (!noupdates && (ret = ldap_modify_s (ld, targetdn, mods)) != LDAP_SUCCESS)
-               ldap_perror (ld, "ldap_modify");
-
-       free (hashed_pw);
-       free (buf);
-       return (ret);
-}
-
-void
-usage (char *s)
-{
-       fprintf (stderr, "Usage: %s [options] [filter]\n", s);
-       fprintf (stderr, "  -a attrib\tpassword attribute (default: %s)\n", LDAP_PASSWD_ATTRIB);
-       fprintf (stderr, "  -b basedn\tbasedn to perform searches\n");
-/*      fprintf (stderr, "  -C\t\tuse entry's current hash mechanism\n"); */
-       fprintf (stderr, "  -D binddn\tbind dn\n");
-       fprintf (stderr, "  -d level\tdebugging level\n");
-       fprintf (stderr, "  -E\t\tprompt for new password\n");
-       fprintf (stderr, "  -e passwd\tnew password\n");
-       fprintf (stderr, "  -g passlen\tauto-generate passwords with length pwlen\n");
-       fprintf (stderr, "  -H hash\thash type (default: crypt)\n");
-       fprintf (stderr, "  -h host\tldap server (default: localhost)\n");
-#ifdef HAVE_KERBEROS
-       fprintf (stderr, "  -K\t\tuse Kerberos step 1\n");
-       fprintf (stderr, "  -k\t\tuse Kerberos\n");
-#endif
-       fprintf (stderr, "  -l time\ttime limit\n");
-       fprintf (stderr, "  -n\t\tmake no modifications\n");
-       fprintf (stderr, "  -P version\tprotocol version (2 or 3)\n");
-       fprintf (stderr, "  -p port\tldap port\n");
-       fprintf (stderr, "  -s scope\tsearch scope: base, one, sub (default: sub)\n");
-       fprintf (stderr, "  -t targetdn\tdn to change password\n");
-       fprintf (stderr, "  -v\t\tverbose (more v's, more verbose)\n");
-       fprintf (stderr, "  -W\t\tprompt for bind password\n");
-       fprintf (stderr, "  -w passwd\tbind password (for simple authentication)\n");
-       fprintf (stderr, "  -Y saltlen\tsalt length to use\n");
-/*      fprintf (stderr, "  -y salt\tsalt to use\n"); */
-       fprintf (stderr, "  -z size\tsize limit\n");
-       exit (1);
-}
+       if( want_newpw && newpw == NULL ) {
+               /* prompt for new password */
+               char *cknewpw;
+               newpw = strdup(getpassphrase("New password: "));
+               cknewpw = getpassphrase("Re-enter new password: ");
 
-int
-main (int argc, char *argv[])
-{
-       char           *base = NULL;
-       char           *binddn = NULL;
-       char           *bindpw = NULL;
-       char           *filtpattern = NULL;
-       char           *ldaphost = NULL;
-       char           *targetdn = NULL;
-       char           *pwattr = LDAP_PASSWD_ATTRIB;
-       char           *newpw = NULL;
-       int             authmethod = LDAP_AUTH_SIMPLE;
-       int             hashtype = HASHTYPE_CRYPT;
-       int             i, j;
-       int             ldapport = 0;
-       int             debug = 0;
-       int             scope = LDAP_SCOPE_SUBTREE;
-       int             sizelimit = -1;
-       int             timelimit = -1;
-       int             version = -1;
-       int             want_bindpw = 0;
-       int             want_newpw = 0;
-       LDAP           *ld;
-       Salt            salt;
+               if( newpw== NULL || cknewpw == NULL ||
+                       strcmp( newpw, cknewpw ))
+               {
+                       fprintf( stderr, "passwords do not match\n" );
+                       return EXIT_FAILURE;
+               }
+       }
 
-       salt.salt = NULL;
-       salt.len = 0;
+       if (want_bindpw && passwd.bv_val == NULL ) {
+               /* handle bind password */
+               passwd.bv_val = strdup( getpassphrase("Enter bind password: "));
+               passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
+       }
 
-       if (argc == 1)
-               usage (argv[0]);
+       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 );
+               }
+       }
 
-       while ((i = getopt (argc, argv, "a:b:C:D:d:Ee:g:H:h:Kkl:nP:p:s:t:vWw:Y:y:z:")) != EOF)
-       {
-               switch (i)
-               {
-               case 'a':       /* password attribute */
-                       pwattr = STRDUP (optarg);
-                       break;
+#ifdef SIGPIPE
+       (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
 
-               case 'b':       /* base search dn */
-                       base = STRDUP (optarg);
-                       break;
+       /* connect to server */
+       if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
+               if ( verbose ) {
+                       fprintf( stderr, "ldap_init( %s, %d )\n",
+                               ldaphost != NULL ? ldaphost : "<DEFAULT>",
+                               ldapport );
+               }
 
-               case 'C':
-                       want_entryhash++;
-                       break;
+               ld = ldap_init( ldaphost, ldapport );
+               if( ld == NULL ) {
+                       perror("ldapsearch: ldap_init");
+                       return EXIT_FAILURE;
+               }
 
-               case 'D':       /* bind distinguished name */
-                       binddn = STRDUP (optarg);
-                       break;
+       } else {
+               if ( verbose ) {
+                       fprintf( stderr, "ldap_initialize( %s )\n",
+                               ldapuri != NULL ? ldapuri : "<DEFAULT>" );
+               }
 
-               case 'd':       /* debugging option */
-                       debug |= atoi (optarg);
-                       break;
+               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;
+               }
+       }
 
-               case 'E':       /* prompt for new password */
-                       want_newpw++;
-                       break;
+       /* 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;
+       }
 
-               case 'e':       /* new password */
-                       newpw = STRDUP (optarg);
-                       break;
+       /* LDAPv3 only */
+       version = LDAP_VERSION3;
+       rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
 
-               case 'g':
-                       auto_gen_pw = strtol (optarg, NULL, 10);
-                       break;
+       if(rc != LDAP_OPT_SUCCESS ) {
+               fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
+               return EXIT_FAILURE;
+       }
 
-               case 'H':       /* hashes */
-                       for (j = 0; hashes[j].name; j++)
-                       {
-                               if (!strncasecmp (optarg, hashes[j].name, hashes[j].namesz))
-                               {
-                                       hashtype = hashes[j].type;
-                                       break;
-                               }
-                       }
+       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 (!hashes[j].name)
-                       {
-                               fprintf (stderr, "hash type: %s is unknown\n", optarg);
-                               usage (argv[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 );
                        }
-                       break;
-
-               case 'h':       /* ldap host */
-                       ldaphost = STRDUP (optarg);
-                       break;
-
-               case 'K':       /* use kerberos bind, 1st part only */
-#ifdef HAVE_KERBEROS
-                       authmethod = LDAP_AUTH_KRBV41;
+               }
+               
+               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 was not compiled with Kerberos support\n", argv[0]);
+               fprintf( stderr, "%s: not compiled with SASL support\n",
+                       prog );
+               return( EXIT_FAILURE );
 #endif
-                       break;
+       }
+       else {
+               if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
+                               != LDAP_SUCCESS ) {
+                       ldap_perror( ld, "ldap_bind" );
+                       return( EXIT_FAILURE );
+               }
+       }
 
-               case 'k':       /* use kerberos bind */
-#ifdef HAVE_KERBEROS
-                       authmethod = LDAP_AUTH_KRBV4;
-#else
-                       fprintf (stderr, "%s was not compiled with Kerberos support\n", argv[0]);
-#endif
-                       break;
+       if( user != NULL || oldpw != NULL || newpw != NULL ) {
+               /* build change password control */
+               BerElement *ber = ber_alloc_t( LBER_USE_DER );
 
-               case 'l':       /* time limit */
-                       timelimit = strtol (optarg, NULL, 10);
-                       break;
+               if( ber == NULL ) {
+                       perror( "ber_alloc_t" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
+               }
 
-               case 'n':       /* don't update entry(s) */
-                       noupdates++;
-                       break;
+               ber_printf( ber, "{" /*}*/ );
 
-               case 'P':
-                       switch(optarg[0])
-                       {
-                       case '2':
-                               version = LDAP_VERSION2;
-                               break;
-                       case '3':
-                               version = LDAP_VERSION3;
-                               break;
-                       }
-                       break;
+               if( user != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, user );
+                       free(user);
+               }
 
-               case 'p':       /* ldap port */
-                       ldapport = strtol (optarg, NULL, 10);
-                       break;
+               if( oldpw != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_OLD, oldpw );
+                       free(oldpw);
+               }
 
-               case 's':       /* scope */
-                       if (strncasecmp (optarg, "base", 4) == 0)
-                               scope = LDAP_SCOPE_BASE;
-                       else if (strncasecmp (optarg, "one", 3) == 0)
-                               scope = LDAP_SCOPE_ONELEVEL;
-                       else if (strncasecmp (optarg, "sub", 3) == 0)
-                               scope = LDAP_SCOPE_SUBTREE;
-                       else
-                       {
-                               fprintf (stderr, "scope should be base, one, or sub\n");
-                               usage (argv[0]);
-                       }
-                       break;
+               if( newpw != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, newpw );
+                       free(newpw);
+               }
 
-               case 't':       /* target dn */
-                       targetdn = STRDUP (optarg);
-                       break;
+               ber_printf( ber, /*{*/ "N}" );
 
-               case 'v':       /* verbose */
-                       verbose++;
-                       break;
+               rc = ber_flatten( ber, &bv );
 
-               case 'W':       /* promt for bind password */
-                       want_bindpw++;
-                       break;
+               if( rc < 0 ) {
+                       perror( "ber_flatten" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
+               }
 
-               case 'w':       /* bind password */
-                       bindpw = STRDUP (optarg);
-                       break;
+               ber_free( ber, 1 );
+       }
 
-               case 'Y':       /* salt length */
-                       salt.len = strtol (optarg, NULL, 10);
-                       break;
+       if ( not ) {
+               rc = LDAP_SUCCESS;
+               goto skip;
+       }
 
-               case 'y':       /* user specified salt */
-                       salt.len = strlen (optarg);
-                       salt.salt = (unsigned char *)STRDUP (optarg);
-                       break;
+       rc = ldap_extended_operation( ld,
+               LDAP_EXOP_X_MODIFY_PASSWD, bv, 
+               NULL, NULL, &id );
 
-               case 'z':       /* time limit */
-                       sizelimit = strtol (optarg, NULL, 10);
-                       break;
+       ber_bvfree( bv );
 
-               default:
-                       usage (argv[0]);
-               }
+       if( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_extended_operation" );
+               ldap_unbind( ld );
+               return EXIT_FAILURE;
        }
 
-       /* grab filter */
-       if (!(argc - optind < 1))
-               filtpattern = STRDUP (argv[optind]);
-
-       /* check for target(s) */
-       if (!filtpattern && !targetdn)
-               targetdn = binddn;
-
-       /* handle bind password */
-       if (want_bindpw)
-               bindpw = strdup (getpass ("Enter LDAP password: "));
+       rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
+       if ( rc < 0 ) {
+               ldap_perror( ld, "ldappasswd: ldap_result" );
+               return rc;
+       }
 
-       /* handle new password */
-       if (!newpw)
-       {
-               char *cknewpw;
-               newpw = strdup (getpass ("New password: "));
-               cknewpw = getpass ("Re-enter new password: ");
+       rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 0 );
 
-               if (strncmp (newpw, cknewpw, strlen (newpw)))
-               {
-                       fprintf (stderr, "passwords do not match\n");
-                       exit (1);
-               }
+       if( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_parse_result" );
+               return rc;
        }
 
-       if ( debug ) {
-               lber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug );
-               ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug );
+       rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 1 );
+
+       if( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_parse_result" );
+               return rc;
        }
 
-#ifdef SIGPIPE
-       (void) SIGNAL( SIGPIPE, SIG_IGN );
-#endif
+       if( retdata != NULL ) {
+               ber_tag_t tag;
+               char *s;
+               BerElement *ber = ber_init( retdata );
 
-       /* connect to server */
-       if ((ld = ldap_init (ldaphost, ldapport)) == NULL)
-       {
-               perror ("ldap_init");
-               exit (1);
-       }
+               if( ber == NULL ) {
+                       perror( "ber_init" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
+               }
 
-       /* set options */
-       if( timelimit != -1 ) {
-               ldap_set_option (ld, LDAP_OPT_TIMELIMIT, (void *)&timelimit);
-       }
-       if( sizelimit != -1 ) {
-               ldap_set_option (ld, LDAP_OPT_SIZELIMIT, (void *)&sizelimit);
-       }
+               /* we should check the tag */
+               tag = ber_scanf( ber, "{a}", &s);
 
-       /* this seems prudent */
-       {
-               int deref = LDAP_DEREF_NEVER;
-               ldap_set_option( ld, LDAP_OPT_DEREF, &deref);
-       }
+               if( tag == LBER_ERROR ) {
+                       perror( "ber_scanf" );
+               } else {
+                       printf("New password: %s\n", s);
+                       free( s );
+               }
 
-       if( version != -1 ) {
-               ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+               ber_free( ber, 1 );
        }
 
-       /* authenticate to server */
-       if (ldap_bind_s (ld, binddn, bindpw, authmethod) != LDAP_SUCCESS)
-       {
-               ldap_perror (ld, "ldap_bind");
-               exit (1);
-       }
+       if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) {
+               printf( "Result: %s (%d)\n", ldap_err2string( code ), code );
 
-       if (targetdn)
-       {
-               if (want_entryhash)
-               {
-                       /* insert code here =) */
+               if( text && *text ) {
+                       printf( "Additional info: %s\n", text );
                }
-               else
-                       modify_dn (ld, targetdn, pwattr, NULL, newpw, hashtype, &salt);
-       }
 
-       if (filtpattern)
-       {
-               char            filter[BUFSIZ];
-               LDAPMessage     *result = NULL, *e;
-               char            *attrs[3];
-               attrs[0] = "dn";
-               attrs[1] = pwattr;
-               attrs[2] = NULL;
-
-               /* search */
-               sprintf (filter, "%s", filtpattern);
-               i = ldap_search_s (ld, base, scope, filter, attrs, 0, &result);
-               if (i != LDAP_SUCCESS &&
-                   i != LDAP_TIMELIMIT_EXCEEDED &&
-                   i != LDAP_SIZELIMIT_EXCEEDED)
-               {
-                       ldap_perror (ld, "ldap_search");
-                       exit (1);
+               if( matcheddn && *matcheddn ) {
+                       printf( "Matched DN: %s\n", matcheddn );
                }
 
-               for (e = ldap_first_entry (ld, result); e; e = ldap_next_entry (ld, e))
-               {
-                       char *dn = ldap_get_dn (ld, e);
-                       if (dn)
-                       {
-                               struct berval **pw_vals = ldap_get_values_len (ld, e, pwattr);
-                               modify_dn (ld, dn, pwattr, pw_vals ? pw_vals[0]->bv_val : NULL, newpw, hashtype, &salt);
-                               if (pw_vals)
-                                       ldap_value_free_len (pw_vals);
-                               free (dn);
+               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 );
+       ber_memfree( retoid );
+       ber_bvfree( retdata );
+
+skip:
        /* disconnect from server */
        ldap_unbind (ld);
-       exit(0);
 
-       /* unreached */
-       return (0);
+       return EXIT_SUCCESS;
 }