|
|
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.