diff --git a/configure.ac b/configure.ac index a97d3917..d0443460 100644 --- a/configure.ac +++ b/configure.ac @@ -277,6 +277,9 @@ AC_ARG_WITH(libcrack, AC_ARG_WITH(sha-crypt, [AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])], [with_sha_crypt=$withval], [with_sha_crypt=yes]) +AC_ARG_WITH(bcrypt, + [AC_HELP_STRING([--with-bcrypt], [allow the bcrypt password encryption algorithm @<:@default=no@:>@])], + [with_bcrypt=$withval], [with_bcrypt=no]) AC_ARG_WITH(nscd, [AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])], [with_nscd=$withval], [with_nscd=yes]) @@ -304,6 +307,11 @@ if test "$with_sha_crypt" = "yes"; then AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms]) fi +AM_CONDITIONAL(USE_BCRYPT, test "x$with_bcrypt" = "xyes") +if test "$with_bcrypt" = "yes"; then + AC_DEFINE(USE_BCRYPT, 1, [Define to allow the bcrypt password encryption algorithm]) +fi + if test "$with_nscd" = "yes"; then AC_CHECK_FUNC(posix_spawn, [AC_DEFINE(USE_NSCD, 1, [Define to support flushing of nscd caches])], @@ -732,6 +740,7 @@ echo " tcb support (incomplete): $with_tcb" echo " shadow group support: $enable_shadowgrp" echo " S/Key support: $with_skey" echo " SHA passwords encryption: $with_sha_crypt" +echo " bcrypt passwords encryption: $with_bcrypt" echo " nscd support: $with_nscd" echo " sssd support: $with_sssd" echo " subordinate IDs support: $enable_subids" diff --git a/etc/login.defs b/etc/login.defs index f235e1b4..cd2597dc 100644 --- a/etc/login.defs +++ b/etc/login.defs @@ -320,6 +320,7 @@ CHFN_RESTRICT rwh # If set to MD5, MD5-based algorithm will be used for encrypting password # If set to SHA256, SHA256-based algorithm will be used for encrypting password # If set to SHA512, SHA512-based algorithm will be used for encrypting password +# If set to BCRYPT, BCRYPT-based algorithm will be used for encrypting password # If set to DES, DES-based algorithm will be used for encrypting password (default) # Overrides the MD5_CRYPT_ENAB option # @@ -344,6 +345,21 @@ CHFN_RESTRICT rwh #SHA_CRYPT_MIN_ROUNDS 5000 #SHA_CRYPT_MAX_ROUNDS 5000 +# +# Only works if ENCRYPT_METHOD is set to BCRYPT. +# +# Define the number of BCRYPT rounds. +# With a lot of rounds, it is more difficult to brute-force the password. +# However, more CPU resources will be needed to authenticate users if +# this value is increased. +# +# If not specified, 13 rounds will be attempted. +# If only one of the MIN or MAX values is set, then this value will be used. +# If MIN > MAX, the highest value will be used. +# +#BCRYPT_MIN_ROUNDS 13 +#BCRYPT_MAX_ROUNDS 13 + # # List of groups to add to the user's supplementary group set # when logging in from the console (as determined by the CONSOLE diff --git a/lib/encrypt.c b/lib/encrypt.c index 53c99c94..4247f241 100644 --- a/lib/encrypt.c +++ b/lib/encrypt.c @@ -65,6 +65,9 @@ case '1': method = "MD5"; break; + case '2': + method = "BCRYPT"; + break; case '5': method = "SHA256"; break; diff --git a/lib/getdef.c b/lib/getdef.c index 939aea29..bbb273f4 100644 --- a/lib/getdef.c +++ b/lib/getdef.c @@ -110,6 +110,10 @@ static struct itemdef def_table[] = { #ifdef USE_SHA_CRYPT {"SHA_CRYPT_MAX_ROUNDS", NULL}, {"SHA_CRYPT_MIN_ROUNDS", NULL}, +#endif +#ifdef USE_BCRYPT + {"BCRYPT_MAX_ROUNDS", NULL}, + {"BCRYPT_MIN_ROUNDS", NULL}, #endif {"SUB_GID_COUNT", NULL}, {"SUB_GID_MAX", NULL}, diff --git a/libmisc/obscure.c b/libmisc/obscure.c index a0751237..15da7603 100644 --- a/libmisc/obscure.c +++ b/libmisc/obscure.c @@ -268,6 +268,9 @@ static /*@observer@*//*@null@*/const char *obscure_msg ( #ifdef USE_SHA_CRYPT || (strcmp (result, "SHA256") == 0) || (strcmp (result, "SHA512") == 0) +#endif +#ifdef USE_BCRYPT + || (strcmp (result, "BCRYPT") == 0) #endif ) { return NULL; diff --git a/libmisc/salt.c b/libmisc/salt.c index c72447ea..e1a7ac80 100644 --- a/libmisc/salt.c +++ b/libmisc/salt.c @@ -22,10 +22,16 @@ /* local function prototypes */ static void seedRNG (void); static /*@observer@*/const char *gensalt (size_t salt_size); -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) static long shadow_random (long min, long max); +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ +#ifdef USE_SHA_CRYPT static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds); #endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT +static /*@observer@*/const char *gensalt_bcrypt (void); +static /*@observer@*/const char *BCRYPT_salt_rounds (/*@null@*/int *prefered_rounds); +#endif /* USE_BCRYPT */ #ifndef HAVE_L64A static /*@observer@*/char *l64a(long value) @@ -79,8 +85,16 @@ static void seedRNG (void) * Add the salt prefix. */ #define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0' +#ifdef USE_BCRYPT +/* + * Using the Prefix $2a$ to enable an anti-collision safety measure in musl libc. + * Negatively affects a subset of passwords containing the '\xff' character, + * which is not valid UTF-8 (so "unlikely to cause much annoyance"). + */ +#define BCRYPTMAGNUM(array) (array)[0]=(array)[3]='$',(array)[1]='2',(array)[2]='a',(array)[4]='\0' +#endif /* USE_BCRYPT */ -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) /* It is not clear what is the maximum value of random(). * We assume 2^31-1.*/ #define RANDOM_MAX 0x7FFFFFFF @@ -105,14 +119,15 @@ static long shadow_random (long min, long max) } return ret; } +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ +#ifdef USE_SHA_CRYPT /* Default number of rounds if not explicitly specified. */ #define ROUNDS_DEFAULT 5000 /* Minimum number of rounds. */ #define ROUNDS_MIN 1000 /* Maximum number of rounds. */ #define ROUNDS_MAX 999999999 - /* * Return a salt prefix specifying the rounds number for the SHA crypt methods. */ @@ -165,6 +180,89 @@ static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds } #endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT +/* Default number of rounds if not explicitly specified. */ +#define B_ROUNDS_DEFAULT 13 +/* Minimum number of rounds. */ +#define B_ROUNDS_MIN 4 +/* Maximum number of rounds. */ +#define B_ROUNDS_MAX 31 +/* + * Return a salt prefix specifying the rounds number for the BCRYPT method. + */ +static /*@observer@*/const char *BCRYPT_salt_rounds (/*@null@*/int *prefered_rounds) +{ + static char rounds_prefix[4]; /* Max size: 31$ */ + long rounds; + + if (NULL == prefered_rounds) { + long min_rounds = getdef_long ("BCRYPT_MIN_ROUNDS", -1); + long max_rounds = getdef_long ("BCRYPT_MAX_ROUNDS", -1); + + if (((-1 == min_rounds) && (-1 == max_rounds)) || (0 == *prefered_rounds)) { + rounds = B_ROUNDS_DEFAULT; + } + else { + if (-1 == min_rounds) { + min_rounds = max_rounds; + } + + if (-1 == max_rounds) { + max_rounds = min_rounds; + } + + if (min_rounds > max_rounds) { + max_rounds = min_rounds; + } + + rounds = shadow_random (min_rounds, max_rounds); + } + } else { + rounds = *prefered_rounds; + } + + /* + * Sanity checks. + * Use 19 as an upper bound for now, + * because musl doesn't allow rounds >= 20. + */ + if (rounds < B_ROUNDS_MIN) { + rounds = B_ROUNDS_MIN; + } + + if (rounds > 19) { + /* rounds = B_ROUNDS_MAX; */ + rounds = 19; + } + + (void) snprintf (rounds_prefix, sizeof rounds_prefix, + "%2.2ld$", rounds); + + return rounds_prefix; +} + +#define BCRYPT_SALT_SIZE 22 +/* + * Generate a 22 character salt string for bcrypt. + */ +static /*@observer@*/const char *gensalt_bcrypt (void) +{ + static char salt[32]; + + salt[0] = '\0'; + + seedRNG (); + strcat (salt, l64a (random())); + do { + strcat (salt, l64a (random())); + } while (strlen (salt) < BCRYPT_SALT_SIZE); + + salt[BCRYPT_SALT_SIZE] = '\0'; + + return salt; +} +#endif /* USE_BCRYPT */ + /* * Generate salt of size salt_size. */ @@ -230,6 +328,11 @@ static /*@observer@*/const char *gensalt (size_t salt_size) if (0 == strcmp (method, "MD5")) { MAGNUM(result, '1'); +#ifdef USE_BCRYPT + } else if (0 == strcmp (method, "BCRYPT")) { + BCRYPTMAGNUM(result); + strcat(result, BCRYPT_salt_rounds((int *)arg)); +#endif /* USE_BCRYPT */ #ifdef USE_SHA_CRYPT } else if (0 == strcmp (method, "SHA256")) { MAGNUM(result, '5'); @@ -252,8 +355,18 @@ static /*@observer@*/const char *gensalt (size_t salt_size) * Concatenate a pseudo random salt. */ assert (sizeof (result) > strlen (result) + salt_len); - strncat (result, gensalt (salt_len), - sizeof (result) - strlen (result) - 1); +#ifdef USE_BCRYPT + if (0 == strcmp (method, "BCRYPT")) { + strncat (result, gensalt_bcrypt (), + sizeof (result) - strlen (result) - 1); + return result; + } else { +#endif /* USE_BCRYPT */ + strncat (result, gensalt (salt_len), + sizeof (result) - strlen (result) - 1); +#ifdef USE_BCRYPT + } +#endif /* USE_BCRYPT */ return result; } diff --git a/src/chgpasswd.c b/src/chgpasswd.c index e5f2eb7e..4013abb3 100644 --- a/src/chgpasswd.c +++ b/src/chgpasswd.c @@ -61,15 +61,18 @@ const char *Prog; static bool eflg = false; static bool md5flg = false; -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) static bool sflg = false; -#endif +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ static /*@null@*//*@observer@*/const char *crypt_method = NULL; #define cflg (NULL != crypt_method) #ifdef USE_SHA_CRYPT static long sha_rounds = 5000; #endif +#ifdef USE_BCRYPT +static long bcrypt_rounds = 13; +#endif #ifdef SHADOWGRP static bool is_shadow_grp; @@ -125,11 +128,15 @@ static /*@noreturn@*/void usage (int status) Prog); (void) fprintf (usageout, _(" -c, --crypt-method METHOD the crypt method (one of %s)\n"), -#ifndef USE_SHA_CRYPT +#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) "NONE DES MD5" -#else /* USE_SHA_CRYPT */ +#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + "NONE DES MD5 SHA256 SHA512 BCRYPT" +#elif defined(USE_SHA_CRYPT) "NONE DES MD5 SHA256 SHA512" -#endif /* USE_SHA_CRYPT */ +#else + "NONE DES MD5 BCRYPT" +#endif ); (void) fputs (_(" -e, --encrypted supplied passwords are encrypted\n"), usageout); (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); @@ -137,11 +144,11 @@ static /*@noreturn@*/void usage (int status) " the MD5 algorithm\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); -#ifdef USE_SHA_CRYPT - (void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n" +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) + (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA or BCRYPT\n" " crypt algorithms\n"), usageout); -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ (void) fputs ("\n", usageout); exit (status); @@ -161,14 +168,13 @@ static void process_flags (int argc, char **argv) {"help", no_argument, NULL, 'h'}, {"md5", no_argument, NULL, 'm'}, {"root", required_argument, NULL, 'R'}, -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) {"sha-rounds", required_argument, NULL, 's'}, -#endif +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ {NULL, 0, NULL, '\0'} }; - while ((c = getopt_long (argc, argv, -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) "c:ehmR:s:", #else "c:ehmR:", @@ -189,10 +195,33 @@ static void process_flags (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) case 's': sflg = true; - if (getlong(optarg, &sha_rounds) == 0) { + if ( ( ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512"))) + && (0 == getlong(optarg, &sha_rounds))) + || ( (0 == strcmp (crypt_method, "BCRYPT")) + && (0 == getlong(optarg, &bcrypt_rounds)))) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (E_USAGE); + } + break; +#elif defined(USE_SHA_CRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &sha_rounds)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (E_USAGE); + } + break; +#elif defined(USE_BCRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &bcrypt_rounds)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); @@ -200,6 +229,7 @@ static void process_flags (int argc, char **argv) } break; #endif + default: usage (E_USAGE); /*@notreached@*/break; @@ -217,7 +247,7 @@ static void process_flags (int argc, char **argv) */ static void check_flags (void) { -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) if (sflg && !cflg) { fprintf (stderr, _("%s: %s flag is only allowed with the %s flag\n"), @@ -241,6 +271,9 @@ static void check_flags (void) #ifdef USE_SHA_CRYPT && (0 != strcmp (crypt_method, "SHA256")) && (0 != strcmp (crypt_method, "SHA512")) +#endif +#ifdef USE_BCRYPT + && (0 != strcmp (crypt_method, "BCRYPT")) #endif ) { fprintf (stderr, @@ -464,10 +497,24 @@ int main (int argc, char **argv) if (md5flg) { crypt_method = "MD5"; } -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + if (sflg) { + if ( (0 == strcmp (crypt_method, "SHA256")) + || (0 == strcmp (crypt_method, "SHA512"))) { + arg = &sha_rounds; + } + else if (0 == strcmp (crypt_method, "BCRYPT")) { + arg = &bcrypt_rounds; + } + } +#elif defined(USE_SHA_CRYPT) if (sflg) { arg = &sha_rounds; } +#elif defined(USE_BCRYPT) + if (sflg) { + arg = &bcrypt_rounds; + } #endif salt = crypt_make_salt (crypt_method, arg); cp = pw_encrypt (newpwd, salt); diff --git a/src/chpasswd.c b/src/chpasswd.c index d1c1043a..be61e038 100644 --- a/src/chpasswd.c +++ b/src/chpasswd.c @@ -58,15 +58,18 @@ const char *Prog; static bool eflg = false; static bool md5flg = false; -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) static bool sflg = false; -#endif /* USE_SHA_CRYPT */ +#endif static /*@null@*//*@observer@*/const char *crypt_method = NULL; #define cflg (NULL != crypt_method) #ifdef USE_SHA_CRYPT static long sha_rounds = 5000; -#endif /* USE_SHA_CRYPT */ +#endif +#ifdef USE_BCRYPT +static long bcrypt_rounds = 13; +#endif static bool is_shadow_pwd; static bool pw_locked = false; @@ -118,11 +121,15 @@ static /*@noreturn@*/void usage (int status) Prog); (void) fprintf (usageout, _(" -c, --crypt-method METHOD the crypt method (one of %s)\n"), -#ifndef USE_SHA_CRYPT +#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) "NONE DES MD5" -#else /* USE_SHA_CRYPT */ +#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + "NONE DES MD5 SHA256 SHA512 BCRYPT" +#elif defined(USE_SHA_CRYPT) "NONE DES MD5 SHA256 SHA512" -#endif /* USE_SHA_CRYPT */ +#else + "NONE DES MD5 BCRYPT" +#endif ); (void) fputs (_(" -e, --encrypted supplied passwords are encrypted\n"), usageout); (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); @@ -130,11 +137,11 @@ static /*@noreturn@*/void usage (int status) " the MD5 algorithm\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); -#ifdef USE_SHA_CRYPT - (void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n" +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) + (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA or BCRYPT\n" " crypt algorithms\n"), usageout); -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ (void) fputs ("\n", usageout); exit (status); @@ -154,18 +161,18 @@ static void process_flags (int argc, char **argv) {"help", no_argument, NULL, 'h'}, {"md5", no_argument, NULL, 'm'}, {"root", required_argument, NULL, 'R'}, -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) {"sha-rounds", required_argument, NULL, 's'}, -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) "c:ehmR:s:", -#else /* !USE_SHA_CRYPT */ +#else "c:ehmR:", -#endif /* !USE_SHA_CRYPT */ +#endif long_options, NULL)) != -1) { switch (c) { case 'c': @@ -182,17 +189,41 @@ static void process_flags (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) case 's': sflg = true; - if (getlong(optarg, &sha_rounds) == 0) { + if ( ( ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512"))) + && (0 == getlong(optarg, &sha_rounds))) + || ( (0 == strcmp (crypt_method, "BCRYPT")) + && (0 == getlong(optarg, &bcrypt_rounds)))) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_USAGE); } break; -#endif /* USE_SHA_CRYPT */ +#elif defined(USE_SHA_CRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &sha_rounds)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (E_USAGE); + } + break; +#elif defined(USE_BCRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &bcrypt_rounds)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (E_USAGE); + } + break; +#endif + default: usage (E_USAGE); /*@notreached@*/break; @@ -210,7 +241,7 @@ static void process_flags (int argc, char **argv) */ static void check_flags (void) { -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) if (sflg && !cflg) { fprintf (stderr, _("%s: %s flag is only allowed with the %s flag\n"), @@ -235,6 +266,9 @@ static void check_flags (void) && (0 != strcmp (crypt_method, "SHA256")) && (0 != strcmp (crypt_method, "SHA512")) #endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT + && (0 != strcmp (crypt_method, "BCRYPT")) +#endif /* USE_BCRYPT */ ) { fprintf (stderr, _("%s: unsupported crypt method: %s\n"), @@ -496,10 +530,24 @@ int main (int argc, char **argv) if (md5flg) { crypt_method = "MD5"; } -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + if (sflg) { + if ( (0 == strcmp (crypt_method, "SHA256")) + || (0 == strcmp (crypt_method, "SHA512"))) { + arg = &sha_rounds; + } + else if (0 == strcmp (crypt_method, "BCRYPT")) { + arg = &bcrypt_rounds; + } + } +#elif defined(USE_SHA_CRYPT) if (sflg) { arg = &sha_rounds; } +#elif defined(USE_BCRYPT) + if (sflg) { + arg = &bcrypt_rounds; + } #endif salt = crypt_make_salt (crypt_method, arg); cp = pw_encrypt (newpwd, salt); diff --git a/src/newusers.c b/src/newusers.c index bf63f4b5..99c69f78 100644 --- a/src/newusers.c +++ b/src/newusers.c @@ -80,10 +80,15 @@ static bool rflg = false; /* create a system account */ #ifndef USE_PAM static /*@null@*//*@observer@*/char *crypt_method = NULL; #define cflg (NULL != crypt_method) -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) static bool sflg = false; +#endif +#ifdef USE_SHA_CRYPT static long sha_rounds = 5000; #endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT +static long bcrypt_rounds = 13; +#endif /* USE_BCRYPT */ #endif /* !USE_PAM */ static bool is_shadow; @@ -134,22 +139,26 @@ static void usage (int status) #ifndef USE_PAM (void) fprintf (usageout, _(" -c, --crypt-method METHOD the crypt method (one of %s)\n"), -#ifndef USE_SHA_CRYPT +#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) "NONE DES MD5" -#else /* USE_SHA_CRYPT */ +#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + "NONE DES MD5 SHA256 SHA512 BCRYPT" +#elif defined(USE_SHA_CRYPT) "NONE DES MD5 SHA256 SHA512" -#endif /* USE_SHA_CRYPT */ +#else + "NONE DES MD5 BCRYPT" +#endif ); #endif /* !USE_PAM */ (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -r, --system create system accounts\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); #ifndef USE_PAM -#ifdef USE_SHA_CRYPT - (void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n" +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) + (void) fputs (_(" -s, --sha-rounds number of rounds for the SHA or BCRYPT\n" " crypt algorithms\n"), usageout); -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ #endif /* !USE_PAM */ (void) fputs ("\n", usageout); @@ -423,15 +432,29 @@ static int update_passwd (struct passwd *pwd, const char *password) { void *crypt_arg = NULL; char *cp; - if (crypt_method != NULL) { -#ifdef USE_SHA_CRYPT + if (NULL != crypt_method) { +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + if (sflg) { + if ( (0 == strcmp (crypt_method, "SHA256")) + || (0 == strcmp (crypt_method, "SHA512"))) { + crypt_arg = &sha_rounds; + } + else if (0 == strcmp (crypt_method, "BCRYPT")) { + crypt_arg = &bcrypt_rounds; + } + } +#elif defined(USE_SHA_CRYPT) if (sflg) { crypt_arg = &sha_rounds; } +#elif defined(USE_BCRYPT) + if (sflg) { + crypt_arg = &bcrypt_rounds; + } #endif } - if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) { + if ((NULL != crypt_method) && (0 == strcmp(crypt_method, "NONE"))) { pwd->pw_passwd = (char *)password; } else { const char *salt = crypt_make_salt (crypt_method, crypt_arg); @@ -460,12 +483,26 @@ static int add_passwd (struct passwd *pwd, const char *password) #ifndef USE_PAM void *crypt_arg = NULL; - if (crypt_method != NULL) { -#ifdef USE_SHA_CRYPT + if (NULL != crypt_method) { +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) + if (sflg) { + if ( (0 == strcmp (crypt_method, "SHA256")) + || (0 == strcmp (crypt_method, "SHA512"))) { + crypt_arg = &sha_rounds; + } + else if (0 == strcmp (crypt_method, "BCRYPT")) { + crypt_arg = &bcrypt_rounds; + } + } +#elif defined(USE_SHA_CRYPT) if (sflg) { crypt_arg = &sha_rounds; } -#endif /* USE_SHA_CRYPT */ +#elif defined(USE_BCRYPT) + if (sflg) { + crypt_arg = &bcrypt_rounds; + } +#endif } /* @@ -591,20 +628,20 @@ static void process_flags (int argc, char **argv) {"system", no_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, #ifndef USE_PAM -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) {"sha-rounds", required_argument, NULL, 's'}, -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ #endif /* !USE_PAM */ {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, #ifndef USE_PAM -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) "c:bhrs:", -#else /* !USE_SHA_CRYPT */ +#else /* !USE_SHA_CRYPT && !USE_BCRYPT */ "c:bhr", -#endif /* !USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT || USE_BCRYPT */ #else /* USE_PAM */ "bhr", #endif @@ -627,17 +664,40 @@ static void process_flags (int argc, char **argv) case 'R': /* no-op, handled in process_root_flag () */ break; #ifndef USE_PAM -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) case 's': sflg = true; - if (getlong(optarg, &sha_rounds) == 0) { + if ( ( ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512"))) + && (0 == getlong(optarg, &sha_rounds))) + || ( (0 == strcmp (crypt_method, "BCRYPT")) + && (0 == getlong(optarg, &bcrypt_rounds)))) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (EXIT_FAILURE); } break; -#endif /* USE_SHA_CRYPT */ +#elif defined(USE_SHA_CRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &sha_rounds)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (EXIT_FAILURE); + } + break; +#elif defined(USE_BCRYPT) + case 's': + sflg = true; + if (0 == getlong(optarg, &bcrypt_rounds)) { + fprintf (stderr, + _("%s: invalid numeric argument '%s'\n"), + Prog, optarg); + usage (EXIT_FAILURE); + } + break; +#endif #endif /* !USE_PAM */ default: usage (EXIT_FAILURE); @@ -671,14 +731,14 @@ static void process_flags (int argc, char **argv) static void check_flags (void) { #ifndef USE_PAM -#ifdef USE_SHA_CRYPT +#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) if (sflg && !cflg) { fprintf (stderr, _("%s: %s flag is only allowed with the %s flag\n"), Prog, "-s", "-c"); usage (EXIT_FAILURE); } -#endif /* USE_SHA_CRYPT */ +#endif if (cflg) { if ( (0 != strcmp (crypt_method, "DES")) @@ -688,6 +748,9 @@ static void check_flags (void) && (0 != strcmp (crypt_method, "SHA256")) && (0 != strcmp (crypt_method, "SHA512")) #endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT + && (0 != strcmp (crypt_method, "BCRYPT")) +#endif /* USE_BCRYPT */ ) { fprintf (stderr, _("%s: unsupported crypt method: %s\n"), diff --git a/src/passwd.c b/src/passwd.c index 8dca4455..13619b16 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -279,7 +279,11 @@ static int new_password (const struct passwd *pw) #ifdef USE_SHA_CRYPT || (strcmp (method, "SHA256") == 0) || (strcmp (method, "SHA512") == 0) -#endif /* USE_SHA_CRYPT */ +#endif /* USE_SHA_CRYPT */ +#ifdef USE_BCRYPT + || (strcmp (method, "BCRYPT") == 0) +#endif /* USE_SHA_CRYPT */ + ) { pass_max_len = -1; } else {