]> git.sur5r.net Git - openldap/blobdiff - clients/tools/ldappasswd.c
Initial implementation of Kerberos password verification for
[openldap] / clients / tools / ldappasswd.c
index 2214938b6f158a017d1e7bc2d78bf2d58c35f290..04b4d469c99f0d5e9e8d55435c6e6de421601578 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
- *
- *     Created: 1998-11-26
- *     Author: David E. Storey <dave@tamos.net>
- *     Last Modified: 1998-12-05
- *
- *             ToDo: passwd style change of password (termcap?)
- *                     option for referral handling
- *                     cracklib support?
- *                     kerberos support? (is this really necessary?)
- *                     update "shadow" fields?
- *                     create/view/change password policies?
- *
- *               Note: I am totally FOR comments and suggestions!
+ * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
 #include "portable.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"
-
-#define LDAP_PASSWD_ATTRIB "userPassword"
-
-typedef enum {
-       HASHTYPE_NONE,
-       HASHTYPE_CRYPT,
-       HASHTYPE_MD5,
-       HASHTYPE_SHA1
-} HashTypes;
-
-struct hash_t {
-       char *name;
-       int namesz;
-       int (*func)(const char *, char *);
-       HashTypes type;
-};
-
-const char crypt64[] =
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
-char    *base = NULL;
-char    *binddn = NULL;
-char    *bindpw = NULL;
-char    *ldaphost = "localhost";
-char    *pwattr = LDAP_PASSWD_ATTRIB;
-char    *targetdn = NULL;
-char    *filtpattern = NULL;
-int      ldapport = LDAP_PORT;
-int      noupdates = 0;
-int      verbose = 0;
-int      hashtype = HASHTYPE_CRYPT;
-int      scope = LDAP_SCOPE_SUBTREE;
-
-/*** functions ***/
 
-/*
- * if you'd like to write a better salt generator, please, be my guest.
- * I just needed *something*. It's actually halfway effective for small,
- * two character salts and it can come up with sequentially different
- * salts.
- */
+#include "ldap_defaults.h"
 
-void
-crypt_make_salt(char *salt)
-{
-       struct timeval tv;
-       int i;
-       char t_salt[5];
-
-       /* grab current time */
-       gettimeofday(&tv, (struct timezone *) 0);
-       i += tv.tv_usec + (int)&salt;
-       strncpy(t_salt, (char *)&i, sizeof(i));
-
-       for (i = 0; i < sizeof(i); i++)
-               salt[i] = crypt64[t_salt[i] % (sizeof(crypt64) - 1)];
-       salt[i] = '\0';
-}
+static int     verbose = 0;
 
-int
-hash_none(const char *pw_in, char *pw_out)
+static void
+usage(const char *s)
 {
-       strcpy(pw_out, pw_in);
-       return(1);
+       fprintf(stderr,
+               "Usage: %s [options] dn\n"
+               "  -A\t\tprompt for old password\n"
+               "  -a secret\told password\n"
+               "  -D binddn\tbind dn\n"
+               "  -d level\tdebugging level\n"
+               "  -h host\tldap server (default: localhost)\n"
+               "  -n\t\tmake no modifications\n"
+               "  -p port\tldap port\n"
+               "  -S\t\tprompt for new password\n"
+               "  -s secret\tnew password\n"
+               "  -v\t\tincrease verbosity\n"
+               "  -W\t\tprompt for bind password\n"
+               "  -w passwd\tbind password (for simple authentication)\n"
+               , s );
+
+       exit( EXIT_FAILURE );
 }
 
 int
-hash_crypt(const char *pw_in, char *pw_out)
+main( int argc, char *argv[] )
 {
-       char salt[5];
-       crypt_make_salt(salt);
-       strcpy(pw_out, crypt(pw_in, salt));
-       return(1);
-}
+       int rc;
+       char    *ldaphost = NULL;
 
