From 090693e116fc6ea0dfb649e11a01af08e19b33d9 Mon Sep 17 00:00:00 2001 From: Thorsten Kukuk Date: Mon, 1 Dec 2008 12:40:40 +0000 Subject: Relevant BUGIDs: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Purpose of commit: new feature Commit summary: --------------- 2008-12-01 Thorsten Kukuk * modules/pam_unix/pam_unix.8.xml: Document blowfish option. * configure.in: Check for crypt_gensalt_rn. * modules/pam_unix/pam_unix_passwd.c: Pass pamh to create_password_hash function. * modules/pam_unix/passverify.c (create_password_hash): Add blowfish support. * modules/pam_unix/passverify.h: Adjust create_password_hash prototype. * modules/pam_unix/support.c: Add support for blowfish option. * modules/pam_unix/support.h: Add defines for blowfish option. Patch from Diego Flameeyes Pettenò --- modules/pam_unix/pam_unix.8.xml | 28 ++++++++-- modules/pam_unix/pam_unix_passwd.c | 2 +- modules/pam_unix/passverify.c | 107 +++++++++++++++---------------------- modules/pam_unix/passverify.h | 51 +++++++----------- modules/pam_unix/support.c | 32 +++++++---- modules/pam_unix/support.h | 4 +- 6 files changed, 113 insertions(+), 111 deletions(-) (limited to 'modules') diff --git a/modules/pam_unix/pam_unix.8.xml b/modules/pam_unix/pam_unix.8.xml index e08edfcc..cc3affd9 100644 --- a/modules/pam_unix/pam_unix.8.xml +++ b/modules/pam_unix/pam_unix.8.xml @@ -266,7 +266,9 @@ When a user changes their password next, encrypt it with the SHA256 algorithm. If the - SHA256 algorithm is not known to the libcrypt, + SHA256 algorithm is not known to the + crypt3 + function, fall back to MD5. @@ -279,7 +281,24 @@ When a user changes their password next, encrypt it with the SHA512 algorithm. If the - SHA512 algorithm is not known to the libcrypt, + SHA512 algorithm is not known to the + crypt3 + function, + fall back to MD5. + + + + + + + + + + When a user changes their password next, + encrypt it with the blowfish algorithm. If the + SHA512 algorithm is not known to the + crypt3 + function, fall back to MD5. @@ -290,8 +309,9 @@ - Set the optional number of rounds of the SHA256 and SHA512 - password hashing algorithms to n. + Set the optional number of rounds of the SHA256, SHA512 + and blowfish password hashing algorithms to + n. diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c index 240caddb..b8da9913 100644 --- a/modules/pam_unix/pam_unix_passwd.c +++ b/modules/pam_unix/pam_unix_passwd.c @@ -749,7 +749,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * First we encrypt the new password. */ - tpass = create_password_hash(pass_new, ctrl, rounds); + tpass = create_password_hash(pamh, pass_new, ctrl, rounds); if (tpass == NULL) { pam_syslog(pamh, LOG_CRIT, "out of memory for password"); diff --git a/modules/pam_unix/passverify.c b/modules/pam_unix/passverify.c index eae1e24c..281716e0 100644 --- a/modules/pam_unix/passverify.c +++ b/modules/pam_unix/passverify.c @@ -151,15 +151,8 @@ is_pwd_shadowed(const struct passwd *pwd) return 0; } -#ifdef HELPER_COMPILE -int -get_account_info(const char *name, - struct passwd **pwd, struct spwd **spwdent) -#else -int -get_account_info(pam_handle_t *pamh, const char *name, - struct passwd **pwd, struct spwd **spwdent) -#endif +PAMH_ARG_DECL(int get_account_info, + const char *name, struct passwd **pwd, struct spwd **spwdent) { /* UNIX passwords area */ *pwd = pam_modutil_getpwnam(pamh, name); /* Get password file entry... */ @@ -219,24 +212,13 @@ get_account_info(pam_handle_t *pamh, const char *name, return PAM_SUCCESS; } -#ifdef HELPER_COMPILE -int -get_pwd_hash(const char *name, - struct passwd **pwd, char **hash) -#else -int -get_pwd_hash(pam_handle_t *pamh, const char *name, - struct passwd **pwd, char **hash) -#endif +PAMH_ARG_DECL(int get_pwd_hash, + const char *name, struct passwd **pwd, char **hash) { int retval; struct spwd *spwdent = NULL; -#ifdef HELPER_COMPILE - retval = get_account_info(name, pwd, &spwdent); -#else - retval = get_account_info(pamh, name, pwd, &spwdent); -#endif + retval = get_account_info(PAMH_ARG(name, pwd, &spwdent)); if (retval != PAM_SUCCESS) { return retval; } @@ -251,13 +233,8 @@ get_pwd_hash(pam_handle_t *pamh, const char *name, return PAM_SUCCESS; } -#ifdef HELPER_COMPILE -int -check_shadow_expiry(struct spwd *spent, int *daysleft) -#else -int -check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft) -#endif +PAMH_ARG_DECL(int check_shadow_expiry, + struct spwd *spent, int *daysleft) { long int curdays; *daysleft = -1; @@ -386,17 +363,19 @@ crypt_md5_wrapper(const char *pass_new) return cp; } -char * -create_password_hash(const char *password, unsigned int ctrl, int rounds) +PAMH_ARG_DECL(char * create_password_hash, + const char *password, unsigned int ctrl, int rounds) { const char *algoid; char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */ char *sp; if (on(UNIX_MD5_PASS, ctrl)) { + /* algoid = "$1" */ return crypt_md5_wrapper(password); - } - if (on(UNIX_SHA256_PASS, ctrl)) { + } else if (on(UNIX_BLOWFISH_PASS, ctrl)) { + algoid = "$2a$"; + } else if (on(UNIX_SHA256_PASS, ctrl)) { algoid = "$5$"; } else if (on(UNIX_SHA512_PASS, ctrl)) { algoid = "$6$"; @@ -416,17 +395,35 @@ create_password_hash(const char *password, unsigned int ctrl, int rounds) return crypted; } - sp = stpcpy(salt, algoid); - if (on(UNIX_ALGO_ROUNDS, ctrl)) { - sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds); +#ifdef HAVE_CRYPT_GENSALT_RN + if (on(UNIX_BLOWFISH_PASS, ctrl)) { + char entropy[17]; + crypt_make_salt(entropy, sizeof(entropy) - 1); + sp = crypt_gensalt_rn(algoid, rounds, + entropy, sizeof(entropy), + salt, sizeof(salt)); + } else { +#endif + sp = stpcpy(salt, algoid); + if (on(UNIX_ALGO_ROUNDS, ctrl)) { + sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds); + } + crypt_make_salt(sp, 8); + /* For now be conservative so the resulting hashes + * are not too long. 8 bytes of salt prevents dictionary + * attacks well enough. */ +#ifdef HAVE_CRYPT_GENSALT_RN } - crypt_make_salt(sp, 8); - /* For now be conservative so the resulting hashes - * are not too long. 8 bytes of salt prevents dictionary - * attacks well enough. */ +#endif sp = crypt(password, salt); if (strncmp(algoid, sp, strlen(algoid)) != 0) { - /* libc doesn't know the algorithm, use MD5 */ + /* libxcrypt/libc doesn't know the algorithm, use MD5 */ + pam_syslog(pamh, LOG_ERR, + "Algo %s not supported by the crypto backend, " + "falling back to MD5\n", + on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" : + on(UNIX_SHA256_PASS, ctrl) ? "sha256" : + on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid); memset(sp, '\0', strlen(sp)); return crypt_md5_wrapper(password); } @@ -703,13 +700,8 @@ done: } } -#ifdef HELPER_COMPILE -int -unix_update_passwd(const char *forwho, const char *towhat) -#else -int -unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) -#endif +PAMH_ARG_DECL(int unix_update_passwd, + const char *forwho, const char *towhat) { struct passwd *tmpent = NULL; struct stat st; @@ -803,11 +795,7 @@ unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) done: if (!err) { if (!rename(PW_TMPFILE, "/etc/passwd")) -#ifdef HELPER_COMPILE - helper_log_err( -#else pam_syslog(pamh, -#endif LOG_NOTICE, "password changed for %s", forwho); else err = 1; @@ -830,13 +818,8 @@ done: } } -#ifdef HELPER_COMPILE -int -unix_update_shadow(const char *forwho, char *towhat) -#else -int -unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) -#endif +PAMH_ARG_DECL(int unix_update_shadow, + const char *forwho, char *towhat) { struct spwd *spwdent = NULL, *stmpent = NULL; struct stat st; @@ -933,11 +916,7 @@ unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) done: if (!err) { if (!rename(SH_TMPFILE, "/etc/shadow")) -#ifdef HELPER_COMPILE - helper_log_err( -#else pam_syslog(pamh, -#endif LOG_NOTICE, "password changed for %s", forwho); else err = 1; diff --git a/modules/pam_unix/passverify.h b/modules/pam_unix/passverify.h index 21bb9232..3de67593 100644 --- a/modules/pam_unix/passverify.h +++ b/modules/pam_unix/passverify.h @@ -21,9 +21,6 @@ is_pwd_shadowed(const struct passwd *pwd); char * crypt_md5_wrapper(const char *pass_new); -char * -create_password_hash(const char *password, unsigned int ctrl, int rounds); - int unix_selinux_confined(void); @@ -58,41 +55,33 @@ getuidname(uid_t uid); int read_passwords(int fd, int npass, char **passwords); +#endif -int -get_account_info(const char *name, - struct passwd **pwd, struct spwd **spwdent); - -int -get_pwd_hash(const char *name, - struct passwd **pwd, char **hash); - -int -check_shadow_expiry(struct spwd *spent, int *daysleft); +#ifdef HELPER_COMPILE +#define PAMH_ARG_DECL(fname, ...) fname(__VA_ARGS__) +#define PAMH_ARG(...) __VA_ARGS__ +#else +#define PAMH_ARG_DECL(fname, ...) fname(pam_handle_t *pamh, __VA_ARGS__) +#define PAMH_ARG(...) pamh, __VA_ARGS__ +#endif -int -unix_update_passwd(const char *forwho, const char *towhat); +PAMH_ARG_DECL(char * create_password_hash, + const char *password, unsigned int ctrl, int rounds); -int -unix_update_shadow(const char *forwho, char *towhat); -#else -int -get_account_info(pam_handle_t *pamh, const char *name, - struct passwd **pwd, struct spwd **spwdent); +PAMH_ARG_DECL(int get_account_info, + const char *name, struct passwd **pwd, struct spwd **spwdent); -int -get_pwd_hash(pam_handle_t *pamh, const char *name, - struct passwd **pwd, char **hash); +PAMH_ARG_DECL(int get_pwd_hash, + const char *name, struct passwd **pwd, char **hash); -int -check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft); +PAMH_ARG_DECL(int check_shadow_expiry, + struct spwd *spent, int *daysleft); -int -unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat); +PAMH_ARG_DECL(int unix_update_passwd, + const char *forwho, const char *towhat); -int -unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat); -#endif +PAMH_ARG_DECL(int unix_update_shadow, + const char *forwho, char *towhat); /* ****************************************************************** * * Copyright (c) Red Hat, Inc. 2007. diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c index db630f51..faec20dc 100644 --- a/modules/pam_unix/support.c +++ b/modules/pam_unix/support.c @@ -109,16 +109,8 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, *remember = 400; } } - if (rounds != NULL) { - if (j == UNIX_ALGO_ROUNDS) { - *rounds = strtol(*argv + 7, NULL, 10); - if ((*rounds < 1000) || (*rounds == INT_MAX)) - /* don't care about bogus values */ - unset(UNIX_ALGO_ROUNDS, ctrl); - if (*rounds >= 10000000) - *rounds = 9999999; - } - } + if (rounds != NULL && j == UNIX_ALGO_ROUNDS) + *rounds = strtol(*argv + 7, NULL, 10); } ++argv; /* step to next argument */ @@ -128,6 +120,26 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, D(("DISALLOW_NULL_AUTHTOK")); set(UNIX__NONULL, ctrl); } + + /* Set default rounds for blowfish */ + if (on(UNIX_BLOWFISH_PASS, ctrl) && off(UNIX_ALGO_ROUNDS, ctrl)) { + *rounds = 5; + set(UNIX_ALGO_ROUNDS, ctrl); + } + + /* Enforce sane "rounds" values */ + if (on(UNIX_ALGO_ROUNDS, ctrl)) { + if (on(UNIX_BLOWFISH_PASS, ctrl)) { + if (*rounds < 4 || *rounds > 31) + *rounds = 5; + } else if (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl)) { + if ((*rounds < 1000) || (*rounds == INT_MAX)) + /* don't care about bogus values */ + unset(UNIX_ALGO_ROUNDS, ctrl); + if (*rounds >= 10000000) + *rounds = 9999999; + } + } /* auditing is a more sensitive version of debug */ diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h index a33dadaa..86575ff0 100644 --- a/modules/pam_unix/support.h +++ b/modules/pam_unix/support.h @@ -88,8 +88,9 @@ typedef struct { #define UNIX_SHA512_PASS 24 /* new password hashes will use SHA512 */ #define UNIX_ALGO_ROUNDS 25 /* optional number of rounds for new password hash algorithms */ +#define UNIX_BLOWFISH_PASS 26 /* new password hashes will use blowfish */ /* -------------- */ -#define UNIX_CTRLS_ 26 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 27 /* number of ctrl arguments defined */ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = { @@ -122,6 +123,7 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = /* UNIX_SHA256_PASS */ {"sha256", _ALL_ON_^(040420000), 020000000}, /* UNIX_SHA512_PASS */ {"sha512", _ALL_ON_^(020420000), 040000000}, /* UNIX_ALGO_ROUNDS */ {"rounds=", _ALL_ON_, 0100000000}, +/* UNIX_BLOWFISH_PASS */ {"blowfish", _ALL_ON_^(060420000),0200000000}, }; #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) -- cgit v1.2.3