!15 fix issue: "Current password:" is repeated twice when executing the passwd command as a normal user and the input password is wrong.

From: @panxh_purple
Reviewed-by: @zhujianwei001
Signed-off-by: @zhujianwei001
This commit is contained in:
openeuler-ci-bot 2020-09-25 22:57:57 +08:00 committed by Gitee
commit 1ac303200d
4 changed files with 391 additions and 1 deletions

View File

@ -0,0 +1,276 @@
From c9593778a6133bf29eb2f47c24cc6d2f5d729fc8 Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
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 <fontaine.fabrice@gmail.com>
* modules/pam_localuser/pam_localuser.c: Include
<security/pam_modutil.h>.
(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 <ldv@altlinux.org>
---
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 <security/_pam_types.h>
+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 <security/pam_ext.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+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 <unistd.h>
#include <security/pam_modules.h>
+#include <security/pam_modutil.h>
#include <security/pam_ext.h>
#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

View File

@ -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 <panxiaohe@huawei.com> - 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 <lirui130@huawei.com> - 1.4.0-1
- update to 1.4.0

View File

@ -0,0 +1,76 @@
From 0adbaeb273da1d45213134aa271e95987103281c Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
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 <fontaine.fabrice@gmail.com>
---
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

View File

@ -0,0 +1,30 @@
From efd2a79c11982d0feebebbf740506c9555120b97 Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
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