-int
-hash_md5(const char *pw_in, char *pw_out)
-{
-       lutil_MD5_CTX MD5context;
-       unsigned char MD5digest[16];
-       char base64digest[25];  /* ceiling(sizeof(input)/3) * 4 + 1 */
-
-       lutil_MD5Init(&MD5context);
-       lutil_MD5Update(&MD5context, (unsigned char *)pw_in, strlen(pw_in));
-       lutil_MD5Final(MD5digest, &MD5context);
-       if (lutil_b64_ntop(MD5digest, sizeof(MD5digest), base64digest, sizeof(base64digest)) < 0)
-               return (0);
-
-       strcpy(pw_out, base64digest);
-       return(1);
-}
+       char    *dn = NULL;
+       char    *binddn = NULL;
 
-int
-hash_sha1(const char *pw_in, char *pw_out)
-{
-       lutil_SHA1_CTX SHA1context;
-       unsigned char SHA1digest[20];
-       char base64digest[29];  /* ceiling(sizeof(input)/3) * 4 + 1 */
-
-       lutil_SHA1Init(&SHA1context);
-       lutil_SHA1Update(&SHA1context, (unsigned char *)pw_in, strlen(pw_in));
-       lutil_SHA1Final(SHA1digest, &SHA1context);
-       if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest), base64digest, sizeof(base64digest)) < 0)
-               return(0);
-
-       strcpy(pw_out, base64digest);
-       return(1);
-}
+       char    *bindpw = NULL;
+       char    *newpw = NULL;
+       char    *oldpw = NULL;
 
-static struct hash_t hashes[] = {
-       {"none",  4, hash_none,  HASHTYPE_NONE},
-       {"crypt", 5, hash_crypt, HASHTYPE_CRYPT},
-       {"md5",   3, hash_md5,   HASHTYPE_MD5},
-       {"sha",   3, hash_sha1,  HASHTYPE_SHA1},
-       {NULL,  0, NULL,           HASHTYPE_NONE}
-};
+       int             want_bindpw = 0;
+       int             want_newpw = 0;
+       int             want_oldpw = 0;
 
-int
-modify_dn(LDAP *ld, char *targetdn, char *newpw)
-{
-       int ret = 0;
-       char hashed_pw[128] = {'\0'};
-       char buf[128] = {'\0'};
-       char *strvals[2] = {buf, NULL};
-       LDAPMod mod, *mods[2] = {&mod, NULL};
-
-       if (!ld || !targetdn || !newpw)
-               return(1);
-
-       /* hash password */
-       hashes[hashtype].func(newpw, hashed_pw);
-       if (hashtype)
-               sprintf(buf, "{%s}%s", hashes[hashtype].name, hashed_pw);
-       else
-               sprintf(buf, "%s", hashed_pw);
-
-       if (verbose > 0)
-       {
-               printf("%s", targetdn);
-               if (verbose > 1)
-               {
-                       printf(":%s", buf);
-                       if (verbose > 2)
-                               printf(":%s", newpw);
-               }
-               printf("\n");
-       }
-
-       mod.mod_vals.modv_strvals = strvals;
-       mod.mod_type = pwattr;
-       mod.mod_op = LDAP_MOD_REPLACE;
+       int             noupdates = 0;
+       int             i;
+       int             ldapport = 0;
+       int             debug = 0;
+       int             version = -1;
+       LDAP           *ld;
+       struct berval *bv = NULL;
 
-       if (!noupdates && (ret = ldap_modify_s(ld, targetdn, mods)) != LDAP_SUCCESS)
-               ldap_perror(ld, "ldap_modify_s");
-       return(ret);
-}
-
-void
-usage(char *s)
-{
-       fprintf(stderr, "usage: %s [options] [filter]\n", s);
-       fprintf(stderr, "       -a attrib   password attribute (default: userPassword)\n");
-       fprintf(stderr, "       -b basedn   basedn to perform searches\n");
-       fprintf(stderr, "       -c hash  hash type: none, crypt, md5, sha (default: crypt)\n");
-       fprintf(stderr, "       -D binddn   bind dn\n");
-       fprintf(stderr, "       -d level        debugging level\n");
-       fprintf(stderr, "       -h host  ldap server (default: localhost)\n");
-       fprintf(stderr, "       -l time  time limit\n");
-       fprintf(stderr, "       -n                make no modifications\n");
-       fprintf(stderr, "       -p port  ldap port\n");
-       fprintf(stderr, "       -s scope        search scope: base, one, sub (default: sub)\n");
-       fprintf(stderr, "       -t targetdn dn to change password\n");
-       fprintf(stderr, "       -W newpass  new password\n");
-       fprintf(stderr, "       -w passwd   bind password (for simple authentication)\n");
-       fprintf(stderr, "       -v                verbose\n");
-       fprintf(stderr, "       -z size  size limit\n");
-       exit(1);
-}
+       char    *retoid;
+       struct berval *retdata;
 
