Install etc/login.defs.linux to get the new CIPHER and CRYPT_ROUNDS definitions. MD5_CRYPT_ENAB has been removed. This patch links shadow-utils to openssl's libcrypto, instead of libcrypt from libc. In this patch des, md5, and hmac-sha1 work. Beware: This patch is expirmental development, not finished, and should not be used outside of a chroot for development. robert diff -Naur shadow-4.0.4.1.orig/configure shadow-4.0.4.1/configure --- shadow-4.0.4.1.orig/configure 2004-01-14 14:15:15.000000000 +0000 +++ shadow-4.0.4.1/configure 2007-05-01 09:52:38.000000000 +0000 @@ -21848,13 +21848,13 @@ if test "$with_libcrypt" != "no"; then - echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5 -echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6 + echo "$as_me:$LINENO: checking for DES_crypt in -lcrypto" >&5 +echo $ECHO_N "checking for DES_crypt in -lcrypto... $ECHO_C" >&6 if test "${ac_cv_lib_crypt_crypt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcrypt $LIBS" +LIBS="-lcrypto $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -21868,11 +21868,11 @@ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char crypt (); +char DES_crypt (); int main () { -crypt (); +DES_crypt (); ; return 0; } @@ -21905,7 +21905,7 @@ cat >>confdefs.h <<\_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF - LIBCRYPT=-lcrypt + LIBCRYPT=-lcrypto fi fi diff -Naur shadow-4.0.4.1.orig/configure.in shadow-4.0.4.1/configure.in --- shadow-4.0.4.1.orig/configure.in 2004-01-14 14:11:25.000000000 +0000 +++ shadow-4.0.4.1/configure.in 2007-05-01 09:52:38.000000000 +0000 @@ -227,7 +227,7 @@ AC_SUBST(LIBCRYPT) if test "$with_libcrypt" != "no"; then - AC_CHECK_LIB(crypt, crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypt]) + AC_CHECK_LIB(crypto, DES_crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypto]) fi AC_SUBST(LIBCRACK) diff -Naur shadow-4.0.4.1.orig/etc/login.defs.linux shadow-4.0.4.1/etc/login.defs.linux --- shadow-4.0.4.1.orig/etc/login.defs.linux 2003-05-04 20:09:43.000000000 +0000 +++ shadow-4.0.4.1/etc/login.defs.linux 2007-05-01 10:50:27.000000000 +0000 @@ -262,7 +262,6 @@ # # Number of significant characters in the password for crypt(). # Default is 8, don't change unless your crypt() is better. -# Ignored if MD5_CRYPT_ENAB set to "yes". # #PASS_MAX_LEN 8 @@ -286,15 +285,16 @@ # to use the default which is just "Password: ". #LOGIN_STRING "%s's Password: " -# -# Only works if compiled with MD5_CRYPT defined: -# If set to "yes", new passwords will be encrypted using the MD5-based -# algorithm compatible with the one used by recent releases of FreeBSD. -# It supports passwords of unlimited length and longer salt strings. -# Set to "no" if you need to copy encrypted passwords to other systems -# which don't understand the new algorithm. Default is "no". -# -#MD5_CRYPT_ENAB no +# Possible values are des, md5, and sha1 (hmac-sha1). +CIPHER sha1 + +# CRYPT_ROUNDS is used by SHA1 (and Blowfish) as a hint to the +# humber of iterations. This number will only be used as a hint, +# and will be mixed in with getpid(), hashed with random(3), and +# divided down. SHA1 uses a 32-bit integer, 0 will default to 24680. +# Blowfish can use numbers between 4 and 31. + +CRYPT_ROUNDS 24680 # # List of groups to add to the user's supplementary group set diff -Naur shadow-4.0.4.1.orig/lib/Makefile.in shadow-4.0.4.1/lib/Makefile.in --- shadow-4.0.4.1.orig/lib/Makefile.in 2004-01-14 14:15:26.000000000 +0000 +++ shadow-4.0.4.1/lib/Makefile.in 2007-05-01 09:52:38.000000000 +0000 @@ -177,9 +177,14 @@ groupio.h \ gshadow.c \ lockpw.c \ - md5.h \ nscd.c \ nscd.h \ + openssl-hmac.c \ + openssl-md5.h \ + openssl-md5.c \ + openssl-sha1.h \ + openssl-sha1.c \ + openssl-util.c \ pam_defs.h \ port.c \ port.h \ @@ -204,7 +209,7 @@ EXTRA_libshadow_la_SOURCESS = grent.c pwent.c mkdir.c rename.c rmdir.c \ strdup.c strcasecmp.c strerror.c strstr.c putgrent.c \ putpwent.c putspent.c sgetgrent.c sgetpwent.c sgetspent.c \ - snprintf.c md5.c md5crypt.c + snprintf.c @@ -232,7 +237,8 @@ am_libshadow_la_OBJECTS = commonio.lo encrypt.lo fputsx.lo getdef.lo \ getpass.lo groupio.lo gshadow.lo lockpw.lo nscd.lo port.lo \ pwauth.lo pwio.lo rad64.lo sgetgrent.lo sgetpwent.lo \ - sgroupio.lo shadow.lo shadowio.lo utent.lo + sgroupio.lo shadow.lo shadowio.lo utent.lo \ + openssl-hmac.lo openssl-md5.lo openssl-sha1.lo openssl-util.lo libshadow_la_OBJECTS = $(am_libshadow_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) diff -Naur shadow-4.0.4.1.orig/lib/defines.h shadow-4.0.4.1/lib/defines.h --- shadow-4.0.4.1.orig/lib/defines.h 2003-05-03 16:14:23.000000000 +0000 +++ shadow-4.0.4.1/lib/defines.h 2007-05-01 11:15:04.000000000 +0000 @@ -335,4 +335,36 @@ #define SHADOW_PASSWD_STRING "x" #endif +#ifndef FALSE +# define FALSE 0 +#endif +#ifndef TRUE +# define TRUE 1 +#endif + +#include +#ifndef CHAR_MAX +# define CHAR_MAX 127 +#endif +#ifndef LINE_MAX +# ifdef _POSIX2_LINE_MAX +# define LINE_MAX _POSIX2_LINE_MAX +# else +# define LINE_MAX 2048 +# endif +#endif + +/* These will probably never need adjustment. */ +#ifndef DES_PASSWORD_LENGTH +# define DES_PASSWORD_LENGTH 8 +#endif +#ifndef BLOWFISH_PASSWORD_LENGTH +# define BLOWFISH_PASSWORD_LENGTH 72 +#endif +/* For sha1 and md5. */ +#ifndef MAX_PASSWORD_LENGTH +/* This will be 255, on most systems, 127 on others. */ +# define MAX_PASSWORD_LENGTH CHAR_MAX +#endif + #endif /* _DEFINES_H_ */ diff -Naur shadow-4.0.4.1.orig/lib/encrypt.c shadow-4.0.4.1/lib/encrypt.c --- shadow-4.0.4.1.orig/lib/encrypt.c 2000-08-26 18:27:17.000000000 +0000 +++ shadow-4.0.4.1/lib/encrypt.c 2007-05-01 09:52:38.000000000 +0000 @@ -27,6 +27,12 @@ * SUCH DAMAGE. */ +/* + * Removed strcpy/strlcpy(). + * Exit with failure, not sucess, if crypt() fails. + * Robert + */ + #include #include "rcsid.h" @@ -35,89 +41,36 @@ #include "prototypes.h" #include "defines.h" -extern char *crypt(); -extern char *libshadow_md5_crypt(const char *, const char *); +#include "openssl-md5.h" +#include "openssl-sha1.h" +#include /* Move this somewhere else. */ char * pw_encrypt(const char *clear, const char *salt) { - static char cipher[128]; - char *cp; -#ifdef SW_CRYPT - static int count; -#endif - -#ifdef MD5_CRYPT - /* - * If the salt string from the password file or from crypt_make_salt() - * begins with the magic string, use the new algorithm. - */ - if (strncmp(salt, "$1$", 3) == 0) - return libshadow_md5_crypt(clear, salt); -#endif - -#ifdef SW_CRYPT - /* - * Copy over the salt. It is always the first two - * characters of the string. - */ - - cipher[0] = salt[0]; - cipher[1] = salt[1]; - cipher[2] = '\0'; - - /* - * Loop up to ten times on the cleartext password. - * This is because the input limit for passwords is - * 80 characters. - * - * The initial salt is that provided by the user, or the - * one generated above. The subsequent salts are gotten - * from the first two characters of the previous encrypted - * block of characters. - */ - - for (count = 0;count < 10;count++) { - cp = crypt(clear, salt); - if (!cp) { - perror("crypt"); - exit(1); + char *cipher; + + if (is_sha1_salt(salt)) { + cipher = sha1_crypt(clear, salt); + if (!cipher) { + perror("sha1_crypt() failed"); + exit(FALSE); + } + } else + if (is_md5_salt(salt)) { + cipher = md5_crypt(clear, salt); + if (!cipher) { + perror("md5_crypt() failed"); + exit(FALSE); } - if (strlen(cp) != 13) - return cp; - strcat(cipher, cp + 2); - salt = cipher + 11 * count + 2; - - if (strlen(clear) > 8) - clear += 8; - else - break; - } -#else - cp = crypt(clear, salt); - if (!cp) { - /* - * Single Unix Spec: crypt() may return a null pointer, - * and set errno to indicate an error. The caller doesn't - * expect us to return NULL, so... - */ - perror("crypt"); - exit(1); } - if (strlen(cp) != 13) - return cp; /* nonstandard crypt() in libc, better bail out */ - strcpy(cipher, cp); - -#ifdef DOUBLESIZE - if (strlen (clear) > 8) { - cp = crypt(clear + 8, salt); - if (!cp) { - perror("crypt"); - exit(1); + else { + cipher = DES_crypt(clear, salt); + if (!cipher) { + perror("DES_crypt() failed"); + exit(FALSE); } - strcat(cipher, cp + 2); } -#endif /* DOUBLESIZE */ -#endif /* SW_CRYPT */ + return cipher; } diff -Naur shadow-4.0.4.1.orig/lib/getdef.c shadow-4.0.4.1/lib/getdef.c --- shadow-4.0.4.1.orig/lib/getdef.c 2003-05-12 02:40:08.000000000 +0000 +++ shadow-4.0.4.1/lib/getdef.c 2007-05-01 09:52:38.000000000 +0000 @@ -55,6 +55,7 @@ static struct itemdef def_table[] = { { "CHFN_AUTH", NULL }, { "CHFN_RESTRICT", NULL }, + { "CIPHER", NULL }, #ifdef USE_PAM { "CLOSE_SESSIONS", NULL }, #endif @@ -62,6 +63,7 @@ { "CONSOLE_GROUPS", NULL }, { "CRACKLIB_DICTPATH", NULL }, { "CREATE_HOME", NULL }, + { "CRYPT_ROUNDS", NULL }, { "DEFAULT_HOME", NULL }, { "ENVIRON_FILE", NULL }, { "ENV_HZ", NULL }, @@ -89,7 +91,6 @@ { "MAIL_CHECK_ENAB", NULL }, { "MAIL_DIR", NULL }, { "MAIL_FILE", NULL }, - { "MD5_CRYPT_ENAB", NULL }, { "MOTD_FILE", NULL }, { "NOLOGINS_FILE", NULL }, { "NOLOGIN_STR", NULL }, diff -Naur shadow-4.0.4.1.orig/lib/md5.h shadow-4.0.4.1/lib/md5.h --- shadow-4.0.4.1.orig/lib/md5.h 1996-08-10 07:59:51.000000000 +0000 +++ shadow-4.0.4.1/lib/md5.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#ifndef MD5_H -#define MD5_H - -#ifdef __alpha -typedef unsigned int uint32; -#else -typedef unsigned long uint32; -#endif - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -void MD5Init(struct MD5Context *context); -void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); -void MD5Final(unsigned char digest[16], struct MD5Context *context); -void MD5Transform(uint32 buf[4], uint32 const in[16]); - -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ -typedef struct MD5Context MD5_CTX; - -#endif /* !MD5_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-hmac.c shadow-4.0.4.1/lib/openssl-hmac.c --- shadow-4.0.4.1.orig/lib/openssl-hmac.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-hmac.c 2007-05-01 09:52:38.000000000 +0000 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2004, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $NetBSD: hmac.c,v 1.1 2006/10/27 18:22:56 drochner Exp $ */ + +/* + * Implement HMAC as described in RFC 2104 + * + * You need to define the following before including this file. + * + * HMAC_FUNC the name of the function (hmac_sha1 or hmac_md5 etc) + * HASH_LENGTH the size of the digest (20 for SHA1, 16 for MD5) + * HASH_CTX the name of the HASH CTX + * HASH_Init + * HASH_Update + * Hash_Final + */ + +#include +#include + +/* If we want to use MD5-HMAC, then this #include needs to be + wrapped in an #ifdef. */ +#include "openssl-sha1.h" + +/* Don't change these */ +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +/* Nor this */ +#ifndef HMAC_BLOCKSZ +# define HMAC_BLOCKSZ 64 +#endif + +/* + * The logic here is lifted straight from RFC 2104 except that + * rather than filling the pads with 0, copying in the key and then + * XOR with the pad byte, we just fill with the pad byte and + * XOR with the key. + */ +void +HMAC_FUNC (const unsigned char *text, size_t text_len, + const unsigned char *key, size_t key_len, + unsigned char *digest) +{ + HASH_CTX context; + /* Inner padding key XOR'd with ipad */ + unsigned char k_ipad[HMAC_BLOCKSZ + 1]; + /* Outer padding key XOR'd with opad */ + unsigned char k_opad[HMAC_BLOCKSZ + 1]; + /* HASH(key) if needed */ + unsigned char tk[HASH_LENGTH]; + int i; + + /* + * If key is longer than HMAC_BLOCKSZ bytes + * reset it to key=HASH(key) + */ + if (key_len > HMAC_BLOCKSZ) { + HASH_CTX tctx; + + HASH_Init(&tctx); + HASH_Update(&tctx, key, key_len); + HASH_Final(tk, &tctx); + + key = tk; + key_len = HASH_LENGTH; + } + + /* + * The HMAC_ transform looks like: + * + * HASH(K XOR opad, HASH(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte HMAC_IPAD repeated HMAC_BLOCKSZ times + * opad is the byte HMAC_OPAD repeated HMAC_BLOCKSZ times + * and text is the data being protected + */ + + /* + * Fill the pads and XOR in the key + */ + memset( k_ipad, HMAC_IPAD, sizeof k_ipad); + memset( k_opad, HMAC_OPAD, sizeof k_opad); + for (i = 0; i < key_len; i++) { + k_ipad[i] ^= key[i]; + k_opad[i] ^= key[i]; + } + + /* + * Perform inner HASH. + * Start with inner pad, + * then the text. + */ + HASH_Init(&context); + HASH_Update(&context, k_ipad, HMAC_BLOCKSZ); + HASH_Update(&context, text, text_len); + HASH_Final(digest, &context); + + /* + * Perform outer HASH. + * Start with the outer pad, + * then the result of the inner hash. + */ + HASH_Init(&context); + HASH_Update(&context, k_opad, HMAC_BLOCKSZ); + HASH_Update(&context, digest, HASH_LENGTH); + HASH_Final(digest, &context); +} + diff -Naur shadow-4.0.4.1.orig/lib/openssl-md5.c shadow-4.0.4.1/lib/openssl-md5.c --- shadow-4.0.4.1.orig/lib/openssl-md5.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-md5.c 2007-05-01 09:52:38.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 + * ---------------------------------------------------------------------------- + * + * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ + * $OpenBSD: md5crypt.c,v 1.14 2005/08/08 08:05:33 espie Exp $ + * + */ + +/* + * Added is_md5_salt() and modified for Linux to use libcrypto. + * Robert Connolly + */ + +#include + +#include +#include +#include +#include + +#include "openssl-md5.h" + +static unsigned char *magic = (unsigned char *)MD5_MAGIC; + +int is_md5_salt(const char *); + +int +is_md5_salt(const char *salt) +{ + return (strncmp(salt, magic, strlen(magic)) == 0); +} + +char *md5_crypt(const char *pw, const char *salt); + +char * +md5_crypt(const char *pw, const char *salt) +{ + static char passwd[120], *p; + static const unsigned char *sp, *ep; + unsigned char final[MD5_DIGEST_LENGTH]; + int sl, pl, i; + MD5_CTX ctx,ctx1; + uint32_t l; + + /* Refine the Salt. */ + sp = (const unsigned char *)salt; + + /* Skip the magic string in the salt. */ + if(!strncmp((const char *)sp, (const char *)magic, strlen((const char *)magic))) + sp += strlen((const char *)magic); + + /* The salt stops at the first '$', maximum 8 characters. */ + for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* Get the length of the true salt. */ + sl = ep - sp; + + MD5_Init(&ctx); + + /* The password first, since that is what is most unknown. */ + MD5_Update(&ctx, (const unsigned char *)pw, strlen(pw)); + + /* Then our magic string. */ + MD5_Update(&ctx, magic, strlen((const char *)magic)); + + /* Then the raw salt. */ + MD5_Update(&ctx, sp, sl); + + /* Then just as many characters of the MD5(pw, salt, pw). */ + MD5_Init(&ctx1); + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_Update(&ctx1, sp, sl); + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_Final(final, &ctx1); + for(pl = strlen(pw); pl > 0; pl -= MD5_DIGEST_LENGTH) + MD5_Update(&ctx, final, pl > MD5_DIGEST_LENGTH ? MD5_DIGEST_LENGTH : pl); + + /* Don't leave anything around in virtual memeory. */ + memset(final, 0, sizeof final); + + /* Then something really weird... */ + for (i = strlen(pw); i ; i >>= 1) + if(i & 1) + MD5_Update(&ctx, final, 1); + else + MD5_Update(&ctx, (const unsigned char *)pw, 1); + + /* Now make the output string. */ + snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic, + sl, (const char *)sp); + + MD5_Final(final, &ctx); + + /* + * 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++) { + MD5_Init(&ctx1); + if(i & 1) + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + else + MD5_Update(&ctx1, final, MD5_DIGEST_LENGTH); + + if(i % 3) + MD5_Update(&ctx1, sp, sl); + + if(i % 7) + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + + if(i & 1) + MD5_Update(&ctx1, final, MD5_DIGEST_LENGTH); + else + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_Final(final, &ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0] << 16) | (final[ 6] << 8) | final[12]; + crypt_to64(p, l, 4); p += 4; + l = (final[ 1] << 16) | (final[ 7] << 8) | final[13]; + crypt_to64(p, l, 4); p += 4; + l = (final[ 2] << 16) | (final[ 8] << 8) | final[14]; + crypt_to64(p, l, 4); p += 4; + l = (final[ 3] << 16) | (final[ 9] << 8) | final[15]; + crypt_to64(p, l, 4); p += 4; + l = (final[ 4] << 16) | (final[10] << 8) | final[ 5]; + crypt_to64(p, l, 4); p += 4; + l = final[11] ; + crypt_to64(p, l, 2); p += 2; + *p = '\0'; + + /* Don't leave anything around in virtual memory. */ + memset(final, 0, sizeof final); + + return passwd; +} + diff -Naur shadow-4.0.4.1.orig/lib/openssl-md5.h shadow-4.0.4.1/lib/openssl-md5.h --- shadow-4.0.4.1.orig/lib/openssl-md5.h 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-md5.h 2007-05-01 09:52:38.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 + * ---------------------------------------------------------------------------- + */ + +/* $Id: md5crypt.h,v 1.4 2003/05/18 14:46:46 djm Exp $ */ + +#ifndef _SHADOW_OPENSSL_MD5_H +#define _SHADOW_OPENSSL_MD5_H + +#include + +#include + +int is_md5_salt(const char *); +char *md5_crypt(const char *, const char *); + +#define MD5_MAGIC "$1$" + +#endif /* _SHADOW_OPENSSL_MD5_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-sha1.c shadow-4.0.4.1/lib/openssl-sha1.c --- shadow-4.0.4.1.orig/lib/openssl-sha1.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-sha1.c 2007-05-01 12:09:01.000000000 +0000 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2004, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $NetBSD: crypt-sha1.c,v 1.3 2006/10/27 18:22:56 drochner Exp $ */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "openssl-sha1.h" + +/* + * The default iterations - should take >0s on a fast CPU + * but not be insane for a slow CPU. + */ +#ifndef CRYPT_SHA1_ITERATIONS +# define CRYPT_SHA1_ITERATIONS 24680 +#endif +/* + * Support a reasonably? long salt. + */ +#ifndef CRYPT_SHA1_SALT_LENGTH +# define CRYPT_SHA1_SALT_LENGTH 64 +#endif + +static unsigned char *magic = (unsigned char *)SHA1_MAGIC; + +int is_sha1_salt(const char *); + +int +is_sha1_salt(const char *salt) +{ + return (strncmp(salt, magic, strlen(magic)) == 0); +} + +/* + * This may be called from sha1_crypt or gensalt. + * + * The value returned will be slightly less than which defaults + * to 24680. The goals are that the number of iterations should take + * non-zero amount of time on a fast cpu while not taking insanely + * long on a slow cpu. The current default will take about 5 seconds + * on a 100MHz sparc, and about 0.04 seconds on a 3GHz i386. + * The number is varied to frustrate those attempting to generate a + * dictionary of pre-computed hashes. + */ +unsigned int +sha1_crypt_iterations (unsigned int hint) +{ + static int once = 1; + + /* + * We treat CRYPT_SHA1_ITERATIONS as a hint. + * Make it harder for someone to pre-compute hashes for a + * dictionary attack by not using the same iteration count for + * every entry. + */ + + if (once) { + int pid = getpid(); + + srandom(time(NULL) ^ (pid * pid)); + once = 0; + } + if (hint == 0) + hint = CRYPT_SHA1_ITERATIONS; + return hint - (random() % (hint / 4)); +} + +/* + * UNIX password using hmac_sha1 + * This is PBKDF1 from RFC 2898, but using hmac_sha1. + * + * The format of the encrypted password is: + * $$$$ + * + * where: + * is "sha1" + * is an unsigned int identifying how many rounds + * have been applied to . The number + * should vary slightly for each password to make + * it harder to generate a dictionary of + * pre-computed hashes. See crypt_sha1_iterations. + * up to 64 bytes of random data, 8 bytes is + * currently considered more than enough. + * the hashed password. + * + * NOTE: + * To be FIPS 140 compliant, the password which is used as a hmac key, + * should be between 10 and 20 characters to provide at least 80bits + * strength, and avoid the need to hash it before using as the + * hmac key. + */ +char * +sha1_crypt (const char *pw, const char *salt) +{ + static unsigned char hmac_buf[SHA_DIGEST_LENGTH]; + static char passwd[(2 * sizeof(SHA1_MAGIC)) + + CRYPT_SHA1_SALT_LENGTH + SHA_DIGEST_LENGTH]; + char *sp; + char *ep; + unsigned long ul; + int sl; + int pl; + int dl; + unsigned int iterations; + unsigned int i; + + /* + * Salt format is + * $$$salt[$] + * If it does not start with $ we use our default iterations. + */ + sp = (void *)(const unsigned char *)salt; + + /* If it starts with the magic string, then skip that */ + if (!strncmp(sp, magic, strlen(magic))) { + sp += strlen(magic); + /* and get the iteration count */ + iterations = strtoul(sp, &ep, 10); + if (*ep != '$') + return NULL; /* invalid input */ + sp = ep + 1; /* skip over the '$' */ + } else { + iterations = sha1_crypt_iterations(0); + } + + /* It stops at the next '$', max CRYPT_SHA1_ITERATIONS chars */ + for (ep = sp; *ep && *ep != '$' && ep < (sp + CRYPT_SHA1_ITERATIONS); ep++) + continue; + + /* Get the length of the actual salt */ + sl = ep - sp; + pl = strlen(pw); + + /* + * Now get to work... + * Prime the pump with + */ + dl = snprintf(passwd, sizeof (passwd), "%.*s%s%u", + sl, sp, magic, iterations); + /* + * Then hmac using as key, and repeat... + */ + ep = (void *)(const unsigned char *)pw; + hmac_sha1(passwd, dl, ep, pl, hmac_buf); + for (i = 1; i < iterations; i++) { + hmac_sha1(hmac_buf, SHA_DIGEST_LENGTH, ep, pl, hmac_buf); + } + /* Now output... */ + pl = snprintf(passwd, sizeof(passwd), "%s%u$%.*s$", + magic, iterations, sl, sp); + ep = passwd + pl; + + /* Every 3 bytes of hash gives 24 bits which is 4 base64 chars */ + for (i = 0; i < SHA_DIGEST_LENGTH - 3; i += 3) { + ul = (hmac_buf[i+0] << 16) | + (hmac_buf[i+1] << 8) | + hmac_buf[i+2]; + crypt_to64(ep, ul, 4); ep += 4; + } + /* Only 2 bytes left, so we pad with byte0 */ + ul = (hmac_buf[SHA_DIGEST_LENGTH - 2] << 16) | + (hmac_buf[SHA_DIGEST_LENGTH - 1] << 8) | + hmac_buf[0]; + crypt_to64(ep, ul, 4); ep += 4; + *ep = '\0'; + + /* Don't leave anything around in virtual memory. */ + memset(hmac_buf, 0, sizeof hmac_buf); + + return passwd; +} diff -Naur shadow-4.0.4.1.orig/lib/openssl-sha1.h shadow-4.0.4.1/lib/openssl-sha1.h --- shadow-4.0.4.1.orig/lib/openssl-sha1.h 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-sha1.h 2007-05-01 09:52:38.000000000 +0000 @@ -0,0 +1,29 @@ +/* + * hmac_sha1 - using HMAC from RFC 2104 + */ + +/* $NetBSD: hmac_sha1.c,v 1.1 2006/10/27 18:22:56 drochner Exp $ */ + +#ifndef _SHADOW_OPENSSL_SHA1_H +#define _SHADOW_OPENSSL_SHA1_H + +#include + +#include + +int is_sha1_salt(const char *); +char *sha1_crypt(const char *, const char *); + +#define HMAC_HASH SHA1 +#define HMAC_FUNC hmac_sha1 +#define HMAC_KAT hmac_kat_sha1 + +#define HASH_LENGTH SHA_DIGEST_LENGTH +#define HASH_CTX SHA_CTX +#define HASH_Init SHA1_Init +#define HASH_Update SHA1_Update +#define HASH_Final SHA1_Final + +#define SHA1_MAGIC "$sha1$" + +#endif /* _SHADOW_OPENSSL_SHA1_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-util.c shadow-4.0.4.1/lib/openssl-util.c --- shadow-4.0.4.1.orig/lib/openssl-util.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-util.c 2007-05-01 11:10:25.000000000 +0000 @@ -0,0 +1,43 @@ +/* $NetBSD: util.c,v 1.1 2004/07/02 00:05:23 sjg Exp $ */ + +#include + +#include + +#include "prototypes.h" +#include "defines.h" +#include "getdef.h" + +/* 0 ... 63 => ascii - 64 */ +static const unsigned char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void crypt_to64(char *, uint32_t, int); + +void +crypt_to64(char *s, uint32_t v, int n) +{ + + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} + +int get_pass_max_len(void); + +int get_pass_max_len(void) +{ + int pass_max_len; + char *cipher_type = getdef_str ("CIPHER"); + + if (strcmp (cipher_type, "des") == 0) { + pass_max_len = DES_PASSWORD_LENGTH; + } else if (strcmp (cipher_type, "blowfish") == 0) { + pass_max_len = BLOWFISH_PASSWORD_LENGTH; + } else { + pass_max_len = MAX_PASSWORD_LENGTH; + } + + return pass_max_len; +} diff -Naur shadow-4.0.4.1.orig/lib/prototypes.h shadow-4.0.4.1/lib/prototypes.h --- shadow-4.0.4.1.orig/lib/prototypes.h 2003-04-25 21:33:47.000000000 +0000 +++ shadow-4.0.4.1/lib/prototypes.h 2007-05-01 12:16:06.000000000 +0000 @@ -136,6 +136,9 @@ /* obscure.c */ extern int obscure(const char *, const char *, const struct passwd *); +/* openssl-util.c */ +extern int get_pass_max_len(void); + /* pam_pass.c */ extern int do_pam_passwd(const char *, int, int); @@ -170,7 +173,7 @@ extern int do_rlogin(const char *, char *, int, char *, int); /* salt.c */ -extern char *crypt_make_salt(void); +extern int pw_gensalt(char *, size_t, const char *, const char *); /* setugid.c */ extern int setup_groups(const struct passwd *); diff -Naur shadow-4.0.4.1.orig/libmisc/obscure.c shadow-4.0.4.1/libmisc/obscure.c --- shadow-4.0.4.1.orig/libmisc/obscure.c 2003-05-05 21:44:15.000000000 +0000 +++ shadow-4.0.4.1/libmisc/obscure.c 2007-05-01 09:55:29.000000000 +0000 @@ -231,9 +231,6 @@ Example: "password$%^&*123". So check it again, this time truncated to the maximum length. Idea from npasswd. --marekm */ - if (getdef_bool ("MD5_CRYPT_ENAB")) - return NULL; /* unlimited password length */ - maxlen = getdef_num ("PASS_MAX_LEN", 8); if (oldlen <= maxlen && newlen <= maxlen) return NULL; diff -Naur shadow-4.0.4.1.orig/libmisc/salt.c shadow-4.0.4.1/libmisc/salt.c --- shadow-4.0.4.1.orig/libmisc/salt.c 2003-04-22 10:59:22.000000000 +0000 +++ shadow-4.0.4.1/libmisc/salt.c 2007-05-01 12:15:52.000000000 +0000 @@ -1,64 +1,185 @@ /* - * salt.c - generate a random salt string for crypt() + * Copyright 1997 Niels Provos + * All rights reserved. * - * Written by Marek Michalkiewicz , - * public domain. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Niels Provos. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from OpenBSD: pwd_gensalt.c,v 1.9 1998/07/05 21:08:32 provos Exp + * $NetBSD: pw_gensalt.c,v 1.6 2007/01/17 23:24:22 hubertf Exp $ */ #include -#include "rcsid.h" -RCSID ("$Id: salt.c,v 1.6 2003/04/22 10:59:22 kloczek Exp $") -#include "prototypes.h" -#include "defines.h" +#include +#include +#include +#include +#include +#include #include -#if 1 -#include "getdef.h" -extern char *l64a (); +#include -/* - * Generate 8 base64 ASCII characters of random salt. If MD5_CRYPT_ENAB - * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$" - * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible - * version of crypt() instead of the standard one. - */ -char *crypt_make_salt (void) +#include +#include + +//int __gensalt_blowfish(char *salt, size_t saltlen, const char *option); +int gensalt_old(char *salt, size_t saltsiz, const char *option); +//int __gensalt_new(char *salt, size_t saltsiz, const char *option); +int gensalt_md5(char *salt, size_t saltsiz, const char *option); +int gensalt_sha1(char *salt, size_t saltsiz, const char *option); + +static const struct pw_salt { + const char *name; + int (*gensalt)(char *, size_t, const char *); +} salts[] = { + { "des", gensalt_old }, +// { "new", __gensalt_new }, +// { "newsalt", __gensalt_new }, + { "md5", gensalt_md5 }, + { "sha1", gensalt_sha1 }, +// { "blowfish", __gensalt_blowfish }, + { NULL, NULL } +}; + +static int +getnum(const char *str, size_t *num) { - struct timeval tv; - static char result[40]; + char *ep; + unsigned long rv; - result[0] = '\0'; - if (getdef_bool ("MD5_CRYPT_ENAB")) { - strcpy (result, "$1$"); /* magic for the new MD5 crypt() */ + if (str == NULL) { + *num = 0; + return 0; } - /* - * Generate 8 chars of salt, the old crypt() will use only first 2. - */ - gettimeofday (&tv, (struct timezone *) 0); - strcat (result, l64a (tv.tv_usec)); - strcat (result, l64a (tv.tv_sec + getpid () + clock ())); + rv = strtoul(str, &ep, 0); + + if (str == ep || *ep) { + errno = EINVAL; + return -1; + } - if (strlen (result) > 3 + 8) /* magic+salt */ - result[11] = '\0'; + if (errno == ERANGE && rv == ULONG_MAX) + return -1; + *num = (size_t)rv; + return 0; +} - return result; +int +/*ARGSUSED2*/ +gensalt_old(char *salt, size_t saltsiz, const char *option) +{ + if (saltsiz < 3) { + errno = ENOSPC; + return -1; + } + crypt_to64(&salt[0], arc4random(), 2); + salt[2] = '\0'; + return 0; } -#else -/* - * This is the old style random salt generator... - */ -char *crypt_make_salt (void) + +#if 0 +int +/*ARGSUSED2*/ +gensalt_new(char *salt, size_t saltsiz, const char* option) { - time_t now; - static unsigned long x; - static char result[3]; - - time (&now); - x += now + getpid () + clock (); - result[0] = i64c (((x >> 18) ^ (x >> 6)) & 077); - result[1] = i64c (((x >> 12) ^ x) & 077); - result[2] = '\0'; - return result; + size_t nrounds; + + if (saltsiz < 10) { + errno = ENOSPC; + return -1; + } + + if (getnum(option, &nrounds) == -1) + return -1; + + /* Check rounds, 24 bit is max */ + if (nrounds < 7250) + nrounds = 7250; + else if (nrounds > 0xffffff) + nrounds = 0xffffff; + salt[0] = _PASSWORD_EFMT1; + __crypt_to64(&salt[1], (uint32_t)nrounds, 4); + __crypt_to64(&salt[5], arc4random(), 4); + salt[9] = '\0'; + return 0; } #endif + +int +/*ARGSUSED2*/ +gensalt_md5(char *salt, size_t saltsiz, const char *option) +{ + if (saltsiz < 13) { /* $1$8salt$\0 */ + errno = ENOSPC; + return -1; + } + salt[0] = '$'; + salt[1] = '1'; + salt[2] = '$'; + crypt_to64(&salt[3], arc4random(), 4); + crypt_to64(&salt[7], arc4random(), 4); + salt[11] = '$'; + salt[12] = '\0'; + return 0; +} + +int +gensalt_sha1(char *salt, size_t saltsiz, const char *option) +{ + int n; + size_t nrounds; + + if (getnum(option, &nrounds) == -1) + return -1; + n = snprintf(salt, saltsiz, "%s%u$", SHA1_MAGIC, + sha1_crypt_iterations(nrounds)); + /* + * The salt can be up to 64 bytes, but 8 + * is considered enough for now. + */ + if (n + 9 >= saltsiz) + return 0; + crypt_to64(&salt[n], arc4random(), 4); + crypt_to64(&salt[n + 4], arc4random(), 4); + salt[n + 8] = '$'; + salt[n + 9] = '\0'; + return 0; +} + +int +pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option) +{ + const struct pw_salt *sp; + + for (sp = salts; sp->name; sp++) + if (strcmp(sp->name, type) == 0) + return (*sp->gensalt)(salt, saltlen, option); + + errno = EINVAL; + return -1; +} + diff -Naur shadow-4.0.4.1.orig/libmisc/xmalloc.c shadow-4.0.4.1/libmisc/xmalloc.c --- shadow-4.0.4.1.orig/libmisc/xmalloc.c 2003-04-22 10:59:22.000000000 +0000 +++ shadow-4.0.4.1/libmisc/xmalloc.c 2007-05-01 09:52:38.000000000 +0000 @@ -12,14 +12,14 @@ #include "rcsid.h" RCSID ("$Id: xmalloc.c,v 1.4 2003/04/22 10:59:22 kloczek Exp $") #include +#include #include "defines.h" -extern char *malloc (); char *xmalloc (size_t size) { char *ptr; - ptr = malloc (size); + ptr = (char *)malloc (size); if (!ptr && size) { fprintf (stderr, _("malloc(%d) failed\n"), (int) size); exit (13); diff -Naur shadow-4.0.4.1.orig/src/chpasswd.c shadow-4.0.4.1/src/chpasswd.c --- shadow-4.0.4.1.orig/src/chpasswd.c 2003-06-19 18:11:01.000000000 +0000 +++ shadow-4.0.4.1/src/chpasswd.c 2007-05-01 12:05:44.000000000 +0000 @@ -32,6 +32,7 @@ #include "rcsid.h" RCSID (PKG_VER "$Id: chpasswd.c,v 1.18 2003/06/19 18:11:01 kloczek Exp $") #include +#include #include "prototypes.h" #include "defines.h" #include @@ -46,6 +47,8 @@ #include #include #endif /* USE_PAM */ +#include "getdef.h" + static char *Prog; static int eflg = 0; @@ -92,6 +95,10 @@ int line = 0; long now = time ((long *) 0) / (24L * 3600L); int ok; + int pass_max_len = get_pass_max_len(); + char salt[pass_max_len+1]; + char *cipher_rounds = getdef_str ("CRYPT_ROUNDS"); + char *cipher_type = getdef_str ("CIPHER"); #ifdef USE_PAM pam_handle_t *pamh = NULL; @@ -220,8 +227,14 @@ continue; } newpwd = cp; - if (!eflg) - cp = pw_encrypt (newpwd, crypt_make_salt ()); + if (!eflg) { + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + return FALSE; + } + cp = pw_encrypt (newpwd, salt); + } /* * Get the password file entry for this user. The user must diff -Naur shadow-4.0.4.1.orig/src/gpasswd.c shadow-4.0.4.1/src/gpasswd.c --- shadow-4.0.4.1.orig/src/gpasswd.c 2003-06-19 18:11:01.000000000 +0000 +++ shadow-4.0.4.1/src/gpasswd.c 2007-05-01 12:13:43.000000000 +0000 @@ -33,6 +33,7 @@ RCSID (PKG_VER "$Id: gpasswd.c,v 1.21 2003/06/19 18:11:01 kloczek Exp $") #include #include +#include #include #include #include @@ -191,6 +192,11 @@ char *group = NULL; char *members = NULL; + int pass_max_len = get_pass_max_len(); + char salt[pass_max_len+1]; + char *cipher_rounds = getdef_str ("CRYPT_ROUNDS"); + char *cipher_type = getdef_str ("CIPHER"); + sanitize_env (); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); @@ -547,7 +553,12 @@ exit (1); } - cp = pw_encrypt (pass, crypt_make_salt ()); + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + exit (FALSE); + } + cp = pw_encrypt (pass, salt); memzero (pass, sizeof pass); #ifdef SHADOWGRP if (is_shadowgrp) diff -Naur shadow-4.0.4.1.orig/src/newusers.c shadow-4.0.4.1/src/newusers.c --- shadow-4.0.4.1.orig/src/newusers.c 2003-12-17 01:33:29.000000000 +0000 +++ shadow-4.0.4.1/src/newusers.c 2007-05-01 12:05:18.000000000 +0000 @@ -42,6 +42,7 @@ #include "prototypes.h" #include "defines.h" #include +#include #include #include #include @@ -231,7 +232,16 @@ static void update_passwd (struct passwd *pwd, const char *passwd) { - pwd->pw_passwd = pw_encrypt (passwd, crypt_make_salt ()); + int pass_max_len = get_pass_max_len(); + char salt[pass_max_len+1]; + char *cipher_rounds = getdef_str ("CRYPT_ROUNDS"); + char *cipher_type = getdef_str ("CIPHER"); + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + exit (FALSE); + } + pwd->pw_passwd = pw_encrypt (passwd, salt); } /* @@ -244,6 +254,10 @@ const struct spwd *sp; struct spwd spent; #endif + int pass_max_len = get_pass_max_len(); + char salt[pass_max_len+1]; + char *cipher_rounds = getdef_str ("CRYPT_ROUNDS"); + char *cipher_type = getdef_str ("CIPHER"); /* * In the case of regular password files, this is real easy - pwd @@ -262,8 +276,13 @@ */ if ((sp = spw_locate (pwd->pw_name))) { + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + return FALSE; + } spent = *sp; - spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ()); + spent.sp_pwdp = pw_encrypt (passwd, salt); return !spw_update (&spent); } @@ -285,7 +304,12 @@ */ spent.sp_namp = pwd->pw_name; - spent.sp_pwdp = pw_encrypt (passwd, crypt_make_salt ()); + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + return FALSE; + } + spent.sp_pwdp = pw_encrypt (passwd, salt); spent.sp_lstchg = time ((time_t *) 0) / SCALE; spent.sp_min = getdef_num ("PASS_MIN_DAYS", 0); /* 10000 is infinity this week */ diff -Naur shadow-4.0.4.1.orig/src/passwd.c shadow-4.0.4.1/src/passwd.c --- shadow-4.0.4.1.orig/src/passwd.c 2003-12-17 09:43:30.000000000 +0000 +++ shadow-4.0.4.1/src/passwd.c 2007-05-01 12:06:10.000000000 +0000 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -197,11 +198,14 @@ char *clear; /* Pointer to clear text */ char *cipher; /* Pointer to cipher text */ char *cp; /* Pointer to getpass() response */ + int pass_max_len = get_pass_max_len(); /* via login.defs */ char orig[200]; /* Original password */ - char pass[200]; /* New password */ + char pass[pass_max_len]; /* New password */ + char salt[pass_max_len+1]; + char *cipher_rounds = getdef_str ("CRYPT_ROUNDS"); + char *cipher_type = getdef_str ("CIPHER"); int i; /* Counter for retries */ int warned; - int pass_max_len; #ifdef HAVE_LIBCRACK_HIST int HistUpdate (const char *, const char *); @@ -240,11 +244,6 @@ * for initial login passwords. */ - if (getdef_bool ("MD5_CRYPT_ENAB")) - pass_max_len = 127; - else - pass_max_len = getdef_num ("PASS_MAX_LEN", 8); - if (!qflg) printf (_("\ Enter the new password (minimum of %d, maximum of %d characters)\n\ @@ -301,7 +300,12 @@ * Encrypt the password, then wipe the cleartext password. */ - cp = pw_encrypt (pass, crypt_make_salt ()); + if (pw_gensalt(salt, pass_max_len, cipher_type, cipher_rounds) == -1) { + fprintf (stderr, + _("Could not generate salt\n")); + return E_FAILURE; + } + cp = pw_encrypt(pass, salt); memzero (pass, sizeof pass); #ifdef HAVE_LIBCRACK_HIST