aboutsummaryrefslogtreecommitdiff
path: root/modules/pam_unix/passverify.c
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@canonical.com>2020-08-11 14:54:35 -0700
committerSteve Langasek <steve.langasek@canonical.com>2020-08-11 15:00:33 -0700
commit239d9c3181694bda5a0531ac579612c46c3b4e6d (patch)
tree43c04725cde922627215f4c32665ea832dd456d1 /modules/pam_unix/passverify.c
parentaa2142277bf5fb4a884c6119180e41258817705b (diff)
parentf6d08ed47a3da3c08345bce2ca366e961c52ad7c (diff)
downloadpam-239d9c3181694bda5a0531ac579612c46c3b4e6d.tar.gz
pam-239d9c3181694bda5a0531ac579612c46c3b4e6d.tar.bz2
pam-239d9c3181694bda5a0531ac579612c46c3b4e6d.zip
Merge upstream version 1.4.0
Diffstat (limited to 'modules/pam_unix/passverify.c')
-rw-r--r--modules/pam_unix/passverify.c133
1 files changed, 102 insertions, 31 deletions
diff --git a/modules/pam_unix/passverify.c b/modules/pam_unix/passverify.c
index 9c1771e2..a571b4f7 100644
--- a/modules/pam_unix/passverify.c
+++ b/modules/pam_unix/passverify.c
@@ -25,6 +25,8 @@
#include <crypt.h>
#endif
+#include "pam_cc_compat.h"
+#include "pam_inline.h"
#include "md5.h"
#include "bigcrypt.h"
#include "passverify.h"
@@ -65,8 +67,8 @@ strip_hpux_aging(char *hash)
}
}
-int
-verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
+PAMH_ARG_DECL(int verify_pwd_hash,
+ const char *p, char *hash, unsigned int nullok)
{
size_t hash_len;
char *pp = NULL;
@@ -87,7 +89,7 @@ verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
} else if (!p || *hash == '*' || *hash == '!') {
retval = PAM_AUTH_ERR;
} else {
- if (!strncmp(hash, "$1$", 3)) {
+ if (pam_str_skip_prefix(hash, "$1$") != NULL) {
pp = Goodcrypt_md5(p, hash);
if (pp && strcmp(pp, hash) != 0) {
_pam_delete(pp);
@@ -103,6 +105,44 @@ verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
* Ok, we don't know the crypt algorithm, but maybe
* libcrypt knows about it? We should try it.
*/
+#if defined(CRYPT_CHECKSALT_AVAILABLE) && CRYPT_CHECKSALT_AVAILABLE
+ /* Get the status of the hash from checksalt */
+ int retval_checksalt = crypt_checksalt(hash);
+
+ /*
+ * Check for hashing methods that are disabled by
+ * libcrypt configuration and/or system preset.
+ */
+ if (retval_checksalt == CRYPT_SALT_METHOD_DISABLED) {
+ /*
+ * pam_syslog() needs a pam handle,
+ * but that's not available here.
+ */
+ pam_syslog(pamh, LOG_ERR,
+ "The support for password hash \"%.6s\" "
+ "has been disabled in libcrypt "
+ "configuration.",
+ hash);
+ }
+ /*
+ * Check for malformed hashes, like descrypt hashes
+ * starting with "$2...", which might have been
+ * generated by unsafe base64 encoding functions
+ * as used in glibc <= 2.16.
+ * Such hashes are likely to be rejected by many
+ * recent implementations of libcrypt.
+ */
+ if (retval_checksalt == CRYPT_SALT_INVALID) {
+ pam_syslog(pamh, LOG_ERR,
+ "The password hash \"%.6s\" is unknown to "
+ "libcrypt.",
+ hash);
+ }
+#else
+#ifndef HELPER_COMPILE
+ (void)pamh;
+#endif
+#endif
#ifdef HAVE_CRYPT_R
struct crypt_data *cdata;
cdata = malloc(sizeof(*cdata));
@@ -166,25 +206,30 @@ PAMH_ARG_DECL(int get_account_info,
save_euid = geteuid();
save_uid = getuid();
- if (save_uid == (*pwd)->pw_uid)
- setreuid(save_euid, save_uid);
- else {
- setreuid(0, -1);
- if (setreuid(-1, (*pwd)->pw_uid) == -1) {
- setreuid(-1, 0);
- setreuid(0, -1);
- if(setreuid(-1, (*pwd)->pw_uid) == -1)
+ if (save_uid == (*pwd)->pw_uid) {
+ if (setreuid(save_euid, save_uid))
+ return PAM_CRED_INSUFFICIENT;
+ } else {
+ if (setreuid(0, -1))
+ return PAM_CRED_INSUFFICIENT;
+ if (setreuid(-1, (*pwd)->pw_uid)) {
+ if (setreuid(-1, 0)
+ || setreuid(0, -1)
+ || setreuid(-1, (*pwd)->pw_uid)) {
return PAM_CRED_INSUFFICIENT;
+ }
}
}
*spwdent = pam_modutil_getspnam(pamh, name);
- if (save_uid == (*pwd)->pw_uid)
- setreuid(save_uid, save_euid);
- else {
- setreuid(-1, 0);
- setreuid(save_uid, -1);
- setreuid(-1, save_euid);
+ if (save_uid == (*pwd)->pw_uid) {
+ if (setreuid(save_uid, save_euid))
+ return PAM_CRED_INSUFFICIENT;
+ } else {
+ if (setreuid(-1, 0)
+ || setreuid(save_uid, -1)
+ || setreuid(-1, save_euid))
+ return PAM_CRED_INSUFFICIENT;
}
if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
@@ -244,7 +289,13 @@ PAMH_ARG_DECL(int check_shadow_expiry,
D(("account expired"));
return PAM_ACCT_EXPIRED;
}
+#if defined(CRYPT_CHECKSALT_AVAILABLE) && CRYPT_CHECKSALT_AVAILABLE
+ if (spent->sp_lstchg == 0 ||
+ crypt_checksalt(spent->sp_pwdp) == CRYPT_SALT_METHOD_LEGACY ||
+ crypt_checksalt(spent->sp_pwdp) == CRYPT_SALT_TOO_CHEAP) {
+#else
if (spent->sp_lstchg == 0) {
+#endif
D(("need a new password"));
*daysleft = 0;
return PAM_NEW_AUTHTOK_REQD;
@@ -372,10 +423,15 @@ crypt_md5_wrapper(const char *pass_new)
}
PAMH_ARG_DECL(char * create_password_hash,
- const char *password, unsigned int ctrl, int rounds)
+ const char *password, unsigned long long ctrl, int rounds)
{
const char *algoid;
+#if defined(CRYPT_GENSALT_OUTPUT_SIZE) && CRYPT_GENSALT_OUTPUT_SIZE > 64
+ /* Strings returned by crypt_gensalt_rn will be no longer than this. */
+ char salt[CRYPT_GENSALT_OUTPUT_SIZE];
+#else
char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */
+#endif
char *sp;
#ifdef HAVE_CRYPT_R
struct crypt_data *cdata = NULL;
@@ -384,8 +440,12 @@ PAMH_ARG_DECL(char * create_password_hash,
if (on(UNIX_MD5_PASS, ctrl)) {
/* algoid = "$1" */
return crypt_md5_wrapper(password);
+ } else if (on(UNIX_YESCRYPT_PASS, ctrl)) {
+ algoid = "$y$";
+ } else if (on(UNIX_GOST_YESCRYPT_PASS, ctrl)) {
+ algoid = "$gy$";
} else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
- algoid = "$2a$";
+ algoid = "$2b$";
} else if (on(UNIX_SHA256_PASS, ctrl)) {
algoid = "$5$";
} else if (on(UNIX_SHA512_PASS, ctrl)) {
@@ -406,6 +466,13 @@ PAMH_ARG_DECL(char * create_password_hash,
return crypted;
}
+#if defined(CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY) && CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY
+ /*
+ * Any version of libcrypt supporting auto entropy is
+ * guaranteed to have crypt_gensalt_rn().
+ */
+ sp = crypt_gensalt_rn(algoid, rounds, NULL, 0, salt, sizeof(salt));
+#else
#ifdef HAVE_CRYPT_GENSALT_R
if (on(UNIX_BLOWFISH_PASS, ctrl)) {
char entropy[17];
@@ -423,6 +490,7 @@ PAMH_ARG_DECL(char * create_password_hash,
#ifdef HAVE_CRYPT_GENSALT_R
}
#endif
+#endif /* CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY */
#ifdef HAVE_CRYPT_R
sp = NULL;
cdata = malloc(sizeof(*cdata));
@@ -434,10 +502,11 @@ PAMH_ARG_DECL(char * create_password_hash,
sp = crypt(password, salt);
#endif
if (!sp || strncmp(algoid, sp, strlen(algoid)) != 0) {
- /* libxcrypt/libc doesn't know the algorithm, use MD5 */
+ /* libxcrypt/libc doesn't know the algorithm, error out */
pam_syslog(pamh, LOG_ERR,
- "Algo %s not supported by the crypto backend, "
- "falling back to MD5\n",
+ "Algo %s not supported by the crypto backend.\n",
+ on(UNIX_YESCRYPT_PASS, ctrl) ? "yescrypt" :
+ on(UNIX_GOST_YESCRYPT_PASS, ctrl) ? "gost_yescrypt" :
on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" :
on(UNIX_SHA256_PASS, ctrl) ? "sha256" :
on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid);
@@ -447,7 +516,7 @@ PAMH_ARG_DECL(char * create_password_hash,
#ifdef HAVE_CRYPT_R
free(cdata);
#endif
- return crypt_md5_wrapper(password);
+ return NULL;
}
sp = x_strdup(sp);
#ifdef HAVE_CRYPT_R
@@ -958,7 +1027,9 @@ PAMH_ARG_DECL(int unix_update_shadow,
fclose(opwfile);
if (!wroteentry && !err) {
+ DIAG_PUSH_IGNORE_CAST_QUAL;
spwdent.sp_namp = (char *)forwho;
+ DIAG_POP_IGNORE_CAST_QUAL;
spwdent.sp_pwdp = towhat;
spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24);
if (spwdent.sp_lstchg == 0)
@@ -1017,21 +1088,21 @@ int
helper_verify_password(const char *name, const char *p, int nullok)
{
struct passwd *pwd = NULL;
- char *salt = NULL;
+ char *hash = NULL;
int retval;
- retval = get_pwd_hash(name, &pwd, &salt);
+ retval = get_pwd_hash(name, &pwd, &hash);
- if (pwd == NULL || salt == NULL) {
+ if (pwd == NULL || hash == NULL) {
helper_log_err(LOG_NOTICE, "check pass; user unknown");
retval = PAM_USER_UNKNOWN;
} else {
- retval = verify_pwd_hash(p, salt, nullok);
+ retval = verify_pwd_hash(p, hash, nullok);
}
- if (salt) {
- _pam_overwrite(salt);
- _pam_drop(salt);
+ if (hash) {
+ _pam_overwrite(hash);
+ _pam_drop(hash);
}
p = NULL; /* no longer needed here */
@@ -1154,7 +1225,7 @@ read_passwords(int fd, int npass, char **passwords)
#endif
/* ****************************************************************** *
- * Copyright (c) Jan Rêkorajski 1999.
+ * Copyright (c) Jan Rękorajski 1999.
* Copyright (c) Andrew G. Morgan 1996-8.
* Copyright (c) Alex O. Yuriev, 1996.
* Copyright (c) Cristian Gafton 1996.