-int
-main(int argc, char *argv[])
-{
-       char *newpw = NULL;
-       int i, j;
-       int sizelimit = LDAP_NO_LIMIT;
-       int timelimit = LDAP_NO_LIMIT;
-       LDAP *ld;
+       if (argc == 1)
+               usage (argv[0]);
 
-       while ((i = getopt(argc, argv, "D:W:a:b:c:d:h:l:np:s:t:vw:z:")) != EOF)
+       while( (i = getopt( argc, argv,
+               "Aa:D:d:h:np:Ss:vWw:" )) != EOF )
        {
-               switch(i)
-               {
-               case 'D':          /* bind distinguished name */
-                       binddn = strdup(optarg);
+               switch (i) {
+               case 'A':       /* prompt for oldr password */
+                       want_oldpw++;
                        break;
+               case 'a':       /* old password (secret) */
+                       oldpw = strdup (optarg);
 
-               case 'W':          /* new password */
-                       if (optarg)
-                               newpw = strdup(optarg);
-                       break;
-
-               case 'a':          /* password attribute */
-                       if (optarg)
-                               pwattr = strdup(optarg);
-                       break;
-
-               case 'b':          /* base search dn */
-                       if (optarg)
-                               base = strdup(optarg);
-                       break;
-
-               case 'c':          /* hashes */
-                       for (j = 0; hashes[j].name; j++)
                        {
-                               if (!strncasecmp(optarg, hashes[j].name, hashes[j].namesz))
-                               {
-                                       hashtype = hashes[j].type;
-                                       break;
-                               }
-                       }
+                               char* p;
 
-                       if (!hashes[j].name)
-                       {
-                               fprintf(stderr, "hash type: %s is unknown\n", optarg);
-                               usage(argv[0]);
+                               for( p = optarg; *p == '\0'; p++ ) {
+                                       *p = '*';
+                               }
                        }
                        break;
-
-               case 'd':          /* debugging option */
-#ifdef LDAP_DEBUG
-                       ldap_debug = lber_debug = atoi(optarg);   /* */
-#else
-                       fprintf(stderr, "compile with -DLDAP_DEBUG for debugging\n");
-#endif
+               case 'D':       /* bind distinguished name */
+                       binddn = strdup (optarg);
                        break;
 
-               case 'h':          /* ldap host */
-                       if (optarg)
-                               ldaphost = strdup(optarg);
+               case 'd':       /* debugging option */
+                       debug |= atoi (optarg);
                        break;
 
-               case 'l':          /* time limit */
-                       if (optarg)
-                               timelimit = strtol(optarg, NULL, 10);
+               case 'h':       /* ldap host */
+                       ldaphost = strdup (optarg);
                        break;
 
-               case 'n':          /* don't update entry(s) */
+               case 'n':       /* don't update entry(s) */
                        noupdates++;
                        break;
 
-               case 'p':          /* ldap port */
-                       if (optarg)
-                               ldapport = strtol(optarg, NULL, 10);
+               case 'p':       /* ldap port */
+                       ldapport = strtol( optarg, NULL, 10 );
                        break;
 
-               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]);
-                       }
+               case 'S':       /* prompt for user password */
+                       want_newpw++;
                        break;
 
-               case 't':          /* password type */
-                       if (optarg)
-                               targetdn = strdup(optarg);
-                       else
-                               targetdn = binddn;
+               case 's':       /* new password (secret) */
+                       newpw = strdup (optarg);
+
+                       {
+                               char* p;
+
+                               for( p = optarg; *p == '\0'; p++ ) {
+                                       *p = '*';
+                               }
+                       }
                        break;
 
-               case 'v':          /* verbose */
+               case 'v':       /* verbose */
                        verbose++;
                        break;
 
-               case 'w':          /* bind password */
-                       bindpw = strdup(optarg);
+               case 'W':       /* prompt for bind password */
+                       want_bindpw++;
                        break;
 
-               case 'z':          /* time limit */
-                       if (optarg)
-                               sizelimit = strtol(optarg, NULL, 10);
+               case 'w':       /* bind password */
+                       bindpw = strdup (optarg);
+
+                       {
+                               char* p;
+
+                               for( p = optarg; *p == '\0'; p++ ) {
+                                       *p = '*';
+                               }
+                       }
                        break;
 
+
                default:
-                       usage(argv[0]);
+                       usage (argv[0]);
                }
        }
 
