You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@hyperreal.org on 1999/02/03 17:22:35 UTC

cvs commit: apache-1.3/src/support htpasswd.c httpd.exp

coar        99/02/03 08:22:34

  Modified:    .        STATUS
               src      ApacheCore.def CHANGES
               src/ap   ap_md5c.c
               src/include ap_md5.h ap_mmn.h
               src/modules/standard mod_auth.c mod_auth_db.c mod_auth_dbm.c
               src/support htpasswd.c httpd.exp
  Log:
  	Rework the ap_MD5Encode() routine to use FreeBSD's algorithm
  	and a private significator ("$apr1"); also make it reentrant.
  	Abstract the password checking into a new routine,
  	ap_validate_password(plaintext, hashed), and modify mod_auth*.c
  	to use it instead of each doing the algorithm check.
  
  Obtained from:	FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c (MD5)
  
  Revision  Changes    Path
  1.610     +1 -2      apache-1.3/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /home/cvs/apache-1.3/STATUS,v
  retrieving revision 1.609
  retrieving revision 1.610
  diff -u -r1.609 -r1.610
  --- STATUS	1999/02/02 16:15:50	1.609
  +++ STATUS	1999/02/03 16:22:25	1.610
  @@ -1,5 +1,5 @@
     1.3 STATUS:
  -  Last modified at [$Date: 1999/02/02 16:15:50 $]
  +  Last modified at [$Date: 1999/02/03 16:22:25 $]
   
   Release:
   
  @@ -15,7 +15,6 @@
   
   RELEASE SHOWSTOPPERS:
   
  -    * md5 passwd stuff incompatible with FreeBSD implementation.
   
   RELEASE NON-SHOWSTOPPERS BUT WOULD BE REAL NICE TO WRAP THESE UP:
   
  
  
  
  1.9       +1 -0      apache-1.3/src/ApacheCore.def
  
  Index: ApacheCore.def
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/ApacheCore.def,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ApacheCore.def	1999/01/29 14:28:53	1.8
  +++ ApacheCore.def	1999/02/03 16:22:27	1.9
  @@ -326,4 +326,5 @@
   	ap_os_is_filename_valid   @319
   	ap_find_opaque_token   @320
   	ap_MD5Encode   @321
  +	ap_validate_password   @322
   
  
  
  
  1.1229    +5 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1228
  retrieving revision 1.1229
  diff -u -r1.1228 -r1.1229
  --- CHANGES	1999/01/30 19:19:23	1.1228
  +++ CHANGES	1999/02/03 16:22:28	1.1229
  @@ -1,5 +1,10 @@
   Changes with Apache 1.3.5
   
  +  *) Rework the MD5 authentication scheme to use FreeBSD's algorithm,
  +     and use a private significator ('$apr1$') to mark passwords as
  +     being smashed with our own algorithm.  Also abstract the password
  +     checking into a new ap_validate_password() routine.  [Ken Coar]
  +
     *) Win32: The filename validity checker now allows "COM" but refuses 
        access to "COM1" through "COM4". This allows filenames such
        as "com.name" to be served. [Paul Sutton] PR#3769.
  
  
  
  1.19      +217 -43   apache-1.3/src/ap/ap_md5c.c
  
  Index: ap_md5c.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/ap/ap_md5c.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- ap_md5c.c	1999/01/25 22:55:36	1.18
  +++ ap_md5c.c	1999/02/03 16:22:30	1.19
  @@ -88,6 +88,17 @@
    *
    */
   
  +/*
  + * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
  + * MD5 crypt() function, which is licenced as follows:
  + * ----------------------------------------------------------------------------
  + * "THE BEER-WARE LICENSE" (Revision 42):
  + * <ph...@login.dknet.dk> wrote this file.  As long as you retain this notice you
  + * can do whatever you want with this stuff. If we meet some day, and you think
  + * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  + * ----------------------------------------------------------------------------
  + */
  +
   #include <string.h>
   
   #include "ap_config.h"
  @@ -381,7 +392,7 @@
   }
   
   /* Decodes input (unsigned char) into output (UINT4). Assumes len is
  -   a multiple of 4.
  + * a multiple of 4.
    */
   static void Decode(UINT4 *output, const unsigned char *input, unsigned int len)
   {
  @@ -391,47 +402,210 @@
   	output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
   	    (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
   }
  +
  +/*
  + * Define the Magic String prefix that identifies a password as being
  + * hashed using our algorithm.
  + */
  +static const char *apr1_id = "$apr1$";
  +
  +/*
  + * The following MD5 password encryption code was largely borrowed from
  + * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
  + * licenced as stated at the top of this file.
  + */
  +
  +static void to64 __P((char *, unsigned long, int));
  +
  +static void to64(char *s, unsigned long v, int n)
  +{
  +static void to64 __P((char *, unsigned long, int));
  +    static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
  +	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  +
  +    while (--n >= 0) {
  +	*s++ = itoa64[v&0x3f];
  +	v >>= 6;
  +    }
  +}
  +
  +API_EXPORT(void) ap_MD5Encode(const char *pw, const char *salt,
  +			      char *result, size_t nbytes)
  +{
  +    /*
  +     * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
  +     * plus 4 for the '$' separators, plus the password hash itself.
  +     * Let's leave a goodly amount of leeway.
  +     */
  +
  +    char passwd[120], *p;
  +    const char *sp, *ep;
  +    unsigned char final[16];
  +    int sl, pl, i;
  +    AP_MD5_CTX ctx, ctx1;
  +    unsigned long l;
  +
  +    /* 
  +     * Refine the salt first.  It's possible we were given an already-hashed
  +     * string as the salt argument, so extract the actual salt value from it
  +     * if so.  Otherwise just use the string up to the first '$' as the salt.
  +     */
  +    sp = salt;
  +
  +    /*
  +     * If it starts with the magic string, then skip that.
  +     */
  +    if (!strncmp(sp, apr1_id, strlen(apr1_id))) {
  +	sp += strlen(apr1_id);
  +    }
  +
  +    /*
  +     * It stops at the first '$' or 8 chars, whichever comes first
  +     */
  +    for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
  +	continue;
  +    }
  +
  +    /*
  +     * Get the length of the true salt
  +     */
  +    sl = ep - sp;
  +
  +    /*
  +     * 'Time to make the doughnuts..'
  +     */
  +    ap_MD5Init(&ctx);
   
  -API_EXPORT(char *) ap_MD5Encode(const char *password, const char * salt) {
  -/* salt has size 2, md5 hash size 22, plus 1 for trailing NUL, plus 4 for
  -   '$' separators between md5 distinguisher, salt, and password.*/
  -
  -    static unsigned char ret[2+22+1+4];
  -    AP_MD5_CTX my_md5;
  -    unsigned char hash[16], *cp;
  -    register int i;
  -    static const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
  - 
  -    /*
  -     * Take the MD5 hash of the string argument.
  -    */
  - 
  -    sprintf(ret, "$1$%s$", salt); 
  - 
  -    /* If the salt is shorter than 2, pad with random characters */
  -    for (cp = &ret[strlen(ret)]; cp < &ret[2]; ++cp) {
  -        *cp = alphabet[rand() & 0x3F];
  -    }
  -    ap_MD5Init(&my_md5);
  -    ap_MD5Update(&my_md5, salt, 2);
  -    ap_MD5Update(&my_md5, password, strlen(password));
  -    ap_MD5Final(hash, &my_md5);
  - 
  -    /* Take 3*8 bits (3 bytes) and store them as 4 base64 bytes (of 6 bit each) */
  -    /* Copy first 15 bytes in loop (producing 20 result bytes) */
  -    for (i = 0, cp = &ret[6]; i < 15; i += 3, cp += 4) {
  -        long l = hash[i] | (hash[i+1] << 8) | (hash[i+2] << 16);
  - 
  -        cp[0] = alphabet[l&0x3F];
  -        cp[1] = alphabet[(l>>6)&0x3F];
  -        cp[2] = alphabet[(l>>12)&0x3F];
  -        cp[3] = alphabet[(l>>18)&0x3F];
  -    }
  -    cp[0] = alphabet[hash[i]&0x3F]; /* Use 16th byte as 21st result byte */
  -    cp[1] = alphabet[(hash[i]>>6)&0x3F]; /* Last 2 bits of 16th byte are 22nd result byte */
  -    cp[2] = '\0';
  - 
  -    /*ap_assert(&cp[2] == &ret[(sizeof ret)-1]);*/
  - 
  -    return (char *)ret;
  +    /*
  +     * The password first, since that is what is most unknown
  +     */
  +    ap_MD5Update(&ctx, pw, strlen(pw));
  +
  +    /*
  +     * Then our magic string
  +     */
  +    ap_MD5Update(&ctx, apr1_id, strlen(apr1_id));
  +
  +    /*
  +     * Then the raw salt
  +     */
  +    ap_MD5Update(&ctx, sp, sl);
  +
  +    /*
  +     * Then just as many characters of the MD5(pw, salt, pw)
  +     */
  +    ap_MD5Init(&ctx1);
  +    ap_MD5Update(&ctx1, pw, strlen(pw));
  +    ap_MD5Update(&ctx1, sp, sl);
  +    ap_MD5Update(&ctx1, pw, strlen(pw));
  +    ap_MD5Final(final, &ctx1);
  +    for(pl = strlen(pw); pl > 0; pl -= 16) {
  +	ap_MD5Update(&ctx, final, (pl > 16) ? 16 : pl);
  +    }
  +
  +    /*
  +     * Don't leave anything around in vm they could use.
  +     */
  +    memset(final, 0, sizeof(final));
  +
  +    /*
  +     * Then something really weird...
  +     */
  +    for (i = strlen(pw); i != 0; i >>= 1) {
  +	if (i & 1) {
  +	    ap_MD5Update(&ctx, final, 1);
  +	}
  +	else {
  +	    ap_MD5Update(&ctx, pw, 1);
  +	}
  +    }
  +
  +    /*
  +     * Now make the output string.  We know our limitations, so we
  +     * can use the string routines without bounds checking.
  +     */
  +    strcpy(passwd, apr1_id);
  +    strncat(passwd, sp, sl);
  +    strcat(passwd, "$");
  +
  +    ap_MD5Final(final, &ctx);
  +
  +    /*
  +     * And now, just to make sure things don't run too fast..
  +     * On a 60 Mhz Pentium this takes 34 msec, so you would
  +     * need 30 seconds to build a 1000 entry dictionary...
  +     */
  +    for (i = 0; i < 1000; i++) {
  +	ap_MD5Init(&ctx1);
  +	if (i & 1) {
  +	    ap_MD5Update(&ctx1, pw, strlen(pw));
  +	}
  +	else {
  +	    ap_MD5Update(&ctx1, final, 16);
  +	}
  +	if (i % 3) {
  +	    ap_MD5Update(&ctx1, sp, sl);
  +	}
  +
  +	if (i % 7) {
  +	    ap_MD5Update(&ctx1, pw, strlen(pw));
  +	}
  +
  +	if (i & 1) {
  +	    ap_MD5Update(&ctx1, final, 16);
  +	}
  +	else {
  +	    ap_MD5Update(&ctx1, pw, strlen(pw));
  +	}
  +	ap_MD5Final(final,&ctx1);
  +    }
  +
  +    p = passwd + strlen(passwd);
  +
  +    l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
  +    l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
  +    l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
  +    l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
  +    l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
  +    l =                    final[11]                ; to64(p, l, 2); p += 2;
  +    *p = '\0';
  +
  +    /*
  +     * Don't leave anything around in vm they could use.
  +     */
  +    memset(final, 0, sizeof(final));
  +
  +    ap_cpystrn(result, passwd, nbytes - 1);
  +}
  +
  +/*
  + * Validate a plaintext password against a smashed one.  Use either
  + * crypt() (if available) or ap_MD5Encode(), depending upon the format
  + * of the smashed input password.  Return NULL if they match, or
  + * an explanatory text string if they don't.
  + */
  +
  +API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash)
  +{
  +    char sample[120];
  +    char *crypt_pw;
  +
  +    if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
  +	/*
  +	 * The hash was created using our custom algorithm.
  +	 */
  +	ap_MD5Encode(passwd, hash, sample, sizeof(sample));
  +    }
  +    else {
  +	/*
  +	 * It's not our algorithm, so feed it to crypt() if possible.
  +	 */
  +#ifdef WIN32
  +	return "crypt() unavailable on Win32, cannot validate password";
  +#else
  +	crypt_pw = crypt(passwd, hash);
  +	ap_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
  +    }
  +    return (strcmp(sample, hash) == 0) ? NULL : "password mismatch";
  +#endif
   }
  
  
  
  1.4       +3 -1      apache-1.3/src/include/ap_md5.h
  
  Index: ap_md5.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/ap_md5.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ap_md5.h	1999/01/25 22:55:37	1.3
  +++ ap_md5.h	1999/02/03 16:22:31	1.4
  @@ -108,7 +108,9 @@
   API_EXPORT(void) ap_MD5Update(AP_MD5_CTX * context, const unsigned char *input,
   			   unsigned int inputLen);
   API_EXPORT(void) ap_MD5Final(unsigned char digest[16], AP_MD5_CTX * context);
  -API_EXPORT(char *) ap_MD5Encode(const char *, const char *);
  +API_EXPORT(void) ap_MD5Encode(const char *password, const char *salt,
  +			      char *result, size_t nbytes);
  +API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash);
   
   #ifdef __cplusplus
   }
  
  
  
  1.25      +5 -1      apache-1.3/src/include/ap_mmn.h
  
  Index: ap_mmn.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/ap_mmn.h,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- ap_mmn.h	1999/01/29 14:28:55	1.24
  +++ ap_mmn.h	1999/02/03 16:22:31	1.25
  @@ -206,6 +206,10 @@
    * 19990108-1           - add ap_find_opaque_token() for things like ETags
    *   (1.3.5-dev)          which can contain opaque quoted strings, and
    *                        ap_MD5Encode() for MD5 password handling.
  + * 19990108-2           - add ap_validate_password() and change ap_MD5Encode()
  + *   (1.3.5-dev)          to use a stronger algorithm (which is incompatible
  + *                        with the one introduced [but not released] with
  + *                        19990108-1).
    */
   
   #define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
  @@ -213,7 +217,7 @@
   #ifndef MODULE_MAGIC_NUMBER_MAJOR
   #define MODULE_MAGIC_NUMBER_MAJOR 19990108
   #endif
  -#define MODULE_MAGIC_NUMBER_MINOR 1                     /* 0...n */
  +#define MODULE_MAGIC_NUMBER_MINOR 2                     /* 0...n */
   #define MODULE_MAGIC_NUMBER MODULE_MAGIC_NUMBER_MAJOR	/* backward compat */
   
   /* Useful for testing for features. */
  
  
  
  1.45      +5 -14     apache-1.3/src/modules/standard/mod_auth.c
  
  Index: mod_auth.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_auth.c,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- mod_auth.c	1999/01/31 22:01:34	1.44
  +++ mod_auth.c	1999/02/03 16:22:32	1.45
  @@ -75,9 +75,6 @@
   #include "http_log.h"
   #include "http_protocol.h"
   #include "ap_md5.h"
  -#if defined(HAVE_CRYPT_H)
  -#include <crypt.h>
  -#endif
   
   typedef struct auth_config_struct {
       char *auth_pwfile;
  @@ -204,6 +201,7 @@
       conn_rec *c = r->connection;
       const char *sent_pw;
       char *real_pw;
  +    char *invalid_pw;
       int res;
   
       if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
  @@ -220,18 +218,11 @@
   	ap_note_basic_auth_failure(r);
   	return AUTH_REQUIRED;
       }
  -    if (real_pw[0] == '$' && real_pw[1] == '1') {
  -        const char *salt = real_pw + 3;
  -        salt = ap_getword(r->pool, &salt, '$');
  -        res = strcmp(real_pw, ap_MD5Encode(sent_pw, salt));
  -    }
  -    else {
  -        res = strcmp(real_pw, crypt(sent_pw, real_pw));
  -    }
  -
  -    if (res != 0) {
  +    invalid_pw = ap_validate_password(sent_pw, real_pw);
  +    if (invalid_pw != NULL) {
   	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -		      "user %s: password mismatch: %s", c->user, r->uri);
  +		      "user %s: authentication failure for \"%s\": %s",
  +		      c->user, r->uri, invalid_pw);
   	ap_note_basic_auth_failure(r);
   	return AUTH_REQUIRED;
       }
  
  
  
  1.40      +5 -14     apache-1.3/src/modules/standard/mod_auth_db.c
  
  Index: mod_auth_db.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_auth_db.c,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- mod_auth_db.c	1999/01/31 22:01:34	1.39
  +++ mod_auth_db.c	1999/02/03 16:22:32	1.40
  @@ -97,9 +97,6 @@
   #include "http_protocol.h"
   #include <db.h>
   #include "ap_md5.h"
  -#if defined(HAVE_CRYPT_H)
  -#include <crypt.h>
  -#endif
   
   #if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
   #define DB2
  @@ -230,6 +227,7 @@
       conn_rec *c = r->connection;
       const char *sent_pw;
       char *real_pw, *colon_pw;
  +    char *invalid_pw;
       int res;
   
       if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
  @@ -250,19 +248,12 @@
       colon_pw = strchr(real_pw, ':');
       if (colon_pw) {
   	*colon_pw = '\0';
  -    }
  -    if (real_pw[0] == '$' && real_pw[1] == '1') {
  -        char *salt = real_pw + 3;
  -        salt = ap_getword(r->pool, &salt, '$');
  -        res = strcmp(real_pw, ap_MD5Encode(sent_pw, salt));
       }
  -    else {
  -        res = strcmp(real_pw, crypt(sent_pw, real_pw));
  -    }
  -
  -    if (res != 0) {
  +    invalid_pw = ap_validate_password(sent_pw, real_pw);
  +    if (invalid_pw != NULL) {
   	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -		      "DB user %s: password mismatch: %s", c->user, r->uri);
  +		      "DB user %s: authentication failure for \"%s\": %s",
  +		      c->user, r->uri, invalid_pw);
   	ap_note_basic_auth_failure(r);
   	return AUTH_REQUIRED;
       }
  
  
  
  1.45      +6 -14     apache-1.3/src/modules/standard/mod_auth_dbm.c
  
  Index: mod_auth_dbm.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_auth_dbm.c,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- mod_auth_dbm.c	1999/01/31 22:01:34	1.44
  +++ mod_auth_dbm.c	1999/02/03 16:22:32	1.45
  @@ -76,9 +76,6 @@
   #include "http_protocol.h"
   #include <ndbm.h>
   #include "ap_md5.h"
  -#if defined(HAVE_CRYPT_H)
  -#include <crypt.h>
  -#endif
   
   /*
    * Module definition information - the part between the -START and -END
  @@ -212,6 +209,7 @@
       conn_rec *c = r->connection;
       const char *sent_pw;
       char *real_pw, *colon_pw;
  +    char *invalid_pw;
       int res;
   
       if ((res = ap_get_basic_auth_pw(r, &sent_pw)))
  @@ -230,20 +228,14 @@
       }
       /* Password is up to first : if exists */
       colon_pw = strchr(real_pw, ':');
  -    if (colon_pw)
  +    if (colon_pw) {
   	*colon_pw = '\0';
  -    if (real_pw[0] == '$' && real_pw[1] == '1') {
  -        char *salt = real_pw + 3;
  -        salt = ap_getword(r->pool, &salt, '$');
  -        res = strcmp(real_pw, ap_MD5Encode(sent_pw, salt));
  -    }
  -    else {
  -        res = strcmp(real_pw, crypt(sent_pw, real_pw));
       }
  -
  -    if (res != 0) {
  +    invalid_pw = ap_validate_password(sent_pw, real_pw);
  +    if (invalid_pw != NULL) {
   	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -		      "user %s: password mismatch: %s", c->user, r->uri);
  +		      "DBM user %s: authentication failure for \"%s\": %s",
  +		      c->user, r->uri, invalid_pw);
   	ap_note_basic_auth_failure(r);
   	return AUTH_REQUIRED;
       }
  
  
  
  1.20      +6 -5      apache-1.3/src/support/htpasswd.c
  
  Index: htpasswd.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/support/htpasswd.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- htpasswd.c	1999/01/25 22:55:41	1.19
  +++ htpasswd.c	1999/02/03 16:22:34	1.20
  @@ -13,6 +13,7 @@
   #include "ap_config.h"
   #include <sys/types.h>
   #include <signal.h>
  +#include "ap.h"
   #include "ap_md5.h"
   
   #ifdef WIN32
  @@ -159,7 +160,7 @@
   
   static void add_password(char *user, FILE *f, int use_md5)
   {
  -    char *pw, *cpw, salt[3];
  +    char *pw, cpw[120], salt[9];
   
       pw = strd((char *) getpass("New password:"));
       if (strcmp(pw, (char *) getpass("Re-type new password:"))) {
  @@ -170,14 +171,14 @@
   	exit(1);
       }
       (void) srand((int) time((time_t *) NULL));
  -    to64(&salt[0], rand(), 2);
  -    salt[2] = '\0';
  +    to64(&salt[0], rand(), 8);
  +    salt[8] = '\0';
   
       if (use_md5) {
  -        cpw = (char *)ap_MD5Encode(pw, salt);
  +        ap_MD5Encode(pw, salt, cpw, sizeof(cpw));
       }
       else {
  -	cpw = (char *)crypt(pw, salt);
  +	ap_cpystrn(cpw, (char *)crypt(pw, salt), sizeof(cpw) - 1);
       }
       free(pw);
       fprintf(f, "%s:%s\n", user, cpw);
  
  
  
  1.13      +1 -0      apache-1.3/src/support/httpd.exp
  
  Index: httpd.exp
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/support/httpd.exp,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- httpd.exp	1999/01/29 14:28:56	1.12
  +++ httpd.exp	1999/02/03 16:22:34	1.13
  @@ -352,6 +352,7 @@
   ap_util_init
   ap_util_uri_init
   ap_uudecode
  +ap_validate_password
   ap_vbprintf
   ap_vformatter
   ap_vsnprintf