pam_passwdqc.c revision 254960
193787Sdes/* 294691Sdes * Copyright (c) 2000-2002 by Solar Designer. See LICENSE. 393787Sdes */ 493787Sdes 5254960Swill#define _XOPEN_SOURCE 600 693787Sdes#define _XOPEN_SOURCE_EXTENDED 7254960Swill#define _XOPEN_VERSION 600 893787Sdes#include <stdio.h> 993787Sdes#include <stdlib.h> 1093787Sdes#include <stdarg.h> 1193787Sdes#include <string.h> 1293787Sdes#include <limits.h> 1393787Sdes#include <unistd.h> 1493787Sdes#include <pwd.h> 1593787Sdes#ifdef HAVE_SHADOW 1693787Sdes#include <shadow.h> 1793787Sdes#endif 1893787Sdes 1993787Sdes#define PAM_SM_PASSWORD 2093787Sdes#ifndef LINUX_PAM 2193787Sdes#include <security/pam_appl.h> 2293787Sdes#endif 2393787Sdes#include <security/pam_modules.h> 2493787Sdes 2593787Sdes#include "pam_macros.h" 2693787Sdes 2793787Sdes#if !defined(PAM_EXTERN) && !defined(PAM_STATIC) 2893787Sdes#define PAM_EXTERN extern 2993787Sdes#endif 3093787Sdes 3194691Sdes#if !defined(PAM_AUTHTOK_RECOVERY_ERR) && defined(PAM_AUTHTOK_RECOVER_ERR) 3294691Sdes#define PAM_AUTHTOK_RECOVERY_ERR PAM_AUTHTOK_RECOVER_ERR 3393787Sdes#endif 3493787Sdes 3594691Sdes#if defined(__sun__) && !defined(LINUX_PAM) && !defined(_OPENPAM) 3694691Sdes/* Sun's PAM doesn't use const here */ 3794691Sdes#define lo_const 3893787Sdes#else 3994691Sdes#define lo_const const 4093787Sdes#endif 4194691Sdestypedef lo_const void *pam_item_t; 4293787Sdes 4393787Sdes#include "passwdqc.h" 4493787Sdes 4593787Sdes#define F_ENFORCE_MASK 0x00000003 4693787Sdes#define F_ENFORCE_USERS 0x00000001 4793787Sdes#define F_ENFORCE_ROOT 0x00000002 4893787Sdes#define F_ENFORCE_EVERYONE F_ENFORCE_MASK 4993787Sdes#define F_NON_UNIX 0x00000004 5093787Sdes#define F_ASK_OLDAUTHTOK_MASK 0x00000030 5193787Sdes#define F_ASK_OLDAUTHTOK_PRELIM 0x00000010 5293787Sdes#define F_ASK_OLDAUTHTOK_UPDATE 0x00000020 5393787Sdes#define F_CHECK_OLDAUTHTOK 0x00000040 5493787Sdes#define F_USE_FIRST_PASS 0x00000100 5593787Sdes#define F_USE_AUTHTOK 0x00000200 5693787Sdes 5793787Sdestypedef struct { 5893787Sdes passwdqc_params_t qc; 5993787Sdes int flags; 6093787Sdes int retry; 6193787Sdes} params_t; 6293787Sdes 6393787Sdesstatic params_t defaults = { 6493787Sdes { 6593787Sdes {INT_MAX, 24, 12, 8, 7}, /* min */ 6693787Sdes 40, /* max */ 6793787Sdes 3, /* passphrase_words */ 6893787Sdes 4, /* match_length */ 6993787Sdes 1, /* similar_deny */ 7093787Sdes 42 /* random_bits */ 7193787Sdes }, 7293787Sdes F_ENFORCE_EVERYONE, /* flags */ 7393787Sdes 3 /* retry */ 7493787Sdes}; 7593787Sdes 7693787Sdes#define PROMPT_OLDPASS \ 7793787Sdes "Enter current password: " 7893787Sdes#define PROMPT_NEWPASS1 \ 7993787Sdes "Enter new password: " 8093787Sdes#define PROMPT_NEWPASS2 \ 8193787Sdes "Re-type new password: " 8293787Sdes 8393787Sdes#define MESSAGE_MISCONFIGURED \ 8493787Sdes "System configuration error. Please contact your administrator." 8593787Sdes#define MESSAGE_INVALID_OPTION \ 8693787Sdes "pam_passwdqc: Invalid option: \"%s\"." 8793787Sdes#define MESSAGE_INTRO_PASSWORD \ 8893787Sdes "\nYou can now choose the new password.\n" 8993787Sdes#define MESSAGE_INTRO_BOTH \ 9093787Sdes "\nYou can now choose the new password or passphrase.\n" 9193787Sdes#define MESSAGE_EXPLAIN_PASSWORD_1 \ 9293787Sdes "A valid password should be a mix of upper and lower case letters,\n" \ 9393787Sdes "digits and other characters. You can use a%s %d character long\n" \ 9493787Sdes "password with characters from at least 3 of these 4 classes.\n" \ 9593787Sdes "Characters that form a common pattern are discarded by the check.\n" 9693787Sdes#define MESSAGE_EXPLAIN_PASSWORD_2 \ 9793787Sdes "A valid password should be a mix of upper and lower case letters,\n" \ 9893787Sdes "digits and other characters. You can use a%s %d character long\n" \ 9993787Sdes "password with characters from at least 3 of these 4 classes, or\n" \ 10093787Sdes "a%s %d character long password containing characters from all the\n" \ 10193787Sdes "classes. Characters that form a common pattern are discarded by\n" \ 10293787Sdes "the check.\n" 10393787Sdes#define MESSAGE_EXPLAIN_PASSPHRASE \ 10493787Sdes "A passphrase should be of at least %d words, %d to %d characters\n" \ 10593787Sdes "long and contain enough different characters.\n" 10693787Sdes#define MESSAGE_RANDOM \ 10793787Sdes "Alternatively, if noone else can see your terminal now, you can\n" \ 10893787Sdes "pick this as your password: \"%s\".\n" 10993787Sdes#define MESSAGE_RANDOMONLY \ 11093787Sdes "This system is configured to permit randomly generated passwords\n" \ 11193787Sdes "only. If noone else can see your terminal now, you can pick this\n" \ 11293787Sdes "as your password: \"%s\". Otherwise, come back later.\n" 11393787Sdes#define MESSAGE_RANDOMFAILED \ 11493787Sdes "This system is configured to use randomly generated passwords\n" \ 11593787Sdes "only, but the attempt to generate a password has failed. This\n" \ 11693787Sdes "could happen for a number of reasons: you could have requested\n" \ 11793787Sdes "an impossible password length, or the access to kernel random\n" \ 11893787Sdes "number pool could have failed." 11993787Sdes#define MESSAGE_TOOLONG \ 12093787Sdes "This password may be too long for some services. Choose another." 12193787Sdes#define MESSAGE_TRUNCATED \ 12293787Sdes "Warning: your longer password will be truncated to 8 characters." 12393787Sdes#define MESSAGE_WEAKPASS \ 12493787Sdes "Weak password: %s." 12593787Sdes#define MESSAGE_NOTRANDOM \ 12693787Sdes "Sorry, you've mistyped the password that was generated for you." 12793787Sdes#define MESSAGE_MISTYPED \ 12893787Sdes "Sorry, passwords do not match." 12993787Sdes#define MESSAGE_RETRY \ 13093787Sdes "Try again." 13193787Sdes 13294691Sdesstatic int converse(pam_handle_t *pamh, int style, lo_const char *text, 13393787Sdes struct pam_response **resp) 13493787Sdes{ 135254960Swill pam_item_t item; 136254960Swill lo_const struct pam_conv *conv; 13793787Sdes struct pam_message msg, *pmsg; 13893787Sdes int status; 13993787Sdes 140254960Swill status = pam_get_item(pamh, PAM_CONV, &item); 14193787Sdes if (status != PAM_SUCCESS) 14293787Sdes return status; 143254960Swill conv = item; 14493787Sdes 14593787Sdes pmsg = &msg; 14693787Sdes msg.msg_style = style; 147254960Swill msg.msg = (char *)text; 14893787Sdes 14993787Sdes *resp = NULL; 15094691Sdes return conv->conv(1, (lo_const struct pam_message **)&pmsg, resp, 15193787Sdes conv->appdata_ptr); 15293787Sdes} 15393787Sdes 15493787Sdes#ifdef __GNUC__ 15593787Sdes__attribute__ ((format (printf, 3, 4))) 15693787Sdes#endif 15793787Sdesstatic int say(pam_handle_t *pamh, int style, const char *format, ...) 15893787Sdes{ 15993787Sdes va_list args; 16093787Sdes char buffer[0x800]; 16193787Sdes int needed; 16293787Sdes struct pam_response *resp; 16393787Sdes int status; 16493787Sdes 16593787Sdes va_start(args, format); 16693787Sdes needed = vsnprintf(buffer, sizeof(buffer), format, args); 16793787Sdes va_end(args); 16893787Sdes 16994691Sdes if ((unsigned int)needed < sizeof(buffer)) { 17093787Sdes status = converse(pamh, style, buffer, &resp); 17193787Sdes _pam_overwrite(buffer); 17293787Sdes } else { 17393787Sdes status = PAM_ABORT; 17493787Sdes memset(buffer, 0, sizeof(buffer)); 17593787Sdes } 17693787Sdes 17793787Sdes return status; 17893787Sdes} 17993787Sdes 18094691Sdesstatic int check_max(params_t *params, pam_handle_t *pamh, const char *newpass) 18193787Sdes{ 18294691Sdes if ((int)strlen(newpass) > params->qc.max) { 18393787Sdes if (params->qc.max != 8) { 18493787Sdes say(pamh, PAM_ERROR_MSG, MESSAGE_TOOLONG); 18593787Sdes return -1; 18693787Sdes } 18793787Sdes say(pamh, PAM_TEXT_INFO, MESSAGE_TRUNCATED); 18893787Sdes } 18993787Sdes 19093787Sdes return 0; 19193787Sdes} 19293787Sdes 19393787Sdesstatic int parse(params_t *params, pam_handle_t *pamh, 19493787Sdes int argc, const char **argv) 19593787Sdes{ 19693787Sdes const char *p; 19794691Sdes char *e; 19893787Sdes int i; 19993787Sdes unsigned long v; 20093787Sdes 20193787Sdes while (argc) { 20293787Sdes if (!strncmp(*argv, "min=", 4)) { 20393787Sdes p = *argv + 4; 20493787Sdes for (i = 0; i < 5; i++) { 20593787Sdes if (!strncmp(p, "disabled", 8)) { 20693787Sdes v = INT_MAX; 20793787Sdes p += 8; 20894691Sdes } else { 20994691Sdes v = strtoul(p, &e, 10); 21094691Sdes p = e; 21194691Sdes } 21293787Sdes if (i < 4 && *p++ != ',') break; 21393787Sdes if (v > INT_MAX) break; 21494691Sdes if (i && (int)v > params->qc.min[i - 1]) break; 21593787Sdes params->qc.min[i] = v; 21693787Sdes } 21793787Sdes if (*p) break; 21893787Sdes } else 21993787Sdes if (!strncmp(*argv, "max=", 4)) { 22094691Sdes v = strtoul(*argv + 4, &e, 10); 22194691Sdes if (*e || v < 8 || v > INT_MAX) break; 22293787Sdes params->qc.max = v; 22393787Sdes } else 22493787Sdes if (!strncmp(*argv, "passphrase=", 11)) { 22594691Sdes v = strtoul(*argv + 11, &e, 10); 22694691Sdes if (*e || v > INT_MAX) break; 22793787Sdes params->qc.passphrase_words = v; 22893787Sdes } else 22993787Sdes if (!strncmp(*argv, "match=", 6)) { 23094691Sdes v = strtoul(*argv + 6, &e, 10); 23194691Sdes if (*e || v > INT_MAX) break; 23293787Sdes params->qc.match_length = v; 23393787Sdes } else 23493787Sdes if (!strncmp(*argv, "similar=", 8)) { 23593787Sdes if (!strcmp(*argv + 8, "permit")) 23693787Sdes params->qc.similar_deny = 0; 23793787Sdes else 23893787Sdes if (!strcmp(*argv + 8, "deny")) 23993787Sdes params->qc.similar_deny = 1; 24093787Sdes else 24193787Sdes break; 24293787Sdes } else 24393787Sdes if (!strncmp(*argv, "random=", 7)) { 24494691Sdes v = strtoul(*argv + 7, &e, 10); 24594691Sdes if (!strcmp(e, ",only")) { 24694691Sdes e += 5; 24793787Sdes params->qc.min[4] = INT_MAX; 24893787Sdes } 24994691Sdes if (*e || v > INT_MAX) break; 25093787Sdes params->qc.random_bits = v; 25193787Sdes } else 25293787Sdes if (!strncmp(*argv, "enforce=", 8)) { 25393787Sdes params->flags &= ~F_ENFORCE_MASK; 25493787Sdes if (!strcmp(*argv + 8, "users")) 25593787Sdes params->flags |= F_ENFORCE_USERS; 25693787Sdes else 25793787Sdes if (!strcmp(*argv + 8, "everyone")) 25893787Sdes params->flags |= F_ENFORCE_EVERYONE; 25993787Sdes else 26093787Sdes if (strcmp(*argv + 8, "none")) 26193787Sdes break; 26293787Sdes } else 26393787Sdes if (!strcmp(*argv, "non-unix")) { 26493787Sdes if (params->flags & F_CHECK_OLDAUTHTOK) break; 26593787Sdes params->flags |= F_NON_UNIX; 26693787Sdes } else 26793787Sdes if (!strncmp(*argv, "retry=", 6)) { 26894691Sdes v = strtoul(*argv + 6, &e, 10); 26994691Sdes if (*e || v > INT_MAX) break; 27093787Sdes params->retry = v; 27193787Sdes } else 27293787Sdes if (!strncmp(*argv, "ask_oldauthtok", 14)) { 27393787Sdes params->flags &= ~F_ASK_OLDAUTHTOK_MASK; 27493787Sdes if (params->flags & F_USE_FIRST_PASS) break; 27593787Sdes if (!strcmp(*argv + 14, "=update")) 27693787Sdes params->flags |= F_ASK_OLDAUTHTOK_UPDATE; 27793787Sdes else 27893787Sdes if (!(*argv)[14]) 27993787Sdes params->flags |= F_ASK_OLDAUTHTOK_PRELIM; 28093787Sdes else 28193787Sdes break; 28293787Sdes } else 28393787Sdes if (!strcmp(*argv, "check_oldauthtok")) { 28493787Sdes if (params->flags & F_NON_UNIX) break; 28593787Sdes params->flags |= F_CHECK_OLDAUTHTOK; 28693787Sdes } else 28793787Sdes if (!strcmp(*argv, "use_first_pass")) { 28893787Sdes if (params->flags & F_ASK_OLDAUTHTOK_MASK) break; 28993787Sdes params->flags |= F_USE_FIRST_PASS | F_USE_AUTHTOK; 29093787Sdes } else 29193787Sdes if (!strcmp(*argv, "use_authtok")) { 29293787Sdes params->flags |= F_USE_AUTHTOK; 29393787Sdes } else 29493787Sdes break; 29593787Sdes argc--; argv++; 29693787Sdes } 29793787Sdes 29893787Sdes if (argc) { 299254960Swill if (getuid() != 0) { 300254960Swill say(pamh, PAM_ERROR_MSG, MESSAGE_MISCONFIGURED); 301254960Swill } else { 302254960Swill say(pamh, PAM_ERROR_MSG, MESSAGE_INVALID_OPTION, *argv); 303254960Swill } 30493787Sdes return PAM_ABORT; 30593787Sdes } 30693787Sdes 30793787Sdes return PAM_SUCCESS; 30893787Sdes} 30993787Sdes 31093787SdesPAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, 31193787Sdes int argc, const char **argv) 31293787Sdes{ 31393787Sdes params_t params; 31493787Sdes struct pam_response *resp; 31593787Sdes struct passwd *pw, fake_pw; 31693787Sdes#ifdef HAVE_SHADOW 31793787Sdes struct spwd *spw; 31893787Sdes#endif 319254960Swill pam_item_t item; 320254960Swill lo_const char *user, *oldpass, *curpass; 321254960Swill char *newpass, *randompass; 32294691Sdes const char *reason; 32393787Sdes int ask_oldauthtok; 32493787Sdes int randomonly, enforce, retries_left, retry_wanted; 32593787Sdes int status; 32693787Sdes 32793787Sdes params = defaults; 32893787Sdes status = parse(¶ms, pamh, argc, argv); 32993787Sdes if (status != PAM_SUCCESS) 33093787Sdes return status; 33193787Sdes 33293787Sdes ask_oldauthtok = 0; 33393787Sdes if (flags & PAM_PRELIM_CHECK) { 33493787Sdes if (params.flags & F_ASK_OLDAUTHTOK_PRELIM) 33593787Sdes ask_oldauthtok = 1; 33693787Sdes } else 33793787Sdes if (flags & PAM_UPDATE_AUTHTOK) { 33893787Sdes if (params.flags & F_ASK_OLDAUTHTOK_UPDATE) 33993787Sdes ask_oldauthtok = 1; 34093787Sdes } else 34193787Sdes return PAM_SERVICE_ERR; 34293787Sdes 34393787Sdes if (ask_oldauthtok && getuid() != 0) { 34493787Sdes status = converse(pamh, PAM_PROMPT_ECHO_OFF, 34593787Sdes PROMPT_OLDPASS, &resp); 34693787Sdes 34793787Sdes if (status == PAM_SUCCESS) { 34893787Sdes if (resp && resp->resp) { 34993787Sdes status = pam_set_item(pamh, 35093787Sdes PAM_OLDAUTHTOK, resp->resp); 35193787Sdes _pam_drop_reply(resp, 1); 35293787Sdes } else 35394691Sdes status = PAM_AUTHTOK_RECOVERY_ERR; 35493787Sdes } 35593787Sdes 35693787Sdes if (status != PAM_SUCCESS) 35793787Sdes return status; 35893787Sdes } 35993787Sdes 36093787Sdes if (flags & PAM_PRELIM_CHECK) 36193787Sdes return status; 36293787Sdes 363254960Swill status = pam_get_item(pamh, PAM_USER, &item); 36493787Sdes if (status != PAM_SUCCESS) 36593787Sdes return status; 366254960Swill user = item; 36793787Sdes 368254960Swill status = pam_get_item(pamh, PAM_OLDAUTHTOK, &item); 36993787Sdes if (status != PAM_SUCCESS) 37093787Sdes return status; 371254960Swill oldpass = item; 37293787Sdes 37393787Sdes if (params.flags & F_NON_UNIX) { 37493787Sdes pw = &fake_pw; 375254960Swill pw->pw_name = (char *)user; 37693787Sdes pw->pw_gecos = ""; 37793787Sdes } else { 37893787Sdes pw = getpwnam(user); 37993787Sdes endpwent(); 38093787Sdes if (!pw) 38193787Sdes return PAM_USER_UNKNOWN; 38293787Sdes if ((params.flags & F_CHECK_OLDAUTHTOK) && getuid() != 0) { 38393787Sdes if (!oldpass) 38493787Sdes status = PAM_AUTH_ERR; 38593787Sdes else 38693787Sdes#ifdef HAVE_SHADOW 38793787Sdes if (!strcmp(pw->pw_passwd, "x")) { 38893787Sdes spw = getspnam(user); 38993787Sdes endspent(); 39093787Sdes if (spw) { 39193787Sdes if (strcmp(crypt(oldpass, spw->sp_pwdp), 39293787Sdes spw->sp_pwdp)) 39393787Sdes status = PAM_AUTH_ERR; 39493787Sdes memset(spw->sp_pwdp, 0, 39593787Sdes strlen(spw->sp_pwdp)); 39693787Sdes } else 39793787Sdes status = PAM_AUTH_ERR; 39893787Sdes } else 39993787Sdes#endif 40093787Sdes if (strcmp(crypt(oldpass, pw->pw_passwd), 40193787Sdes pw->pw_passwd)) 40293787Sdes status = PAM_AUTH_ERR; 40393787Sdes } 40493787Sdes memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); 40593787Sdes if (status != PAM_SUCCESS) 40693787Sdes return status; 40793787Sdes } 40893787Sdes 40993787Sdes randomonly = params.qc.min[4] > params.qc.max; 41093787Sdes 41193787Sdes if (getuid() != 0) 41293787Sdes enforce = params.flags & F_ENFORCE_USERS; 41393787Sdes else 41493787Sdes enforce = params.flags & F_ENFORCE_ROOT; 41593787Sdes 41693787Sdes if (params.flags & F_USE_AUTHTOK) { 417254960Swill status = pam_get_item(pamh, PAM_AUTHTOK, &item); 41893787Sdes if (status != PAM_SUCCESS) 41993787Sdes return status; 420254960Swill curpass = item; 421254960Swill if (!curpass || (check_max(¶ms, pamh, curpass) && enforce)) 42294889Sdes return PAM_AUTHTOK_ERR; 423254960Swill reason = _passwdqc_check(¶ms.qc, curpass, oldpass, pw); 42493787Sdes if (reason) { 42593787Sdes say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason); 42693787Sdes if (enforce) 42794889Sdes status = PAM_AUTHTOK_ERR; 42893787Sdes } 42993787Sdes return status; 43093787Sdes } 43193787Sdes 43293787Sdes retries_left = params.retry; 43393787Sdes 43493787Sdesretry: 43593787Sdes retry_wanted = 0; 43693787Sdes 43793787Sdes if (!randomonly && 43893787Sdes params.qc.passphrase_words && params.qc.min[2] <= params.qc.max) 43993787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_INTRO_BOTH); 44093787Sdes else 44193787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_INTRO_PASSWORD); 44293787Sdes if (status != PAM_SUCCESS) 44393787Sdes return status; 44493787Sdes 44593787Sdes if (!randomonly && params.qc.min[3] <= params.qc.min[4]) 44693787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_1, 44793787Sdes params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "", 44893787Sdes params.qc.min[3]); 44993787Sdes else 45093787Sdes if (!randomonly) 45193787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSWORD_2, 45293787Sdes params.qc.min[3] == 8 || params.qc.min[3] == 11 ? "n" : "", 45393787Sdes params.qc.min[3], 45493787Sdes params.qc.min[4] == 8 || params.qc.min[4] == 11 ? "n" : "", 45593787Sdes params.qc.min[4]); 45693787Sdes if (status != PAM_SUCCESS) 45793787Sdes return status; 45893787Sdes 45993787Sdes if (!randomonly && 46093787Sdes params.qc.passphrase_words && 46193787Sdes params.qc.min[2] <= params.qc.max) { 46293787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_EXPLAIN_PASSPHRASE, 46393787Sdes params.qc.passphrase_words, 46493787Sdes params.qc.min[2], params.qc.max); 46593787Sdes if (status != PAM_SUCCESS) 46693787Sdes return status; 46793787Sdes } 46893787Sdes 46993787Sdes randompass = _passwdqc_random(¶ms.qc); 47093787Sdes if (randompass) { 47193787Sdes status = say(pamh, PAM_TEXT_INFO, randomonly ? 47293787Sdes MESSAGE_RANDOMONLY : MESSAGE_RANDOM, randompass); 47393787Sdes if (status != PAM_SUCCESS) { 47493787Sdes _pam_overwrite(randompass); 47593787Sdes randompass = NULL; 47693787Sdes } 47793787Sdes } else 47893787Sdes if (randomonly) { 47993787Sdes say(pamh, PAM_ERROR_MSG, getuid() != 0 ? 48093787Sdes MESSAGE_MISCONFIGURED : MESSAGE_RANDOMFAILED); 48194889Sdes return PAM_AUTHTOK_ERR; 48293787Sdes } 48393787Sdes 48493787Sdes status = converse(pamh, PAM_PROMPT_ECHO_OFF, PROMPT_NEWPASS1, &resp); 48593787Sdes if (status == PAM_SUCCESS && (!resp || !resp->resp)) 48694889Sdes status = PAM_AUTHTOK_ERR; 48793787Sdes 48893787Sdes if (status != PAM_SUCCESS) { 48993787Sdes if (randompass) _pam_overwrite(randompass); 49093787Sdes return status; 49193787Sdes } 49293787Sdes 49393787Sdes newpass = strdup(resp->resp); 49493787Sdes 49593787Sdes _pam_drop_reply(resp, 1); 49693787Sdes 49793787Sdes if (!newpass) { 49893787Sdes if (randompass) _pam_overwrite(randompass); 499254960Swill return status; 50093787Sdes } 50193787Sdes 50293787Sdes if (check_max(¶ms, pamh, newpass) && enforce) { 50394889Sdes status = PAM_AUTHTOK_ERR; 50493787Sdes retry_wanted = 1; 50593787Sdes } 50693787Sdes 50793787Sdes reason = NULL; 50893787Sdes if (status == PAM_SUCCESS && 50993787Sdes (!randompass || !strstr(newpass, randompass)) && 51093787Sdes (randomonly || 51193787Sdes (reason = _passwdqc_check(¶ms.qc, newpass, oldpass, pw)))) { 51293787Sdes if (randomonly) 51393787Sdes say(pamh, PAM_ERROR_MSG, MESSAGE_NOTRANDOM); 51493787Sdes else 51593787Sdes say(pamh, PAM_ERROR_MSG, MESSAGE_WEAKPASS, reason); 51693787Sdes if (enforce) { 51794889Sdes status = PAM_AUTHTOK_ERR; 51893787Sdes retry_wanted = 1; 51993787Sdes } 52093787Sdes } 52193787Sdes 52293787Sdes if (status == PAM_SUCCESS) 52393787Sdes status = converse(pamh, PAM_PROMPT_ECHO_OFF, 52493787Sdes PROMPT_NEWPASS2, &resp); 52593787Sdes if (status == PAM_SUCCESS) { 52693787Sdes if (resp && resp->resp) { 52793787Sdes if (strcmp(newpass, resp->resp)) { 52893787Sdes status = say(pamh, 52993787Sdes PAM_ERROR_MSG, MESSAGE_MISTYPED); 53093787Sdes if (status == PAM_SUCCESS) { 53194889Sdes status = PAM_AUTHTOK_ERR; 53293787Sdes retry_wanted = 1; 53393787Sdes } 53493787Sdes } 53593787Sdes _pam_drop_reply(resp, 1); 53693787Sdes } else 53794889Sdes status = PAM_AUTHTOK_ERR; 53893787Sdes } 53993787Sdes 54093787Sdes if (status == PAM_SUCCESS) 54193787Sdes status = pam_set_item(pamh, PAM_AUTHTOK, newpass); 54293787Sdes 54393787Sdes if (randompass) _pam_overwrite(randompass); 54493787Sdes _pam_overwrite(newpass); 54593787Sdes free(newpass); 54693787Sdes 54793787Sdes if (retry_wanted && --retries_left > 0) { 54893787Sdes status = say(pamh, PAM_TEXT_INFO, MESSAGE_RETRY); 54993787Sdes if (status == PAM_SUCCESS) 55093787Sdes goto retry; 55193787Sdes } 55293787Sdes 55393787Sdes return status; 55493787Sdes} 55593787Sdes 55694691Sdes#ifdef PAM_MODULE_ENTRY 55794691SdesPAM_MODULE_ENTRY("pam_passwdqc"); 55894691Sdes#elif defined(PAM_STATIC) 55993787Sdesstruct pam_module _pam_passwdqc_modstruct = { 56093787Sdes "pam_passwdqc", 56193787Sdes NULL, 56293787Sdes NULL, 56393787Sdes NULL, 56493787Sdes NULL, 56593787Sdes NULL, 56693787Sdes pam_sm_chauthtok 56793787Sdes}; 56893787Sdes#endif 569