-       if (!(argc - optind < 1))
-               filtpattern = strdup(argv[optind]);
+       if( argc - optind != 1 ) {
+               usage( argv[0] );
+       } 
 
-       if (!filtpattern && !targetdn)
-       {
-               fprintf(stderr, "No filter or targetdn(-t)\n");
-               usage(argv[0]);
+       dn = strdup( argv[optind] );
+
+       if( want_oldpw && oldpw == NULL ) {
+               /* prompt for old password */
+               char *ckoldpw;
+               newpw = strdup(getpass("Old password: "));
+               ckoldpw = getpass("Re-enter old password: ");
+
+               if( strncmp( oldpw, ckoldpw, strlen(oldpw) )) {
+                       fprintf( stderr, "passwords do not match\n" );
+                       return EXIT_FAILURE;
+               }
        }
 
-       if (!newpw)
-       {
-               fprintf(stderr, "Need a password (-W)\n");
-               usage(argv[0]);
+       if( want_newpw && newpw == NULL ) {
+               /* prompt for new password */
+               char *cknewpw;
+               newpw = strdup(getpass("New password: "));
+               cknewpw = getpass("Re-enter new password: ");
+
+               if( strncmp( newpw, cknewpw, strlen(newpw) )) {
+                       fprintf( stderr, "passwords do not match\n" );
+                       return EXIT_FAILURE;
+               }
        }
 
+       if( binddn == NULL && dn != NULL ) {
+               binddn = dn;
+               dn = NULL;
+
+               if( bindpw == NULL ) bindpw = oldpw;
+       }
+
+       if (want_bindpw && bindpw == NULL ) {
+               /* handle bind password */
+               fprintf( stderr, "Bind DN: %s\n", binddn );
+               bindpw = strdup( getpass("Enter bind password: "));
+       }
+
+       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 );
+               }
+       }
+
+#ifdef SIGPIPE
+       (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
        /* connect to server */
-       if ((ld = ldap_open(ldaphost, ldapport)) == NULL)
-       {
-               perror(ldaphost);
-               return(1);
+       if ((ld = ldap_init( ldaphost, ldapport )) == NULL) {
+               perror("ldap_init");
+               return EXIT_FAILURE;
        }
 
-       /* set options */
-       ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *)&timelimit);
-       ldap_set_option(ld, LDAP_OPT_SIZELIMIT, (void *)&sizelimit);
+       /* don't chase referrals */
+       ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
 
