|
Message-ID: <20180704233216.GD29590@altlinux.org> Date: Thu, 5 Jul 2018 02:32:16 +0300 From: "Dmitry V. Levin" <ldv@...linux.org> To: owl-dev@...ts.openwall.com Subject: [PATCH 3/5] pam_tcb: use pam_get_authtok(3) instead of _unix_read_password This follows the change implemented in Linux-PAM commit Linux-PAM-1.3.0~5. pam_get_authtok(3) was introduced in Linux-PAM by commit Linux-PAM-1_0_90~4 back in 2008. As pam_get_authtok(3) does not support not_set_pass option, the support for this not much useful option is dropped. Instead we get a proper support for authtok_type= option. --- pam_tcb/pam_tcb.8 | 6 ++- pam_tcb/pam_unix_auth.c | 4 +- pam_tcb/pam_unix_passwd.c | 83 +++++++--------------------- pam_tcb/support.c | 134 ++-------------------------------------------- pam_tcb/support.h | 30 ++--------- 5 files changed, 32 insertions(+), 225 deletions(-) diff --git a/pam_tcb/pam_tcb.8 b/pam_tcb/pam_tcb.8 index 38a338c..0c6ed3c 100644 --- a/pam_tcb/pam_tcb.8 +++ b/pam_tcb/pam_tcb.8 @@ -171,8 +171,10 @@ but applies to the (new) .B PAM_AUTHTOK only. This is intended for stacking password management modules. .TP -.B not_set_pass -Don't set the PAM items with passwords used by this module. +.BR authtok_type = +This option can be used to modify the password prompt +when changing passwords to include the type of the password. +The default is empty. .TP .B likeauth When called as a credential setting module, return the same value as diff --git a/pam_tcb/pam_unix_auth.c b/pam_tcb/pam_unix_auth.c index 9740870..8857daf 100644 --- a/pam_tcb/pam_unix_auth.c +++ b/pam_tcb/pam_unix_auth.c @@ -12,7 +12,6 @@ #include "attribute.h" #include "support.h" -#define DATA_AUTHTOK "-UN*X-PASS" #define DATA_AUTH_RETVAL "-UN*X-AUTH-RETVAL" static void retval_cleanup(unused pam_handle_t * pamh, void *data, @@ -84,8 +83,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, goto out_save_retval; } - retval = _unix_read_password(pamh, NULL, PROMPT_PASS, NULL, - DATA_AUTHTOK, &pass); + retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, NULL); if (retval != PAM_SUCCESS) { #if defined(PAM_CONV_AGAIN) && defined(PAM_INCOMPLETE) diff --git a/pam_tcb/pam_unix_passwd.c b/pam_tcb/pam_unix_passwd.c index ee99609..1561d14 100644 --- a/pam_tcb/pam_unix_passwd.c +++ b/pam_tcb/pam_unix_passwd.c @@ -23,9 +23,6 @@ #include "attribute.h" #include "support.h" -#define DATA_OLD_AUTHTOK "-UN*X-OLD-PASS" -#define DATA_NEW_AUTHTOK "-UN*X-NEW-PASS" - #define TRIES 3 #define TMP_SUFFIX ".tmp" @@ -246,8 +243,7 @@ static char *get_pwfile(const char *forwho) } } -static int do_setpass(pam_handle_t *pamh, const char *forwho, - const char *fromwhat, char *towhat) +static int do_setpass(pam_handle_t *pamh, const char *forwho, char *towhat) { struct passwd *pw = NULL; char *file; @@ -382,9 +378,6 @@ static int unix_approve_pass(pam_handle_t *pamh, static int unix_prelim(pam_handle_t *pamh, const char *user) { - int lctrl[OPT_SIZE]; - char *greeting; - const char *oldpass; int retval = PAM_SUCCESS; D(("called")); @@ -392,20 +385,15 @@ static int unix_prelim(pam_handle_t *pamh, const char *user) if (_unix_blankpasswd(pamh, user)) goto out; - if (asprintf(&greeting, MESSAGE_CHANGING, user) < 0) { - pam_syslog(pamh, LOG_CRIT, "Out of memory"); - return PAM_BUF_ERR; - } - if (off(UNIX__IAMROOT)) { - memcpy(lctrl, pam_unix_param.ctrl, sizeof(lctrl)); - set(UNIX__OLD_PASSWD); - retval = _unix_read_password(pamh, greeting, - PROMPT_OLDPASS, NULL, - DATA_OLD_AUTHTOK, &oldpass); - free(greeting); - memcpy(pam_unix_param.ctrl, lctrl, - sizeof(pam_unix_param.ctrl)); + const char *oldpass; + + if (off(UNIX__QUIET)) { + retval = pam_info(pamh, MESSAGE_CHANGING, user); + if (retval != PAM_SUCCESS) + return retval; + } + retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &oldpass, NULL); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, @@ -423,14 +411,8 @@ static int unix_prelim(pam_handle_t *pamh, const char *user) } } else { D(("process run by root so no authentication is done")); - oldpass = NULL; - retval = PAM_SUCCESS; } - retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *)oldpass); - if (retval != PAM_SUCCESS) - pam_syslog(pamh, LOG_CRIT, "Failed to set PAM_OLDAUTHTOK"); - retval = unix_verify_shadow(user); if (retval == PAM_AUTHTOK_ERR) { if (off(UNIX__IAMROOT)) { @@ -465,6 +447,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { int retval, retry; + pam_item_t item; char oldprefix[HASH_PREFIX_SIZE]; /* <DO NOT free() THESE> */ const char *user, *oldpass, *newpass; @@ -519,33 +502,15 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, D(("do update")); - /* - * Get the old token back. NULL was ok only if root (at this - * point we assume that this has already been enforced on a - * previous call to this function). - */ - if (off(UNIX_NOT_SET_PASS)) { - pam_item_t item; - - retval = pam_get_item(pamh, PAM_OLDAUTHTOK, &item); - oldpass = item; - } else { - pam_data_t item; - - retval = pam_get_data(pamh, DATA_OLD_AUTHTOK, &item); - if (retval == PAM_NO_MODULE_DATA) { - retval = PAM_SUCCESS; - item = NULL; - } - oldpass = item; - } - D(("oldpass=[%s]", oldpass)); - + retval = pam_get_item(pamh, PAM_OLDAUTHTOK, &item); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "User not authenticated"); return retval; } + oldpass = item; + D(("oldpass=[%s]", oldpass)); + /* check account expiration */ retval = unix_verify_shadow(user); if (retval != PAM_SUCCESS) { @@ -557,20 +522,10 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, D(("get new password now")); retval = PAM_AUTHTOK_ERR; - retry = 0; + retry = on(UNIX_USE_FIRST_PASS) ? TRIES - 1 : 0; newhash = NULL; while (retval != PAM_SUCCESS && retry++ < TRIES) { - int old_authtok_usage = pam_unix_param.authtok_usage; - /* - * use_authtok is to force the use of a previously entered - * password, needed for pluggable password strength checking. - */ - if (on(UNIX_USE_AUTHTOK)) - pam_unix_param.authtok_usage = USE_FORCED; - retval = _unix_read_password(pamh, NULL, - PROMPT_NEWPASS1, PROMPT_NEWPASS2, - DATA_NEW_AUTHTOK, &newpass); - pam_unix_param.authtok_usage = old_authtok_usage; + retval = pam_get_authtok(pamh, PAM_AUTHTOK, &newpass, NULL); D(("returned to pam_sm_chauthtok")); @@ -592,10 +547,11 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, retval = unix_approve_pass(pamh, oldpass, newpass); } + _pam_overwrite((char *)oldpass); + if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "New password not acceptable"); _pam_overwrite((char *)newpass); - _pam_overwrite((char *)oldpass); return retval; } @@ -612,10 +568,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* update the password database(s) -- race conditions? */ if (newhash) - retval = do_setpass(pamh, user, oldpass, newhash); + retval = do_setpass(pamh, user, newhash); else retval = PAM_BUF_ERR; - _pam_overwrite((char *)oldpass); _pam_delete(newhash); if (retval == PAM_SUCCESS) { diff --git a/pam_tcb/support.c b/pam_tcb/support.c index 322d366..5a60a5d 100644 --- a/pam_tcb/support.c +++ b/pam_tcb/support.c @@ -32,12 +32,6 @@ IO_LOOP(write_loop, write, const) #include "attribute.h" #include "support.h" -static void data_cleanup(unused pam_handle_t *pamh, void *data, - unused int error_status) -{ - _pam_delete(data); -} - int unix_getspnam(struct spwd **spw, const struct passwd *pw) { D(("called")); @@ -640,109 +634,6 @@ int _unix_verify_password(pam_handle_t *pamh, return retval; } -/* - * Obtain a password from the user. - */ - -int _unix_read_password(pam_handle_t *pamh, - const char *comment, const char *prompt1, const char *prompt2, - const char *data_name, const char **pass) -{ - pam_item_t item; - char *token; - int authtok_flag; - int retval = PAM_SUCCESS; - - D(("called")); - - /* make sure nothing inappropriate gets returned */ - *pass = token = NULL; - - /* which authentication token are we getting? */ - authtok_flag = on(UNIX__OLD_PASSWD) ? PAM_OLDAUTHTOK : PAM_AUTHTOK; - - /* should we obtain the password from a PAM item? */ - if (pam_unix_param.authtok_usage != USE_NONE) { - retval = pam_get_item(pamh, authtok_flag, &item); - if (retval != PAM_SUCCESS) { - /* very strange */ - return retval; - } else if (item) { /* we have a password! */ - *pass = item; - item = NULL; - return PAM_SUCCESS; - } else if (pam_unix_param.authtok_usage == USE_FORCED) { - return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ - } else if (on(UNIX_USE_AUTHTOK) - && off(UNIX__OLD_PASSWD)) { - return PAM_AUTHTOK_RECOVER_ERR; - } - } - - /* getting here implies we will have to get the password from the - * user directly */ - if (comment && off(UNIX__QUIET)) { - retval = pam_info(pamh, "%s", comment); - } - - if (retval == PAM_SUCCESS && prompt1) { - retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &token, "%s", - prompt1); - } - - if (retval == PAM_SUCCESS && token && prompt2) { - char *resp; - retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &resp, "%s", - prompt2); - if (retval != PAM_SUCCESS || !resp) { - _pam_delete(token); - } else if (strcmp(token, resp)) { - _pam_delete(token); - pam_error(pamh, "%s", MESSAGE_MISTYPED); - retval = PAM_AUTHTOK_RECOVER_ERR; - } - _pam_delete(resp); - } - - if (retval != PAM_SUCCESS) { - pam_syslog(pamh, LOG_NOTICE, - "Unable to obtain a password"); - return retval; - } - - /* 'token' is the entered password */ - if (off(UNIX_NOT_SET_PASS)) { - /* we store this password as an item */ - retval = pam_set_item(pamh, authtok_flag, token); - _pam_delete(token); - if (retval != PAM_SUCCESS || - (retval = pam_get_item(pamh, authtok_flag, &item)) - != PAM_SUCCESS) { - pam_syslog(pamh, LOG_CRIT, - "Error manipulating password"); - return retval; - } - } else { - /* - * Then store it as data specific to this module. pam_end() - * will arrange to clean it up. - */ - retval = pam_set_data(pamh, data_name, (void *)token, - data_cleanup); - if (retval != PAM_SUCCESS) { - _pam_delete(token); - pam_syslog(pamh, LOG_CRIT, - "Error manipulating password"); - return retval; - } - item = token; - } - - *pass = item; - - return PAM_SUCCESS; -} - static char *crypt_wrapper_ra(pam_handle_t *pamh, const char *key, const char *salt) { @@ -824,7 +715,8 @@ static struct bool_names { int optval, negate; } unix_bools[] = { {"audit", UNIX_AUDIT, 0}, - {"not_set_pass", UNIX_NOT_SET_PASS, 0}, + {"use_first_pass", UNIX_USE_FIRST_PASS, 0}, + {"try_first_pass", UNIX_TRY_FIRST_PASS, 0}, {"use_authtok", UNIX_USE_AUTHTOK, 0}, {"shadow", UNIX_SHADOW, 0}, {"passwd", UNIX_PASSWD, 0}, @@ -849,10 +741,6 @@ static int parse_opt(pam_handle_t *pamh, const char *item, if (!strcmp(item, "md5")) opt = "prefix=$1$"; - else if (!strcmp(item, "try_first_pass")) - opt = "authtok_usage=try"; - else if (!strcmp(item, "use_first_pass")) - opt = "authtok_usage=forced"; else opt = item; @@ -905,7 +793,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int argc, const char **argv) unsigned int i; const char *param; struct cmdline_opts the_cmdline_opts[] = { - {"authtok_usage=", NULL, NULL}, + {"authtok_type=", NULL, NULL}, {"helper=", NULL, NULL}, {"count=", NULL, NULL}, {"write_to=", NULL, NULL}, @@ -970,22 +858,6 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int argc, const char **argv) } else pam_unix_param.count = 0; - param = get_optval("authtok_usage=", the_cmdline_opts); - if (param) { - if (!strcmp(param, "no")) - pam_unix_param.authtok_usage = USE_NONE; - else if (!strcmp(param, "try")) - pam_unix_param.authtok_usage = USE_TRY; - else if (!strcmp(param, "forced")) - pam_unix_param.authtok_usage = USE_FORCED; - else { - pam_syslog(pamh, LOG_ERR, - "Invalid authtok_usage= argument: %s", param); - return 0; - } - } else - pam_unix_param.authtok_usage = USE_NONE; - param = get_optval("write_to=", the_cmdline_opts); if (param) { if (!strcmp(param, "passwd")) diff --git a/pam_tcb/support.h b/pam_tcb/support.h index f2cf89e..4abf1f1 100644 --- a/pam_tcb/support.h +++ b/pam_tcb/support.h @@ -27,18 +27,6 @@ /* should be large enough to hold "*NP*" */ #define HASH_PREFIX_SIZE 5 -/* Password prompt to use for authentication */ -#define PROMPT_PASS \ - _("Password: ") - -/* Prompts to use for password changes */ -#define PROMPT_OLDPASS \ - _("Enter current password: ") -#define PROMPT_NEWPASS1 \ - _("Enter new password: ") -#define PROMPT_NEWPASS2 \ - _("Re-type new password: ") - /* Possible messages during account management */ #define MESSAGE_ACCT_EXPIRED \ _("Your account has expired; please contact your system administrator.") @@ -56,8 +44,6 @@ _("No password supplied.") #define MESSAGE_TOOSOON \ _("You must wait longer to change your password.") -#define MESSAGE_MISTYPED \ - _("Sorry, passwords do not match.") /* * Here are the various boolean options recognized by the unix module. @@ -71,7 +57,11 @@ enum { UNIX_AUDIT, /* print more things than debug, */ /* some information may be sensitive */ - UNIX_NOT_SET_PASS, /* don't set the AUTHTOK items */ + UNIX_USE_FIRST_PASS, /* don't prompt the user for passwords */ + UNIX_TRY_FIRST_PASS, /* take passwords from PAM_AUTHTOK and possibly + PAM_OLDAUTHTOK items, but prompt the user + if the appropriate PAM item is unset */ + UNIX_AUTHTOK_TYPE, /* the type of password to use in prompts */ UNIX__PRELIM, /* internal */ UNIX__UPDATE, /* internal */ @@ -101,12 +91,6 @@ enum { ((_UNIX_BOOLS - 1) / _INT_BITS + 1) enum { - USE_NONE = 0, /* ask for password via the conv function */ - USE_TRY, /* try to get password(s) from PAM_*AUTHTOK */ - USE_FORCED /* get password(s) from PAM_*AUTHTOK or fail */ -}; - -enum { WRITE_PASSWD = 0, /* write changed password to /etc/passwd */ WRITE_SHADOW, /* write changed password to /etc/shadow */ WRITE_TCB /* write changed password to /etc/tcb/ */ @@ -119,7 +103,6 @@ struct cmdline_opts { struct pam_unix_params { unsigned int ctrl[OPT_SIZE]; - int authtok_usage; int write_to; const unsigned char *crypt_prefix; const unsigned char *helper; @@ -182,9 +165,6 @@ extern int _unix_fork(pam_handle_t *, cb_func, const void *); extern int _set_ctrl(pam_handle_t *, int flags, int argc, const char **argv); extern int _unix_blankpasswd(pam_handle_t *, const char *user); extern int _unix_verify_password(pam_handle_t *, const char *, const char *); -extern int _unix_read_password(pam_handle_t *, const char *comment, - const char *prompt1, const char *prompt2, const char *data_name, - const char **pass); extern int unix_getspnam(struct spwd **, const struct passwd *); extern char *crypt_wrapper(pam_handle_t *, const char *, const char *); extern char *do_crypt(pam_handle_t *, const char *); -- ldv
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.