aboutsummaryrefslogtreecommitdiff
path: root/contrib/pam_modules/pam_passwdqc/pam_passwdqc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pam_modules/pam_passwdqc/pam_passwdqc.c')
-rw-r--r--contrib/pam_modules/pam_passwdqc/pam_passwdqc.c601
1 files changed, 303 insertions, 298 deletions
diff --git a/contrib/pam_modules/pam_passwdqc/pam_passwdqc.c b/contrib/pam_modules/pam_passwdqc/pam_passwdqc.c
index 7c3973105cd2..6be3d9e0499f 100644
--- a/contrib/pam_modules/pam_passwdqc/pam_passwdqc.c
+++ b/contrib/pam_modules/pam_passwdqc/pam_passwdqc.c
@@ -1,10 +1,19 @@
/*
- * Copyright (c) 2000-2002 by Solar Designer. See LICENSE.
+ * Copyright (c) 2000-2003,2005,2012,2016,2019,2021 by Solar Designer
+ * Copyright (c) 2017,2018 by Dmitry V. Levin
+ * Copyright (c) 2017,2018 by Oleg Solovyov
+ * See LICENSE
*/
+#ifdef __FreeBSD__
+/* For vsnprintf(3) */
+#define _XOPEN_SOURCE 600
+#else
#define _XOPEN_SOURCE 500
#define _XOPEN_SOURCE_EXTENDED
#define _XOPEN_VERSION 500
+#define _DEFAULT_SOURCE
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -15,6 +24,10 @@
#ifdef HAVE_SHADOW
#include <shadow.h>
#endif
+#ifdef HAVE_LIBAUDIT
+#include <security/pam_modutil.h>
+#include <libaudit.h>
+#endif
#define PAM_SM_PASSWORD
#ifndef LINUX_PAM
@@ -32,119 +45,164 @@
#define PAM_AUTHTOK_RECOVERY_ERR PAM_AUTHTOK_RECOVER_ERR
#endif
-#if defined(__sun__) && !defined(LINUX_PAM) && !defined(_OPENPAM)
-/* Sun's PAM doesn't use const here */
+#if (defined(__sun) || defined(__hpux)) && \
+ !defined(LINUX_PAM) && !defined(_OPENPAM)
+/* Sun's PAM doesn't use const here, while Linux-PAM and OpenPAM do */
#define lo_const
#else
#define lo_const const
#endif
+#ifdef _OPENPAM
+/* OpenPAM doesn't use const here, while Linux-PAM does */
+#define l_const
+#else
+#define l_const lo_const
+#endif
typedef lo_const void *pam_item_t;
#include "passwdqc.h"
-#define F_ENFORCE_MASK 0x00000003
-#define F_ENFORCE_USERS 0x00000001
-#define F_ENFORCE_ROOT 0x00000002
-#define F_ENFORCE_EVERYONE F_ENFORCE_MASK
-#define F_NON_UNIX 0x00000004
-#define F_ASK_OLDAUTHTOK_MASK 0x00000030
-#define F_ASK_OLDAUTHTOK_PRELIM 0x00000010
-#define F_ASK_OLDAUTHTOK_UPDATE 0x00000020
-#define F_CHECK_OLDAUTHTOK 0x00000040
-#define F_USE_FIRST_PASS 0x00000100
-#define F_USE_AUTHTOK 0x00000200
-
-typedef struct {
- passwdqc_params_t qc;
- int flags;
- int retry;
-} params_t;
-
-static params_t defaults = {
- {
- {INT_MAX, 24, 12, 8, 7}, /* min */
- 40, /* max */
- 3, /* passphrase_words */
- 4, /* match_length */
- 1, /* similar_deny */
- 42 /* random_bits */
- },
- F_ENFORCE_EVERYONE, /* flags */
- 3 /* retry */
-};
+#include "passwdqc_i18n.h"
#define PROMPT_OLDPASS \
- "Enter current password: "
+ _("Enter current password: ")
#define PROMPT_NEWPASS1 \
- "Enter new password: "
+ _("Enter new password: ")
#define PROMPT_NEWPASS2 \
- "Re-type new password: "
+ _("Re-type new password: ")
#define MESSAGE_MISCONFIGURED \
- "System configuration error. Please contact your administrator."
+ _("System configuration error. Please contact your administrator.")
#define MESSAGE_INVALID_OPTION \
- "pam_passwdqc: Invalid option: \"%s\"."
+ "pam_passwdqc: %s."
#define MESSAGE_INTRO_PASSWORD \
- "\nYou can now choose the new password.\n"
+ _("\nYou can now choose the new password.\n")
#define MESSAGE_INTRO_BOTH \
- "\nYou can now choose the new password or passphrase.\n"
-#define MESSAGE_EXPLAIN_PASSWORD_1 \
- "A valid password should be a mix of upper and lower case letters,\n" \
- "digits and other characters. You can use a%s %d character long\n" \
- "password with characters from at least 3 of these 4 classes.\n" \
- "Characters that form a common pattern are discarded by the check.\n"
-#define MESSAGE_EXPLAIN_PASSWORD_2 \
- "A valid password should be a mix of upper and lower case letters,\n" \
- "digits and other characters. You can use a%s %d character long\n" \
- "password with characters from at least 3 of these 4 classes, or\n" \
- "a%s %d character long password containing characters from all the\n" \
- "classes. Characters that form a common pattern are discarded by\n" \
- "the check.\n"
-#define MESSAGE_EXPLAIN_PASSPHRASE \
- "A passphrase should be of at least %d words, %d to %d characters\n" \
- "long and contain enough different characters.\n"
+ _("\nYou can now choose the new password or passphrase.\n")
+
+#define MESSAGE_EXPLAIN_PASSWORD_1_CLASS(count) \
+ P3_( \
+ "A good password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d character.\n", \
+ \
+ "A good password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d characters.\n", \
+ count), (count)
+
+#define MESSAGE_EXPLAIN_PASSWORD_N_CLASSES(count) \
+ P3_( \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d character\n" \
+ "from at least %d of these 4 classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d characters\n" \
+ "from at least %d of these 4 classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ count), (count)
+
+#define MESSAGE_EXPLAIN_PASSWORD_ALL_CLASSES(count) \
+ P3_( \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d character\n" \
+ "from all of these classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d characters\n" \
+ "from all of these classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ count), (count)
+
+#define MESSAGE_EXPLAIN_PASSWORD_ALL_OR_3_CLASSES(count) \
+ P3_( \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d character\n" \
+ "from all of these classes, or a password containing at least %d characters\n" \
+ "from just 3 of these 4 classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ \
+ "A valid password should be a mix of upper and lower case letters, digits, and\n" \
+ "other characters. You can use a password containing at least %d characters\n" \
+ "from all of these classes, or a password containing at least %d characters\n" \
+ "from just 3 of these 4 classes.\n" \
+ "An upper case letter that begins the password and a digit that ends it do not\n" \
+ "count towards the number of character classes used.\n", \
+ count), (count)
+
+#define MESSAGE_EXPLAIN_PASSPHRASE(count) \
+ P3_(\
+ "A passphrase should be of at least %d word, %d to %d characters long, and\n" \
+ "contain enough different characters.\n", \
+ \
+ "A passphrase should be of at least %d words, %d to %d characters long, and\n" \
+ "contain enough different characters.\n", \
+ count), (count)
+
#define MESSAGE_RANDOM \
- "Alternatively, if noone else can see your terminal now, you can\n" \
- "pick this as your password: \"%s\".\n"
+ _("Alternatively, if no one else can see your terminal now, you can pick this as\n" \
+ "your password: \"%s\".\n")
#define MESSAGE_RANDOMONLY \
- "This system is configured to permit randomly generated passwords\n" \
- "only. If noone else can see your terminal now, you can pick this\n" \
- "as your password: \"%s\". Otherwise, come back later.\n"
+ _("This system is configured to permit randomly generated passwords only.\n" \
+ "If no one else can see your terminal now, you can pick this as your\n" \
+ "password: \"%s\". Otherwise come back later.\n")
#define MESSAGE_RANDOMFAILED \
- "This system is configured to use randomly generated passwords\n" \
- "only, but the attempt to generate a password has failed. This\n" \
- "could happen for a number of reasons: you could have requested\n" \
- "an impossible password length, or the access to kernel random\n" \
- "number pool could have failed."
+ _("This system is configured to use randomly generated passwords only,\n" \
+ "but the attempt to generate a password has failed. This could happen\n" \
+ "for a number of reasons: you could have requested an impossible password\n" \
+ "length, or the access to kernel random number pool could have failed.")
#define MESSAGE_TOOLONG \
- "This password may be too long for some services. Choose another."
+ _("This password may be too long for some services. Choose another.")
#define MESSAGE_TRUNCATED \
- "Warning: your longer password will be truncated to 8 characters."
+ _("Warning: your longer password will be truncated to 8 characters.")
#define MESSAGE_WEAKPASS \
- "Weak password: %s."
+ _("Weak password: %s.")
#define MESSAGE_NOTRANDOM \
- "Sorry, you've mistyped the password that was generated for you."
+ _("Sorry, you've mistyped the password that was generated for you.")
#define MESSAGE_MISTYPED \
- "Sorry, passwords do not match."
+ _("Sorry, passwords do not match.")
#define MESSAGE_RETRY \
- "Try again."
+ _("Try again.")
-static int converse(pam_handle_t *pamh, int style, lo_const char *text,
+static int logaudit(pam_handle_t *pamh, int status, passwdqc_params_t *params)
+{
+#ifdef HAVE_LIBAUDIT
+ if (!(params->pam.flags & F_NO_AUDIT)) {
+ int rc = pam_modutil_audit_write(pamh, AUDIT_USER_CHAUTHTOK, "pam_passwdqc", status);
+ if (status == PAM_SUCCESS)
+ status = rc;
+ }
+#else /* !HAVE_LIBAUDIT */
+ (void) pamh;
+#endif
+ passwdqc_params_free(params);
+ return status;
+}
+
+static int converse(pam_handle_t *pamh, int style, l_const char *text,
struct pam_response **resp)
{
- struct pam_conv *conv;
+ pam_item_t item;
+ const struct pam_conv *conv;
struct pam_message msg, *pmsg;
int status;
- status = pam_get_item(pamh, PAM_CONV, (pam_item_t *)&conv);
+ *resp = NULL;
+ status = pam_get_item(pamh, PAM_CONV, &item);
if (status != PAM_SUCCESS)
return status;
+ conv = item;
pmsg = &msg;
msg.msg_style = style;
msg.msg = text;
- *resp = NULL;
return conv->conv(1, (lo_const struct pam_message **)&pmsg, resp,
conv->appdata_ptr);
}
@@ -166,19 +224,20 @@ static int say(pam_handle_t *pamh, int style, const char *format, ...)
if ((unsigned int)needed < sizeof(buffer)) {
status = converse(pamh, style, buffer, &resp);
- _pam_overwrite(buffer);
+ pwqc_drop_pam_reply(resp, 1);
} else {
status = PAM_ABORT;
- memset(buffer, 0, sizeof(buffer));
}
+ _passwdqc_memzero(buffer, sizeof(buffer));
return status;
}
-static int check_max(params_t *params, pam_handle_t *pamh, const char *newpass)
+static int check_max(passwdqc_params_qc_t *qc, pam_handle_t *pamh,
+ const char *newpass)
{
- if ((int)strlen(newpass) > params->qc.max) {
- if (params->qc.max != 8) {
+ if (strlen(newpass) > (size_t)qc->max) {
+ if (qc->max != 8) {
say(pamh, PAM_ERROR_MSG, MESSAGE_TOOLONG);
return -1;
}
@@ -188,152 +247,96 @@ static int check_max(params_t *params, pam_handle_t *pamh, const char *newpass)
return 0;
}
-static int parse(params_t *params, pam_handle_t *pamh,
- int argc, const char **argv)
+static int check_pass(struct passwd *pw, const char *pass)
{
- const char *p;
- char *e;
- int i;
- unsigned long v;
-
- while (argc) {
- if (!strncmp(*argv, "min=", 4)) {
- p = *argv + 4;
- for (i = 0; i < 5; i++) {
- if (!strncmp(p, "disabled", 8)) {
- v = INT_MAX;
- p += 8;
- } else {
- v = strtoul(p, &e, 10);
- p = e;
- }
- if (i < 4 && *p++ != ',') break;
- if (v > INT_MAX) break;
- if (i && (int)v > params->qc.min[i - 1]) break;
- params->qc.min[i] = v;
- }
- if (*p) break;
- } else
- if (!strncmp(*argv, "max=", 4)) {
- v = strtoul(*argv + 4, &e, 10);
- if (*e || v < 8 || v > INT_MAX) break;
- params->qc.max = v;
- } else
- if (!strncmp(*argv, "passphrase=", 11)) {
- v = strtoul(*argv + 11, &e, 10);
- if (*e || v > INT_MAX) break;
- params->qc.passphrase_words = v;
- } else
- if (!strncmp(*argv, "match=", 6)) {
- v = strtoul(*argv + 6, &e, 10);
- if (*e || v > INT_MAX) break;
- params->qc.match_length = v;
- } else
- if (!strncmp(*argv, "similar=", 8)) {
- if (!strcmp(*argv + 8, "permit"))
- params->qc.similar_deny = 0;
- else
- if (!strcmp(*argv + 8, "deny"))
- params->qc.similar_deny = 1;
- else
- break;
- } else
- if (!strncmp(*argv, "random=", 7)) {
- v = strtoul(*argv + 7, &e, 10);
- if (!strcmp(e, ",only")) {
- e += 5;
- params->qc.min[4] = INT_MAX;
- }
- if (*e || v > INT_MAX) break;
- params->qc.random_bits = v;
- } else
- if (!strncmp(*argv, "enforce=", 8)) {
- params->flags &= ~F_ENFORCE_MASK;
- if (!strcmp(*argv + 8, "users"))
- params->flags |= F_ENFORCE_USERS;
- else
- if (!strcmp(*argv + 8, "everyone"))
- params->flags |= F_ENFORCE_EVERYONE;
- else
- if (strcmp(*argv + 8, "none"))
- break;
- } else
- if (!strcmp(*argv, "non-unix")) {
- if (params->flags & F_CHECK_OLDAUTHTOK) break;
- params->flags |= F_NON_UNIX;
- } else
- if (!strncmp(*argv, "retry=", 6)) {
- v = strtoul(*argv + 6, &e, 10);
- if (*e || v > INT_MAX) break;
- params->retry = v;
- } else
- if (!strncmp(*argv, "ask_oldauthtok", 14)) {
- params->flags &= ~F_ASK_OLDAUTHTOK_MASK;
- if (params->flags & F_USE_FIRST_PASS) break;
- if (!strcmp(*argv + 14, "=update"))
- params->flags |= F_ASK_OLDAUTHTOK_UPDATE;
- else
- if (!(*argv)[14])
- params->flags |= F_ASK_OLDAUTHTOK_PRELIM;
- else
- break;
- } else
- if (!strcmp(*argv, "check_oldauthtok")) {
- if (params->flags & F_NON_UNIX) break;
- params->flags |= F_CHECK_OLDAUTHTOK;
- } else
- if (!strcmp(*argv, "use_first_pass")) {
- if (params->flags & F_ASK_OLDAUTHTOK_MASK) break;
- params->flags |= F_USE_FIRST_PASS | F_USE_AUTHTOK;
- } else
- if (!strcmp(*argv, "use_authtok")) {
- params->flags |= F_USE_AUTHTOK;
- } else
- break;
- argc--; argv++;
- }
+ const char *hash;
+ int retval;
- if (argc) {
- say(pamh, PAM_ERROR_MSG, getuid() != 0 ?
- MESSAGE_MISCONFIGURED : MESSAGE_INVALID_OPTION, *argv);
- return PAM_ABORT;
+#ifdef HAVE_SHADOW
+#ifdef __hpux
+ if (iscomsec()) {
+#else
+ if (!strcmp(pw->pw_passwd, "x")) {
+#endif
+ struct spwd *spw = getspnam(pw->pw_name);
+ endspent();
+ if (!spw)
+ return -1;
+ hash = NULL;
+ if (strlen(spw->sp_pwdp) >= 13) {
+#ifdef __hpux
+ hash = bigcrypt(pass, spw->sp_pwdp);
+#else
+ hash = crypt(pass, spw->sp_pwdp);
+#endif
+ }
+ retval = (hash && !strcmp(hash, spw->sp_pwdp)) ? 0 : -1;
+ _passwdqc_memzero(spw->sp_pwdp, strlen(spw->sp_pwdp));
+ return retval;
}
+#endif
- return PAM_SUCCESS;
+ hash = NULL;
+ if (strlen(pw->pw_passwd) >= 13)
+ hash = crypt(pass, pw->pw_passwd);
+ retval = (hash && !strcmp(hash, pw->pw_passwd)) ? 0 : -1;
+ _passwdqc_memzero(pw->pw_passwd, strlen(pw->pw_passwd));
+ return retval;
+}
+
+static int am_root(pam_handle_t *pamh)
+{
+ pam_item_t item;
+ const char *service;
+
+ if (getuid() != 0)
+ return 0;
+
+ if (pam_get_item(pamh, PAM_SERVICE, &item) != PAM_SUCCESS)
+ return 0;
+ service = item;
+
+ return !strcmp(service, "passwd") || !strcmp(service, "chpasswd");
}
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
- params_t params;
+ passwdqc_params_t params;
struct pam_response *resp;
struct passwd *pw, fake_pw;
-#ifdef HAVE_SHADOW
- struct spwd *spw;
-#endif
- char *user, *oldpass, *newpass, *randompass;
- const char *reason;
+ pam_item_t item;
+ const char *user, *oldpass, *newpass;
+ char *trypass, *randompass;
+ char *parse_reason;
+ const char *check_reason;
int ask_oldauthtok;
int randomonly, enforce, retries_left, retry_wanted;
int status;
- params = defaults;
- status = parse(&params, pamh, argc, argv);
- if (status != PAM_SUCCESS)
- return status;
+ passwdqc_params_reset(&params);
+ if (passwdqc_params_parse(&params, &parse_reason, argc, argv)) {
+ say(pamh, PAM_ERROR_MSG, am_root(pamh) ?
+ MESSAGE_INVALID_OPTION : MESSAGE_MISCONFIGURED,
+ parse_reason);
+ free(parse_reason);
+ return PAM_ABORT;
+ }
+ status = PAM_SUCCESS;
ask_oldauthtok = 0;
if (flags & PAM_PRELIM_CHECK) {
- if (params.flags & F_ASK_OLDAUTHTOK_PRELIM)
+ if (params.pam.flags & F_ASK_OLDAUTHTOK_PRELIM)
ask_oldauthtok = 1;
- } else
- if (flags & PAM_UPDATE_AUTHTOK) {
- if (params.flags & F_ASK_OLDAUTHTOK_UPDATE)
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+ if (params.pam.flags & F_ASK_OLDAUTHTOK_UPDATE)
ask_oldauthtok = 1;
- } else
+ } else {
+ passwdqc_params_free(&params);
return PAM_SERVICE_ERR;
+ }
- if (ask_oldauthtok && getuid() != 0) {
+ if (ask_oldauthtok && !am_root(pamh)) {
status = converse(pamh, PAM_PROMPT_ECHO_OFF,
PROMPT_OLDPASS, &resp);
@@ -341,86 +344,80 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
if (resp && resp->resp) {
status = pam_set_item(pamh,
PAM_OLDAUTHTOK, resp->resp);
- _pam_drop_reply(resp, 1);
+ pwqc_drop_pam_reply(resp, 1);
} else
status = PAM_AUTHTOK_RECOVERY_ERR;
}
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
}
- if (flags & PAM_PRELIM_CHECK)
+ if (flags & PAM_PRELIM_CHECK) {
+ passwdqc_params_free(&params);
return status;
+ }
- status = pam_get_item(pamh, PAM_USER, (pam_item_t *)&user);
+ status = pam_get_item(pamh, PAM_USER, &item);
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
+ user = item;
- status = pam_get_item(pamh, PAM_OLDAUTHTOK, (pam_item_t *)&oldpass);
+ status = pam_get_item(pamh, PAM_OLDAUTHTOK, &item);
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
+ oldpass = item;
- if (params.flags & F_NON_UNIX) {
+ if (params.pam.flags & F_NON_UNIX) {
pw = &fake_pw;
- pw->pw_name = user;
+ memset(pw, 0, sizeof(*pw));
+ pw->pw_name = (char *)user;
pw->pw_gecos = "";
+ pw->pw_dir = "";
} else {
+/* As currently implemented, we don't avoid timing leaks for valid vs. not
+ * usernames and hashes. Normally, the username would have already been
+ * checked and determined valid, and the check_oldauthtok option is only needed
+ * on systems that happen to have similar timing leaks all over the place. */
pw = getpwnam(user);
endpwent();
if (!pw)
- return PAM_USER_UNKNOWN;
- if ((params.flags & F_CHECK_OLDAUTHTOK) && getuid() != 0) {
- if (!oldpass)
- status = PAM_AUTH_ERR;
- else
-#ifdef HAVE_SHADOW
- if (!strcmp(pw->pw_passwd, "x")) {
- spw = getspnam(user);
- endspent();
- if (spw) {
- if (strcmp(crypt(oldpass, spw->sp_pwdp),
- spw->sp_pwdp))
- status = PAM_AUTH_ERR;
- memset(spw->sp_pwdp, 0,
- strlen(spw->sp_pwdp));
- } else
- status = PAM_AUTH_ERR;
- } else
-#endif
- if (strcmp(crypt(oldpass, pw->pw_passwd),
- pw->pw_passwd))
- status = PAM_AUTH_ERR;
- }
- memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
+ return logaudit(pamh, PAM_USER_UNKNOWN, &params);
+ if ((params.pam.flags & F_CHECK_OLDAUTHTOK) && !am_root(pamh)
+ && (!oldpass || check_pass(pw, oldpass)))
+ status = PAM_AUTH_ERR;
+ _passwdqc_memzero(pw->pw_passwd, strlen(pw->pw_passwd));
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
}
randomonly = params.qc.min[4] > params.qc.max;
- if (getuid() != 0)
- enforce = params.flags & F_ENFORCE_USERS;
+ if (am_root(pamh))
+ enforce = params.pam.flags & F_ENFORCE_ROOT;
else
- enforce = params.flags & F_ENFORCE_ROOT;
+ enforce = params.pam.flags & F_ENFORCE_USERS;
- if (params.flags & F_USE_AUTHTOK) {
- status = pam_get_item(pamh, PAM_AUTHTOK,
- (pam_item_t *)&newpass);
+ if (params.pam.flags & F_USE_AUTHTOK) {
+ status = pam_get_item(pamh, PAM_AUTHTOK, &item);
if (status != PAM_SUCCESS)
- return status;
- if (!newpass || (check_max(&params, pamh, newpass) && enforce))
- return PAM_AUTHTOK_ERR;
- reason = _passwdqc_check(&params.qc, newpass, oldpass, pw);
- if (reason) {
- say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason);
+ return logaudit(pamh, status, &params);
+ newpass = item;
+ if (!newpass ||
+ (check_max(&params.qc, pamh, newpass) && enforce))
+ return logaudit(pamh, PAM_AUTHTOK_ERR, &params);
+ check_reason =
+ passwdqc_check(&params.qc, newpass, oldpass, pw);
+ if (check_reason) {
+ say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS,
+ check_reason);
if (enforce)
status = PAM_AUTHTOK_ERR;
}
- return status;
+ return logaudit(pamh, status, &params);
}
- retries_left = params.retry;
+ retries_left = params.pam.retry;
retry:
retry_wanted = 0;
@@ -431,45 +428,48 @@ retry:
else
status = say(pamh, PAM_TEXT_INFO, MESSAGE_INTRO_PASSWORD);
if (status != PAM_SUCCESS)
- return status;
-
- if (!randomonly && params.qc.min[3] <= params.qc.min[4])
- status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_1,
- params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "",
+ return logaudit(pamh, status, &params);
+
+ if (!randomonly && params.qc.min[0] == params.qc.min[4])
+ status = say(pamh, PAM_TEXT_INFO,
+ MESSAGE_EXPLAIN_PASSWORD_1_CLASS(params.qc.min[4]));
+
+ else if (!randomonly && params.qc.min[3] == params.qc.min[4])
+ status = say(pamh, PAM_TEXT_INFO,
+ MESSAGE_EXPLAIN_PASSWORD_N_CLASSES(params.qc.min[4]),
+ params.qc.min[1] != params.qc.min[3] ? 3 : 2);
+ else if (!randomonly && params.qc.min[3] == INT_MAX)
+ status = say(pamh, PAM_TEXT_INFO,
+ MESSAGE_EXPLAIN_PASSWORD_ALL_CLASSES(params.qc.min[4]));
+ else if (!randomonly) {
+ status = say(pamh, PAM_TEXT_INFO,
+ MESSAGE_EXPLAIN_PASSWORD_ALL_OR_3_CLASSES(params.qc.min[4]),
params.qc.min[3]);
- else
- if (!randomonly)
- status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_2,
- params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "",
- params.qc.min[3],
- params.qc.min[4] == 8 || params.qc.min[4] == 11 ? "n" : "",
- params.qc.min[4]);
+ }
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
if (!randomonly &&
- params.qc.passphrase_words &&
- params.qc.min[2] <= params.qc.max) {
- status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSPHRASE,
- params.qc.passphrase_words,
+ params.qc.passphrase_words && params.qc.min[2] <= params.qc.max) {
+ status = say(pamh, PAM_TEXT_INFO,
+ MESSAGE_EXPLAIN_PASSPHRASE(params.qc.passphrase_words),
params.qc.min[2], params.qc.max);
if (status != PAM_SUCCESS)
- return status;
+ return logaudit(pamh, status, &params);
}
- randompass = _passwdqc_random(&params.qc);
+ randompass = passwdqc_random(&params.qc);
if (randompass) {
status = say(pamh, PAM_TEXT_INFO, randomonly ?
MESSAGE_RANDOMONLY : MESSAGE_RANDOM, randompass);
if (status != PAM_SUCCESS) {
- _pam_overwrite(randompass);
- randompass = NULL;
+ pwqc_overwrite_string(randompass);
+ pwqc_drop_mem(randompass);
}
- } else
- if (randomonly) {
- say(pamh, PAM_ERROR_MSG, getuid() != 0 ?
- MESSAGE_MISCONFIGURED : MESSAGE_RANDOMFAILED);
- return PAM_AUTHTOK_ERR;
+ } else if (randomonly) {
+ say(pamh, PAM_ERROR_MSG, am_root(pamh) ?
+ MESSAGE_RANDOMFAILED : MESSAGE_MISCONFIGURED);
+ return logaudit(pamh, PAM_AUTHTOK_ERR, &params);
}
status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_NEWPASS1, &resp);
@@ -477,33 +477,36 @@ retry:
status = PAM_AUTHTOK_ERR;
if (status != PAM_SUCCESS) {
- if (randompass) _pam_overwrite(randompass);
- return status;
+ pwqc_overwrite_string(randompass);
+ pwqc_drop_mem(randompass);
+ return logaudit(pamh, status, &params);
}
- newpass = strdup(resp->resp);
+ trypass = strdup(resp->resp);
- _pam_drop_reply(resp, 1);
+ pwqc_drop_pam_reply(resp, 1);
- if (!newpass) {
- if (randompass) _pam_overwrite(randompass);
- return PAM_AUTHTOK_ERR;
+ if (!trypass) {
+ pwqc_overwrite_string(randompass);
+ pwqc_drop_mem(randompass);
+ return logaudit(pamh, PAM_AUTHTOK_ERR, &params);
}
- if (check_max(&params, pamh, newpass) && enforce) {
+ if (check_max(&params.qc, pamh, trypass) && enforce) {
status = PAM_AUTHTOK_ERR;
retry_wanted = 1;
}
- reason = NULL;
+ check_reason = NULL; /* unused */
if (status == PAM_SUCCESS &&
- (!randompass || !strstr(newpass, randompass)) &&
+ (!randompass || !strstr(trypass, randompass)) &&
(randomonly ||
- (reason = _passwdqc_check(&params.qc, newpass, oldpass, pw)))) {
+ (check_reason = passwdqc_check(&params.qc, trypass, oldpass, pw)))) {
if (randomonly)
say(pamh, PAM_ERROR_MSG, MESSAGE_NOTRANDOM);
else
- say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason);
+ say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS,
+ check_reason);
if (enforce) {
status = PAM_AUTHTOK_ERR;
retry_wanted = 1;
@@ -515,7 +518,7 @@ retry:
PROMPT_NEWPASS2, &resp);
if (status == PAM_SUCCESS) {
if (resp && resp->resp) {
- if (strcmp(newpass, resp->resp)) {
+ if (strcmp(trypass, resp->resp)) {
status = say(pamh,
PAM_ERROR_MSG, MESSAGE_MISTYPED);
if (status == PAM_SUCCESS) {
@@ -523,17 +526,19 @@ retry:
retry_wanted = 1;
}
}
- _pam_drop_reply(resp, 1);
+ pwqc_drop_pam_reply(resp, 1);
} else
status = PAM_AUTHTOK_ERR;
}
if (status == PAM_SUCCESS)
- status = pam_set_item(pamh, PAM_AUTHTOK, newpass);
+ status = pam_set_item(pamh, PAM_AUTHTOK, trypass);
- if (randompass) _pam_overwrite(randompass);
- _pam_overwrite(newpass);
- free(newpass);
+ pwqc_overwrite_string(randompass);
+ pwqc_drop_mem(randompass);
+
+ pwqc_overwrite_string(trypass);
+ pwqc_drop_mem(trypass);
if (retry_wanted && --retries_left > 0) {
status = say(pamh, PAM_TEXT_INFO, MESSAGE_RETRY);
@@ -541,13 +546,13 @@ retry:
goto retry;
}
- return status;
+ return logaudit(pamh, status, &params);
}
#ifdef PAM_MODULE_ENTRY
PAM_MODULE_ENTRY("pam_passwdqc");
#elif defined(PAM_STATIC)
-struct pam_module _pam_passwdqc_modstruct = {
+const struct pam_module _pam_passwdqc_modstruct = {
"pam_passwdqc",
NULL,
NULL,