Submitted By: Robert Connolly (ashes) Date: 2005-02-04 Initial Package Version: 4.0.7 Upstream Status: Not submitted Origin: http://www.openwall.com/crypt/contrib/\ shadow-4.0.3-crypt_blowfish.diff.gz Description: Adds blowfish passwords to shadow. This depends on a blowfish library. See: http://www.openwall.com/crypt/ or http://ftp.suse.com/pub/people/kukuk/pam/libxcrypt/ If you use libxcrypt you need to do: sed -e 's/lcrypt/lxcrypt/g' -i configure This is the autoconf version. Run: autoconf There's a hint for this patch here: http://www.linuxfromscratch.org/hints/downloads/files/blowfish-passwords.txt diff -Naur shadow-4.0.7.orig/acconfig.h shadow-4.0.7/acconfig.h --- shadow-4.0.7.orig/acconfig.h 2005-02-04 13:06:12.152309336 +0000 +++ shadow-4.0.7/acconfig.h 2005-02-04 13:13:03.424272008 +0000 @@ -8,6 +8,9 @@ /* Path for faillog file. */ #undef FAILLOG_FILE +/* Defined if you have blowfish crypt. */ +#undef HAVE_CRYPT_GENSALT + /* Defined if you have libcrack. */ #undef HAVE_LIBCRACK @@ -44,6 +47,9 @@ /* Path to passwd program. */ #undef PASSWD_PROGRAM +/* Where is /dev/urandom or a /dev/urandom-alike. */ +#undef RANDOM_FILE + /* Define if login should support the -r flag for rlogind. */ #undef RLOGIN diff -Naur shadow-4.0.7.orig/config.h.in shadow-4.0.7/config.h.in --- shadow-4.0.7.orig/config.h.in 2005-02-04 13:06:11.841356608 +0000 +++ shadow-4.0.7/config.h.in 2005-02-04 13:13:18.862466696 +0000 @@ -9,6 +9,9 @@ /* Path for faillog file. */ #undef FAILLOG_FILE +/* Defined if you have blowfish crypt. */ +#undef HAVE_CRYPT_GENSALT + /* Defined if you have libcrack. */ #undef HAVE_LIBCRACK @@ -45,6 +48,9 @@ /* Path to passwd program. */ #undef PASSWD_PROGRAM +/* Where is /dev/urandom or a /dev/urandom-alike. */ +#undef RANDOM_FILE + /* Define if login should support the -r flag for rlogind. */ #undef RLOGIN diff -Naur shadow-4.0.7.orig/configure.in shadow-4.0.7/configure.in --- shadow-4.0.7.orig/configure.in 2005-02-04 13:06:11.857354176 +0000 +++ shadow-4.0.7/configure.in 2005-02-04 13:16:41.669382224 +0000 @@ -202,6 +202,23 @@ AC_ARG_WITH(libskey, [ --with-libskey use libskey for S/Key support]) AC_ARG_WITH(selinux, [ --with-selinux use SELinux support]) +AC_ARG_WITH(random, + [ --with-random=FILE read randomness from FILE (default=/dev/urandom)], + [ RANDOM_FILE="$withval" ], + [ + dnl Check for random device + AC_CHECK_FILE("/dev/urandom", + [ + RANDOM_FILE="/dev/urandom"; + ] + ) + ] +) +if test -n "$RANDOM_FILE" ; then + AC_SUBST(RANDOM_FILE) + AC_DEFINE_UNQUOTED(RANDOM_FILE, "$RANDOM_FILE") +fi + dnl Check for some functions in libc first, only if not found check for dnl other libraries. This should prevent linking libnsl if not really dnl needed (Linux glibc, Irix), but still link it if needed (Solaris). @@ -226,6 +243,7 @@ AC_SUBST(LIBCRYPT) if test "$with_libcrypt" != "no"; then AC_CHECK_LIB(crypt, crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypt]) + AC_CHECK_LIB(crypt, crypt_gensalt, AC_DEFINE(HAVE_CRYPT_GENSALT)) fi AC_SUBST(LIBCRACK) diff -Naur shadow-4.0.7.orig/etc/login.defs.linux shadow-4.0.7/etc/login.defs.linux --- shadow-4.0.7.orig/etc/login.defs.linux 2005-02-04 13:06:11.878350984 +0000 +++ shadow-4.0.7/etc/login.defs.linux 2005-02-04 13:18:59.931363208 +0000 @@ -260,13 +260,6 @@ PASS_ALWAYS_WARN yes # -# 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 - -# # Require password before chfn/chsh can make any changes. # CHFN_AUTH yes @@ -287,14 +280,62 @@ #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". +# Each password entry contains a prefix that specifies the hashing algorithm +# used to create the remaining characters/bytes. Use this setting to specify +# which hashing algorithm is used to create new passwords. +# +# The default here is to use the Blowfish-based algorithm, (which currently +# requires you to be running a patched version of glibc). To use the slightly +# more compatible MD5-based algorithm, you would set this to $1$. To be +# completely backwards compatible and use the traditional DES-based hashing, +# you should set this value to an empty string, but be warned, passwords using +# this algorithm offer very little security. +# +CRYPT_PREFIX "$2a$" + +# +# For hashing algorithms that can alter their complexity, use this setting to +# achieve a balance between the security of the password and performance on the +# host system. +# +# This value is interpreted by each algorithm in specific ways. With the +# Blowfish algorithm, it specifies the number of rounds as a base-2 logarithm +# of the actual iteration count, so 12 actually refers to 2^12. Altering the +# value to 11 would therefore halve the number of iterations used to 2^11. +# +# Make sure that if you alter the above setting, this setting is also +# appropriate. For algorithms that have fixed iteration counts, or to +# enforce the use of a low default value, use a setting of 0. +# +CRYPT_ROUNDS 12 + +# +# All algorithms require varying amounts of random bytes known as salt. For +# example the DES-based algorithm requires only 12-bits, (1½ bytes), whereas +# the Blowfish-based algorithm requires 128-bits, (16 bytes). +# +# If an algorithm doesn't receive enough salt, more will be collected from +# /dev/urandom, a byte at a time until it's satisfied. If you know how much +# is enough to satisfy even the most hungry of algorithms locally available, +# setting it here will speed up the generation of passwords. +# +# A maximum is also provided to enforce an upper limit on this to prevent a +# wayward algorithm munching all the randomness unnecessarily. +# +CRYPT_MINSALT 16 +CRYPT_MAXSALT 32 + +# +# Number of significant characters in the password for crypt(). MD5 can +# effectively cope with unlimited length passwords, but a limit of ~127 is +# reasonable. Blowfish can handle up to 72 characters, and the DES algorithm +# can only handle 8. +# +# This setting is used in some of the obscure checks, and also to inform the +# user on how big their new password should be, so it should be set in +# accordance to the choice of algorithm. # -#MD5_CRYPT_ENAB no +PASS_MAX_LEN 72 # # List of groups to add to the user's supplementary group set diff -Naur shadow-4.0.7.orig/lib/getdef.c shadow-4.0.7/lib/getdef.c --- shadow-4.0.7.orig/lib/getdef.c 2005-02-04 13:06:11.888349464 +0000 +++ shadow-4.0.7/lib/getdef.c 2005-02-04 13:08:02.577522152 +0000 @@ -63,6 +63,12 @@ { "CONSOLE_GROUPS", NULL }, { "CRACKLIB_DICTPATH", NULL }, { "CREATE_HOME", NULL }, +#ifdef HAVE_CRYPT_GENSALT + { "CRYPT_MAXSALT", NULL }, + { "CRYPT_MINSALT", NULL }, + { "CRYPT_PREFIX", NULL }, + { "CRYPT_ROUNDS", NULL }, +#endif /* HAVE_CRYPT_GENSALT */ { "DEFAULT_HOME", NULL }, { "ENVIRON_FILE", NULL }, { "ENV_HZ", NULL }, @@ -90,7 +96,9 @@ { "MAIL_CHECK_ENAB", NULL }, { "MAIL_DIR", NULL }, { "MAIL_FILE", NULL }, +#ifndef HAVE_CRYPT_GENSALT { "MD5_CRYPT_ENAB", NULL }, +#endif /* ! HAVE_CRYPT_GENSALT */ { "MOTD_FILE", NULL }, { "NOLOGINS_FILE", NULL }, { "NOLOGIN_STR", NULL }, diff -Naur shadow-4.0.7.orig/libmisc/obscure.c shadow-4.0.7/libmisc/obscure.c --- shadow-4.0.7.orig/libmisc/obscure.c 2005-02-04 13:06:11.920344600 +0000 +++ shadow-4.0.7/libmisc/obscure.c 2005-02-04 13:20:53.056165624 +0000 @@ -231,8 +231,10 @@ Example: "password$%^&*123". So check it again, this time truncated to the maximum length. Idea from npasswd. --marekm */ +#ifndef HAVE_CRYPT_GENSALT if (getdef_bool ("MD5_CRYPT_ENAB")) return NULL; /* unlimited password length */ +#endif maxlen = getdef_num ("PASS_MAX_LEN", 8); if (oldlen <= maxlen && newlen <= maxlen) diff -Naur shadow-4.0.7.orig/libmisc/salt.c shadow-4.0.7/libmisc/salt.c --- shadow-4.0.7.orig/libmisc/salt.c 2005-02-04 13:06:11.922344296 +0000 +++ shadow-4.0.7/libmisc/salt.c 2005-02-04 13:22:49.523459904 +0000 @@ -3,8 +3,12 @@ * * Written by Marek Michalkiewicz , * public domain. + * + * Broken by Matt Dainty */ +#define _OW_SOURCE + #include #include "rcsid.h" @@ -12,8 +16,97 @@ #include "prototypes.h" #include "defines.h" #include -#if 1 + +#ifdef HAVE_CRYPT_GENSALT +#include +#include +#include +#include +#include +#include "getdef.h" + +/* Soopa-doopa salt generation function. There isn't anything algorithm + * specific in here, although it does require the Openwall-patched glibc to + * provide the crypt_gensalt() function, as well as make use of Blowfish-based + * hashing. + * + * All parameters can be customised from the /etc/login.defs file + * + * Written by Matt Dainty + */ +char * +crypt_make_salt(void) +{ + char *result, *salt; + int fd, offset, minsalt, maxsalt, count; + + minsalt = getdef_num( "CRYPT_MINSALT", 16 ); + maxsalt = getdef_num( "CRYPT_MAXSALT", 32 ); + + if( minsalt > maxsalt ) { + fprintf( stderr, "Check the CRYPT_MINSALT and CRYPT_MAXSALT settings!\n" ); + exit(1); + } + + if( ( salt = ( char * ) malloc( maxsalt ) ) == NULL ) { + fprintf( stderr, "Can't allocate %d bytes of memory\n", maxsalt ); + exit(1); + } + + if( ( fd = open( RANDOM_FILE, O_RDONLY ) ) < 0 ) { + fprintf( stderr, "Can't open %s for reading\n", RANDOM_FILE ); + free( salt ); + exit(1); + } + + offset = 0; + result = NULL; + + while( !result ) { + while( offset < minsalt ) { + count = read( fd, &salt[offset], minsalt - offset ); + if( count <= 0 ) { + if( errno == EINTR ) + continue; + goto finish; + } + offset += count; + } + result = crypt_gensalt( getdef_str( "CRYPT_PREFIX" ), + getdef_num( "CRYPT_ROUNDS", 0 ), + salt, minsalt ); + + if( !result && errno == EINVAL ) { + if( minsalt < maxsalt ) { + minsalt++; + } else { + fprintf( stderr, "CRYPT_PREFIX or CRYPT_ROUNDS is set incorrectly\n" ); + goto finish; + } + } + } + +finish: + if( salt ) + free( salt ); + if( fd ) + close( fd ); + + /* XXX If we return the salt string as NULL, crypt will currently + * segfault, so if have we a NULL salt string, exit here. + * Otherwise, every invocation of crypt_make_salt() will have to + * check for a NULL return value. + * + * This way, I don't muck up any more code! :-) + */ + if( result ) + return result; + + exit(1); +} +#elif 1 /* HAVE_CRYPT_GENSALT */ #include "getdef.h" + extern char *l64a (); /* diff -Naur shadow-4.0.7.orig/src/passwd.c shadow-4.0.7/src/passwd.c --- shadow-4.0.7.orig/src/passwd.c 2005-02-04 13:06:12.145310400 +0000 +++ shadow-4.0.7/src/passwd.c 2005-02-04 13:08:02.597519112 +0000 @@ -240,9 +240,11 @@ * for initial login passwords. */ +#ifndef HAVE_CRYPT_GENSALT if (getdef_bool ("MD5_CRYPT_ENAB")) pass_max_len = 127; else +#endif pass_max_len = getdef_num ("PASS_MAX_LEN", 8); if (!qflg)