-       /* authenticate to server */
-       if (ldap_bind_s(ld, binddn, bindpw, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS)
-       {
-               ldap_perror(ld, "ldap_bind");
-               return(1);
+       version = 3;
+       rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+
+       if(rc != LDAP_OPT_SUCCESS ) {
+               fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
        }
 
-       if (filtpattern)
-       {
-               char filter[BUFSIZ];
-               LDAPMessage *result = NULL, *e = NULL;
-               char *attrs[] = {"dn", NULL};
-
-               /* search */
-               sprintf(filter, "%s", filtpattern);
-               i = ldap_search_s(ld, base, scope, filter, attrs, 1, &result);
-               if (i != LDAP_SUCCESS && i != LDAP_TIMELIMIT_EXCEEDED && i != LDAP_SIZELIMIT_EXCEEDED)
-               {
-                       ldap_perror(ld, "ldap_search_s");
-                       return(1);
+       rc = ldap_bind_s( ld, binddn, bindpw, LDAP_AUTH_SIMPLE );
+
+       if ( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_bind" );
+               ldap_unbind( ld );
+               return EXIT_FAILURE;
+       }
+
+       if( dn != NULL || oldpw != NULL || newpw != NULL ) {
+               /* build change password control */
+               BerElement *ber = ber_alloc_t( LBER_USE_DER );
+
+               if( ber == NULL ) {
+                       perror( "ber_alloc_t" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
                }
 
-               for (e = ldap_first_entry(ld, result); e; e = ldap_next_entry(ld, e))
-               {
-                       char *dn = ldap_get_dn(ld, e);
-                       if (dn)
-                       {
-                               modify_dn(ld, dn, newpw);
-                               free(dn);
-                       }
+               ber_printf( ber, "{" /*}*/ );
+
+               if( dn != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, dn );
+                       free(dn);
+               }
+
+               if( oldpw != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, oldpw );
+                       free(oldpw);
+               }
+
+               if( newpw != NULL ) {
+                       ber_printf( ber, "ts",
+                               LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, newpw );
+                       free(newpw);
                }
+
+               ber_printf( ber, /*{*/ "}" );
+
+               rc = ber_flatten( ber, &bv );
+
+               if( rc < 0 ) {
+                       perror( "ber_flatten" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
+               }
+
+               ber_free( ber, 1 );
        }
 
-       if (targetdn)
-               modify_dn(ld, targetdn, newpw);
+       rc = ldap_extended_operation_s( ld,
+               LDAP_EXOP_X_MODIFY_PASSWD, bv, 
+               NULL, NULL,
+               &retoid, &retdata );
+
+       ber_bvfree( bv );
+
+       if( retdata != NULL ) {
+               ber_tag_t tag;
+               char *s;
+               BerElement *ber = ber_init( retdata );
+
+               if( ber == NULL ) {
+                       perror( "ber_init" );
+                       ldap_unbind( ld );
+                       return EXIT_FAILURE;
+               }
+
+               /* we should check the tag */
+               tag = ber_scanf( ber, "{a}", &s);
+
+               if( tag == LBER_ERROR ) {
+                       perror( "ber_scanf" );
+               } else {
+                       printf("New password: %s\n", s);
+                       free( s );
+               }
+
+               ber_free( ber, 1 );
+       }
+
+       if ( rc != LDAP_SUCCESS ) {
+               ldap_perror( ld, "ldap_extended_operation" );
+               ldap_unbind( ld );
+               return EXIT_FAILURE;
+       }
+
+       ldap_memfree( retoid );
+       ber_bvfree( retdata );
 
        /* disconnect from server */
-       ldap_unbind(ld);
-       return(0);
+       ldap_unbind (ld);
+
+       return ( EXIT_SUCCESS );
 }