From 295bf7403364b23ab03287ecdd95ea266d6f4d89 Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Thu, 11 Jun 2020 17:39:03 +0200 Subject: [PATCH] fix build on musl Rename check_user_in_passwd from pam_localuser.c to pam_modutil_check_user_in_passwd and use it in pam_faillock.c instead of fgetpwent_r which is not available on musl Fix #236 Fixes: - http://autobuild.buildroot.org/results/0432736ffee376dd84757469434a4bbcfdcdaf4b Signed-off-by: Fabrice Fontaine [Upstream status: https://github.com/linux-pam/linux-pam/pull/237] --- libpam/Makefile.am | 1 + libpam/include/security/pam_modutil.h | 5 ++ libpam/libpam.map | 5 ++ libpam/pam_modutil_check_user_in_passwd.c | 89 +++++++++++++++++++++++ modules/pam_faillock/pam_faillock.c | 37 +--------- modules/pam_localuser/pam_localuser.c | 86 +--------------------- 6 files changed, 103 insertions(+), 120 deletions(-) create mode 100644 libpam/pam_modutil_check_user_in_passwd.c diff --git a/libpam/Makefile.am b/libpam/Makefile.am index 9252a837..a8fc428d 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_in_passwd.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 3a6aec6a..33f87b90 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 c9690a91..3cc7ef35 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_in_passwd.c b/libpam/pam_modutil_check_user_in_passwd.c new file mode 100644 index 00000000..b998aa25 --- /dev/null +++ b/libpam/pam_modutil_check_user_in_passwd.c @@ -0,0 +1,89 @@ +#include "pam_modutil_private.h" +#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_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c index f592d0a2..8bca46ca 100644 --- a/modules/pam_faillock/pam_faillock.c +++ b/modules/pam_faillock/pam_faillock.c @@ -348,42 +348,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); } static int diff --git a/modules/pam_localuser/pam_localuser.c b/modules/pam_localuser/pam_localuser.c index cb507524..a9f2233c 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 -- 2.26.2