From 46f4cdd560282caa4bc496835d04fa0a743dd47a Mon Sep 17 00:00:00 2001 From: panxiaohe Date: Fri, 25 Sep 2020 20:11:13 +0800 Subject: [PATCH] fix the following issue:"Current password:" is repeated twice when executing the passwd command as a normal user and the input password is wrong. --- ...in_passwd-from-pam_localuser.c-to-pa.patch | 276 ++++++++++++++++++ pam.spec | 10 +- pam_faillock-fix-build-on-musl.patch | 76 +++++ ...k_user_in_passwd-avoid-timing-attack.patch | 30 ++ 4 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 Move-check_user_in_passwd-from-pam_localuser.c-to-pa.patch create mode 100644 pam_faillock-fix-build-on-musl.patch create mode 100644 pam_modutil_check_user_in_passwd-avoid-timing-attack.patch diff --git a/Move-check_user_in_passwd-from-pam_localuser.c-to-pa.patch b/Move-check_user_in_passwd-from-pam_localuser.c-to-pa.patch new file mode 100644 index 0000000..86a6642 --- /dev/null +++ b/Move-check_user_in_passwd-from-pam_localuser.c-to-pa.patch @@ -0,0 +1,276 @@ +From c9593778a6133bf29eb2f47c24cc6d2f5d729fc8 Mon Sep 17 00:00:00 2001 +From: Fabrice Fontaine +Date: Thu, 11 Jun 2020 17:39:03 +0200 +Subject: [PATCH] Move check_user_in_passwd from pam_localuser.c to pam_modutil + +Signed-off-by: Fabrice Fontaine + +* modules/pam_localuser/pam_localuser.c: Include +. +(pam_sm_authenticate): Replace check_user_in_passwd with +pam_modutil_check_user_in_passwd. +(check_user_in_passwd): Rename to pam_modutil_check_user_in_passwd, +move to ... +* libpam/pam_modutil_check_user.c: ... new file. +* libpam/Makefile.am (libpam_la_SOURCES): Add pam_modutil_check_user.c. +* libpam/include/security/pam_modutil.h +(pam_modutil_check_user_in_passwd): New function declaration. +* libpam/libpam.map (LIBPAM_MODUTIL_1.4.1): New interface. + +Co-authored-by: Dmitry V. Levin +--- + libpam/Makefile.am | 1 + + libpam/include/security/pam_modutil.h | 5 ++ + libpam/libpam.map | 5 ++ + libpam/pam_modutil_check_user.c | 90 +++++++++++++++++++++++++++++++++++ + modules/pam_localuser/pam_localuser.c | 86 +-------------------------------- + 5 files changed, 103 insertions(+), 84 deletions(-) + create mode 100644 libpam/pam_modutil_check_user.c + +diff --git a/libpam/Makefile.am b/libpam/Makefile.am +index 9252a83..11a1f32 100644 +--- a/libpam/Makefile.am ++++ b/libpam/Makefile.am +@@ -35,6 +35,7 @@ libpam_la_SOURCES = pam_account.c pam_auth.c pam_data.c pam_delay.c \ + pam_misc.c pam_password.c pam_prelude.c \ + pam_session.c pam_start.c pam_strerror.c \ + pam_vprompt.c pam_syslog.c pam_dynamic.c pam_audit.c \ ++ pam_modutil_check_user.c \ + pam_modutil_cleanup.c pam_modutil_getpwnam.c pam_modutil_ioloop.c \ + pam_modutil_getgrgid.c pam_modutil_getpwuid.c pam_modutil_getgrnam.c \ + pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c \ +diff --git a/libpam/include/security/pam_modutil.h b/libpam/include/security/pam_modutil.h +index 3a6aec6..33f87b9 100644 +--- a/libpam/include/security/pam_modutil.h ++++ b/libpam/include/security/pam_modutil.h +@@ -58,6 +58,11 @@ extern "C" { + + #include + ++extern int PAM_NONNULL((1,2)) ++pam_modutil_check_user_in_passwd(pam_handle_t *pamh, ++ const char *user_name, ++ const char *file_name); ++ + extern struct passwd * PAM_NONNULL((1,2)) + pam_modutil_getpwnam(pam_handle_t *pamh, const char *user); + +diff --git a/libpam/libpam.map b/libpam/libpam.map +index c9690a9..3cc7ef3 100644 +--- a/libpam/libpam.map ++++ b/libpam/libpam.map +@@ -82,3 +82,8 @@ LIBPAM_1.4 { + global: + pam_start_confdir; + } LIBPAM_1.0; ++ ++LIBPAM_MODUTIL_1.4.1 { ++ global: ++ pam_modutil_check_user_in_passwd; ++} LIBPAM_MODUTIL_1.3.2; +diff --git a/libpam/pam_modutil_check_user.c b/libpam/pam_modutil_check_user.c +new file mode 100644 +index 0000000..898b13a +--- /dev/null ++++ b/libpam/pam_modutil_check_user.c +@@ -0,0 +1,90 @@ ++#include "pam_modutil_private.h" ++#include ++ ++#include ++#include ++#include ++ ++int ++pam_modutil_check_user_in_passwd(pam_handle_t *pamh, ++ const char *user_name, ++ const char *file_name) ++{ ++ int rc; ++ size_t user_len; ++ FILE *fp; ++ char line[BUFSIZ]; ++ ++ /* Validate the user name. */ ++ if ((user_len = strlen(user_name)) == 0) { ++ pam_syslog(pamh, LOG_NOTICE, "user name is not valid"); ++ return PAM_SERVICE_ERR; ++ } ++ ++ if (user_len > sizeof(line) - sizeof(":")) { ++ pam_syslog(pamh, LOG_NOTICE, "user name is too long"); ++ return PAM_SERVICE_ERR; ++ } ++ ++ if (strchr(user_name, ':') != NULL) { ++ /* ++ * "root:x" is not a local user name even if the passwd file ++ * contains a line starting with "root:x:". ++ */ ++ return PAM_PERM_DENIED; ++ } ++ ++ /* Open the passwd file. */ ++ if (file_name == NULL) { ++ file_name = "/etc/passwd"; ++ } ++ if ((fp = fopen(file_name, "r")) == NULL) { ++ pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name); ++ return PAM_SERVICE_ERR; ++ } ++ ++ /* ++ * Scan the file using fgets() instead of fgetpwent_r() because ++ * the latter is not flexible enough in handling long lines ++ * in passwd files. ++ */ ++ rc = PAM_PERM_DENIED; ++ while (fgets(line, sizeof(line), fp) != NULL) { ++ size_t line_len; ++ const char *str; ++ ++ /* ++ * Does this line start with the user name ++ * followed by a colon? ++ */ ++ if (strncmp(user_name, line, user_len) == 0 && ++ line[user_len] == ':') { ++ rc = PAM_SUCCESS; ++ break; ++ } ++ /* Has a newline been read? */ ++ line_len = strlen(line); ++ if (line_len < sizeof(line) - 1 || ++ line[line_len - 1] == '\n') { ++ /* Yes, continue with the next line. */ ++ continue; ++ } ++ ++ /* No, read till the end of this line first. */ ++ while ((str = fgets(line, sizeof(line), fp)) != NULL) { ++ line_len = strlen(line); ++ if (line_len == 0 || ++ line[line_len - 1] == '\n') { ++ break; ++ } ++ } ++ if (str == NULL) { ++ /* fgets returned NULL, we are done. */ ++ break; ++ } ++ /* Continue with the next line. */ ++ } ++ ++ fclose(fp); ++ return rc; ++} +diff --git a/modules/pam_localuser/pam_localuser.c b/modules/pam_localuser/pam_localuser.c +index cb50752..a9f2233 100644 +--- a/modules/pam_localuser/pam_localuser.c ++++ b/modules/pam_localuser/pam_localuser.c +@@ -45,92 +45,10 @@ + #include + + #include ++#include + #include + #include "pam_inline.h" + +-static int +-check_user_in_passwd(pam_handle_t *pamh, const char *user_name, +- const char *file_name) +-{ +- int rc; +- size_t user_len; +- FILE *fp; +- char line[BUFSIZ]; +- +- /* Validate the user name. */ +- if ((user_len = strlen(user_name)) == 0) { +- pam_syslog(pamh, LOG_NOTICE, "user name is not valid"); +- return PAM_SERVICE_ERR; +- } +- +- if (user_len > sizeof(line) - sizeof(":")) { +- pam_syslog(pamh, LOG_NOTICE, "user name is too long"); +- return PAM_SERVICE_ERR; +- } +- +- if (strchr(user_name, ':') != NULL) { +- /* +- * "root:x" is not a local user name even if the passwd file +- * contains a line starting with "root:x:". +- */ +- return PAM_PERM_DENIED; +- } +- +- /* Open the passwd file. */ +- if (file_name == NULL) { +- file_name = "/etc/passwd"; +- } +- if ((fp = fopen(file_name, "r")) == NULL) { +- pam_syslog(pamh, LOG_ERR, "error opening %s: %m", file_name); +- return PAM_SERVICE_ERR; +- } +- +- /* +- * Scan the file using fgets() instead of fgetpwent_r() because +- * the latter is not flexible enough in handling long lines +- * in passwd files. +- */ +- rc = PAM_PERM_DENIED; +- while (fgets(line, sizeof(line), fp) != NULL) { +- size_t line_len; +- const char *str; +- +- /* +- * Does this line start with the user name +- * followed by a colon? +- */ +- if (strncmp(user_name, line, user_len) == 0 && +- line[user_len] == ':') { +- rc = PAM_SUCCESS; +- break; +- } +- /* Has a newline been read? */ +- line_len = strlen(line); +- if (line_len < sizeof(line) - 1 || +- line[line_len - 1] == '\n') { +- /* Yes, continue with the next line. */ +- continue; +- } +- +- /* No, read till the end of this line first. */ +- while ((str = fgets(line, sizeof(line), fp)) != NULL) { +- line_len = strlen(line); +- if (line_len == 0 || +- line[line_len - 1] == '\n') { +- break; +- } +- } +- if (str == NULL) { +- /* fgets returned NULL, we are done. */ +- break; +- } +- /* Continue with the next line. */ +- } +- +- fclose(fp); +- return rc; +-} +- + int + pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +@@ -173,7 +91,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, + return rc == PAM_CONV_AGAIN ? PAM_INCOMPLETE : rc; + } + +- return check_user_in_passwd(pamh, user_name, file_name); ++ return pam_modutil_check_user_in_passwd(pamh, user_name, file_name); + } + + int +-- +1.8.3.1 + diff --git a/pam.spec b/pam.spec index b7df54e..ab17104 100644 --- a/pam.spec +++ b/pam.spec @@ -4,7 +4,7 @@ %define _pamconfdir %{_sysconfdir}/pam.d Name: pam Version: 1.4.0 -Release: 1 +Release: 2 Summary: Pluggable Authentication Modules for Linux License: BSD and GPLv2+ URL: http://www.linux-pam.org/ @@ -21,6 +21,9 @@ Source18: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt Patch0: bugfix-pam-1.1.8-faillock-failmessages.patch Patch1: bugfix-pam-1.1.8-faillock-systemtime.patch Patch2: fix-login-message.patch +Patch3: Move-check_user_in_passwd-from-pam_localuser.c-to-pa.patch +Patch4: pam_faillock-fix-build-on-musl.patch +Patch5: pam_modutil_check_user_in_passwd-avoid-timing-attack.patch BuildRequires: autoconf automake libtool bison flex sed cracklib-devel BuildRequires: perl-interpreter pkgconfig gettext-devel libtirpc-devel libnsl2-devel @@ -166,6 +169,11 @@ fi %changelog +* Fri Sep 25 2020 panxiaohe - 1.4.0-2 +- fix the following issue. + "Current password:" is repeated twice when executing the passwd + command as a normal user and the input password is wrong. + * Fri Jul 24 2020 Liquor - 1.4.0-1 - update to 1.4.0 diff --git a/pam_faillock-fix-build-on-musl.patch b/pam_faillock-fix-build-on-musl.patch new file mode 100644 index 0000000..da51666 --- /dev/null +++ b/pam_faillock-fix-build-on-musl.patch @@ -0,0 +1,76 @@ +From 0adbaeb273da1d45213134aa271e95987103281c Mon Sep 17 00:00:00 2001 +From: Fabrice Fontaine +Date: Thu, 11 Jun 2020 17:39:03 +0200 +Subject: [PATCH] pam_faillock: fix build on musl + +Use pam_modutil_check_user_in_passwd in pam_faillock.c instead of +fgetpwent_r which is not available on musl. + +Resolves: https://github.com/linux-pam/linux-pam/issues/236 +Resolves: https://github.com/linux-pam/linux-pam/pull/237 +Fixes: http://autobuild.buildroot.org/results/0432736ffee376dd84757469434a4bbcfdcdaf4b +Signed-off-by: Fabrice Fontaine +--- + modules/pam_faillock/pam_faillock.c | 39 +------------------------------------ + 1 file changed, 1 insertion(+), 38 deletions(-) + +diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c +index f592d0a..71988d0 100644 +--- a/modules/pam_faillock/pam_faillock.c ++++ b/modules/pam_faillock/pam_faillock.c +@@ -71,8 +71,6 @@ + #define MAX_TIME_INTERVAL 604800 /* 7 days */ + #define FAILLOCK_CONF_MAX_LINELEN 1023 + +-#define PATH_PASSWD "/etc/passwd" +- + static const char default_faillock_conf[] = FAILLOCK_DEFAULT_CONF; + + struct options { +@@ -348,42 +346,7 @@ set_conf_opt(pam_handle_t *pamh, struct options *opts, const char *name, const c + static int + check_local_user (pam_handle_t *pamh, const char *user) + { +- struct passwd pw, *pwp; +- char buf[16384]; +- int found = 0; +- FILE *fp; +- int errn; +- +- fp = fopen(PATH_PASSWD, "r"); +- if (fp == NULL) { +- pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", +- PATH_PASSWD); +- return -1; +- } +- +- for (;;) { +- errn = fgetpwent_r(fp, &pw, buf, sizeof (buf), &pwp); +- if (errn == ERANGE) { +- pam_syslog(pamh, LOG_WARNING, "%s contains very long lines; corrupted?", +- PATH_PASSWD); +- break; +- } +- if (errn != 0) +- break; +- if (strcmp(pwp->pw_name, user) == 0) { +- found = 1; +- break; +- } +- } +- +- fclose (fp); +- +- if (errn != 0 && errn != ENOENT) { +- pam_syslog(pamh, LOG_ERR, "unable to enumerate local accounts: %m"); +- return -1; +- } else { +- return found; +- } ++ return pam_modutil_check_user_in_passwd(pamh, user, NULL) == PAM_SUCCESS; + } + + static int +-- +1.8.3.1 + diff --git a/pam_modutil_check_user_in_passwd-avoid-timing-attack.patch b/pam_modutil_check_user_in_passwd-avoid-timing-attack.patch new file mode 100644 index 0000000..f92054e --- /dev/null +++ b/pam_modutil_check_user_in_passwd-avoid-timing-attack.patch @@ -0,0 +1,30 @@ +From efd2a79c11982d0feebebbf740506c9555120b97 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Tue, 16 Jun 2020 15:00:00 +0000 +Subject: [PATCH] pam_modutil_check_user_in_passwd: avoid timing attacks + +* libpam/pam_modutil_check_user.c (pam_modutil_check_user_in_passwd): Do +not exit the file reading loop when the user is found, continue reading +the file to avoid timing attacks. +--- + libpam/pam_modutil_check_user.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libpam/pam_modutil_check_user.c b/libpam/pam_modutil_check_user.c +index 898b13a..cf1bd1b 100644 +--- a/libpam/pam_modutil_check_user.c ++++ b/libpam/pam_modutil_check_user.c +@@ -60,7 +60,9 @@ pam_modutil_check_user_in_passwd(pam_handle_t *pamh, + if (strncmp(user_name, line, user_len) == 0 && + line[user_len] == ':') { + rc = PAM_SUCCESS; +- break; ++ /* ++ * Continue reading the file to avoid timing attacks. ++ */ + } + /* Has a newline been read? */ + line_len = strlen(line); +-- +1.8.3.1 + -- Gitee