From cc494428b0984194d11b047732728a65891ce5d5 Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Fri, 26 Jan 2024 08:48:08 +0100 Subject: [PATCH] - libpam: use getlogin() from libc and not utmp - pam_access: handle hostnames in access.conf Resolves: RHEL-16727 Resolves: RHEL-22300 Signed-off-by: Iker Pedrosa --- pam-1-5-1-libpam-getlogin.patch | 144 ++++++++++++++++++++ pam-1.5.1-access-handle-hostnames.patch | 168 ++++++++++++++++++++++++ pam.spec | 13 +- 3 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 pam-1-5-1-libpam-getlogin.patch create mode 100644 pam-1.5.1-access-handle-hostnames.patch diff --git a/pam-1-5-1-libpam-getlogin.patch b/pam-1-5-1-libpam-getlogin.patch new file mode 100644 index 0000000..a644b94 --- /dev/null +++ b/pam-1-5-1-libpam-getlogin.patch @@ -0,0 +1,144 @@ +From 244b46908df930626535c0cd7c2867407fe8714a Mon Sep 17 00:00:00 2001 +From: Thorsten Kukuk +Date: Tue, 14 Feb 2023 14:57:40 +0100 +Subject: [PATCH] libpam: use getlogin() from libc and not utmp + + utmp uses 32bit time_t for compatibility with 32bit userland on some + 64bit systems and is thus not Y2038 safe. Use getlogin() from libc + which avoids using utmp and is more safe than the old utmp-based + implementation by using /proc/self/loginuid. + + * libpam/pam_modutil_getlogin.c: Use getlogin() instead of parsing utmp +--- + libpam/pam_modutil_getlogin.c | 52 ++++++++--------------------------- + 1 file changed, 11 insertions(+), 41 deletions(-) + +diff --git a/libpam/pam_modutil_getlogin.c b/libpam/pam_modutil_getlogin.c +index 04a20fd8..633dd676 100644 +--- a/libpam/pam_modutil_getlogin.c ++++ b/libpam/pam_modutil_getlogin.c +@@ -10,7 +10,6 @@ + + #include + #include +-#include + + #define _PAMMODUTIL_GETLOGIN "_pammodutil_getlogin" + +@@ -19,62 +18,33 @@ pam_modutil_getlogin(pam_handle_t *pamh) + { + int status; + const void *logname; +- const void *void_curr_tty; +- const char *curr_tty; + char *curr_user; +- struct utmp *ut, line; ++ size_t curr_user_len; + + status = pam_get_data(pamh, _PAMMODUTIL_GETLOGIN, &logname); + if (status == PAM_SUCCESS) { + return logname; + } + +- status = pam_get_item(pamh, PAM_TTY, &void_curr_tty); +- if ((status != PAM_SUCCESS) || (void_curr_tty == NULL)) +- curr_tty = ttyname(0); +- else +- curr_tty = (const char*)void_curr_tty; +- +- if (curr_tty == NULL) { +- return NULL; +- } +- +- if (curr_tty[0] == '/') { /* full path */ +- const char *t; +- curr_tty++; +- if ((t = strchr(curr_tty, '/')) != NULL) { +- curr_tty = t + 1; +- } ++ logname = getlogin(); ++ if (logname == NULL) { ++ return NULL; + } +- logname = NULL; + +- setutent(); +- strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); +- +- if ((ut = getutline(&line)) == NULL) { +- goto clean_up_and_go_home; +- } +- +- curr_user = calloc(sizeof(line.ut_user)+1, 1); ++ curr_user_len = strlen(logname)+1; ++ curr_user = calloc(curr_user_len, 1); + if (curr_user == NULL) { +- goto clean_up_and_go_home; ++ return NULL; + } + +- strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); +- /* calloc already zeroed the memory */ ++ memcpy(curr_user, logname, curr_user_len); + + status = pam_set_data(pamh, _PAMMODUTIL_GETLOGIN, curr_user, + pam_modutil_cleanup); + if (status != PAM_SUCCESS) { +- free(curr_user); +- goto clean_up_and_go_home; ++ free(curr_user); ++ return NULL; + } + +- logname = curr_user; +- +-clean_up_and_go_home: +- +- endutent(); +- +- return logname; ++ return curr_user; + } +-- +2.43.0 + +From f26d873435be9f35fa7953493cc07a9bc4e31876 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= +Date: Sat, 18 Feb 2023 14:37:04 +0100 +Subject: [PATCH] libpam: simplify string copying using strdup + +--- + libpam/pam_modutil_getlogin.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/libpam/pam_modutil_getlogin.c b/libpam/pam_modutil_getlogin.c +index 633dd676..2e7a0116 100644 +--- a/libpam/pam_modutil_getlogin.c ++++ b/libpam/pam_modutil_getlogin.c +@@ -19,7 +19,6 @@ pam_modutil_getlogin(pam_handle_t *pamh) + int status; + const void *logname; + char *curr_user; +- size_t curr_user_len; + + status = pam_get_data(pamh, _PAMMODUTIL_GETLOGIN, &logname); + if (status == PAM_SUCCESS) { +@@ -31,14 +30,11 @@ pam_modutil_getlogin(pam_handle_t *pamh) + return NULL; + } + +- curr_user_len = strlen(logname)+1; +- curr_user = calloc(curr_user_len, 1); ++ curr_user = strdup(logname); + if (curr_user == NULL) { + return NULL; + } + +- memcpy(curr_user, logname, curr_user_len); +- + status = pam_set_data(pamh, _PAMMODUTIL_GETLOGIN, curr_user, + pam_modutil_cleanup); + if (status != PAM_SUCCESS) { +-- +2.43.0 + diff --git a/pam-1.5.1-access-handle-hostnames.patch b/pam-1.5.1-access-handle-hostnames.patch new file mode 100644 index 0000000..8cd9e8e --- /dev/null +++ b/pam-1.5.1-access-handle-hostnames.patch @@ -0,0 +1,168 @@ +diff -up Linux-PAM-1.5.1/modules/pam_access/pam_access.c.access-handle-hostnames Linux-PAM-1.5.1/modules/pam_access/pam_access.c +--- Linux-PAM-1.5.1/modules/pam_access/pam_access.c.access-handle-hostnames 2020-11-25 17:57:02.000000000 +0100 ++++ Linux-PAM-1.5.1/modules/pam_access/pam_access.c 2024-01-22 15:56:09.977868880 +0100 +@@ -662,7 +662,7 @@ from_match (pam_handle_t *pamh UNUSED, c + } + } + } else { +- /* Assume network/netmask with a IP of a host. */ ++ /* Assume network/netmask, IP address or hostname. */ + if (network_netmask_match(pamh, tok, string, item)) + return YES; + } +@@ -684,7 +684,7 @@ string_match (pam_handle_t *pamh, const + /* + * If the token has the magic value "ALL" the match always succeeds. + * Otherwise, return YES if the token fully matches the string. +- * "NONE" token matches NULL string. ++ * "NONE" token matches NULL string. + */ + + if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ +@@ -702,7 +702,8 @@ string_match (pam_handle_t *pamh, const + + /* network_netmask_match - match a string against one token + * where string is a hostname or ip (v4,v6) address and tok +- * represents either a single ip (v4,v6) address or a network/netmask ++ * represents either a hostname, a single ip (v4,v6) address ++ * or a network/netmask + */ + static int + network_netmask_match (pam_handle_t *pamh, +@@ -711,10 +712,12 @@ network_netmask_match (pam_handle_t *pam + char *netmask_ptr; + char netmask_string[MAXHOSTNAMELEN + 1]; + int addr_type; ++ struct addrinfo *ai = NULL; + + if (item->debug) +- pam_syslog (pamh, LOG_DEBUG, ++ pam_syslog (pamh, LOG_DEBUG, + "network_netmask_match: tok=%s, item=%s", tok, string); ++ + /* OK, check if tok is of type addr/mask */ + if ((netmask_ptr = strchr(tok, '/')) != NULL) + { +@@ -748,54 +751,108 @@ network_netmask_match (pam_handle_t *pam + netmask_ptr = number_to_netmask(netmask, addr_type, + netmask_string, MAXHOSTNAMELEN); + } +- } ++ ++ /* ++ * Construct an addrinfo list from the IP address. ++ * This should not fail as the input is a correct IP address... ++ */ ++ if (getaddrinfo (tok, NULL, NULL, &ai) != 0) ++ { ++ return NO; ++ } ++ } + else +- /* NO, then check if it is only an addr */ +- if (isipaddr(tok, NULL, NULL) != YES) ++ { ++ /* ++ * It is either an IP address or a hostname. ++ * Let getaddrinfo sort everything out ++ */ ++ if (getaddrinfo (tok, NULL, NULL, &ai) != 0) + { ++ pam_syslog(pamh, LOG_ERR, "cannot resolve hostname \"%s\"", tok); ++ + return NO; + } ++ netmask_ptr = NULL; ++ } + + if (isipaddr(string, NULL, NULL) != YES) + { +- /* Assume network/netmask with a name of a host. */ + struct addrinfo hint; + ++ /* Assume network/netmask with a name of a host. */ + memset (&hint, '\0', sizeof (hint)); + hint.ai_flags = AI_CANONNAME; + hint.ai_family = AF_UNSPEC; + + if (item->gai_rv != 0) ++ { ++ freeaddrinfo(ai); + return NO; ++ } + else if (!item->res && + (item->gai_rv = getaddrinfo (string, NULL, &hint, &item->res)) != 0) ++ { ++ freeaddrinfo(ai); + return NO; ++ } + else + { + struct addrinfo *runp = item->res; ++ struct addrinfo *runp1; + + while (runp != NULL) + { + char buf[INET6_ADDRSTRLEN]; + +- DIAG_PUSH_IGNORE_CAST_ALIGN; +- inet_ntop (runp->ai_family, +- runp->ai_family == AF_INET +- ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr +- : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr, +- buf, sizeof (buf)); +- DIAG_POP_IGNORE_CAST_ALIGN; ++ if (getnameinfo (runp->ai_addr, runp->ai_addrlen, buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) != 0) ++ { ++ freeaddrinfo(ai); ++ return NO; ++ } + +- if (are_addresses_equal(buf, tok, netmask_ptr)) ++ for (runp1 = ai; runp1 != NULL; runp1 = runp1->ai_next) + { +- return YES; ++ char buf1[INET6_ADDRSTRLEN]; ++ ++ if (runp->ai_family != runp1->ai_family) ++ continue; ++ ++ if (getnameinfo (runp1->ai_addr, runp1->ai_addrlen, buf1, sizeof (buf1), NULL, 0, NI_NUMERICHOST) != 0) ++ { ++ freeaddrinfo(ai); ++ return NO; ++ } ++ ++ if (are_addresses_equal (buf, buf1, netmask_ptr)) ++ { ++ freeaddrinfo(ai); ++ return YES; ++ } + } + runp = runp->ai_next; + } + } + } + else +- return (are_addresses_equal(string, tok, netmask_ptr)); ++ { ++ struct addrinfo *runp1; ++ ++ for (runp1 = ai; runp1 != NULL; runp1 = runp1->ai_next) ++ { ++ char buf1[INET6_ADDRSTRLEN]; ++ ++ (void) getnameinfo (runp1->ai_addr, runp1->ai_addrlen, buf1, sizeof (buf1), NULL, 0, NI_NUMERICHOST); ++ ++ if (are_addresses_equal(string, buf1, netmask_ptr)) ++ { ++ freeaddrinfo(ai); ++ return YES; ++ } ++ } ++ } ++ ++ freeaddrinfo(ai); + + return NO; + } diff --git a/pam.spec b/pam.spec index 16b7c00..615155a 100644 --- a/pam.spec +++ b/pam.spec @@ -3,7 +3,7 @@ Summary: An extensible library which provides authentication for applications Name: pam Version: 1.5.1 -Release: 17%{?dist} +Release: 18%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ # - this option is redundant as the BSD license allows that anyway. # pam_timestamp, pam_loginuid, and pam_console modules are GPLv2+. @@ -58,6 +58,11 @@ Patch15: pam-1.5.1-libpam-close-range.patch Patch16: pam-1.5.1-audit-messages-formatting.patch # https://github.com/linux-pam/linux-pam/commit/d54870f993e97fe75e2cd0470a3701d5af22877c Patch17: pam-1.5.1-faillock-create-tallydir.patch +# https://github.com/linux-pam/linux-pam/commit/244b46908df930626535c0cd7c2867407fe8714a +# https://github.com/linux-pam/linux-pam/commit/f26d873435be9f35fa7953493cc07a9bc4e31876 +Patch18: pam-1-5-1-libpam-getlogin.patch +# https://github.com/linux-pam/linux-pam/commit/23393bef92c1e768eda329813d7af55481c6ca9f +Patch19: pam-1.5.1-access-handle-hostnames.patch %global _pamlibdir %{_libdir} %global _moduledir %{_libdir}/security @@ -157,6 +162,8 @@ cp %{SOURCE18} . %patch15 -p1 -b .libpam-close-range %patch16 -p1 -b .audit-messages-formatting %patch17 -p1 -b .faillock-create-tallydir +%patch18 -p1 -b .libpam-getlogin +%patch19 -p1 -b .access-handle-hostnames autoreconf -i @@ -412,6 +419,10 @@ done %doc doc/sag/*.txt doc/sag/html %changelog +* Fri Jan 26 2024 Iker Pedrosa - 1.3.1-18 +- libpam: use getlogin() from libc and not utmp. Resolves: RHEL-16727 +- pam_access: handle hostnames in access.conf. Resolves: RHEL-22300 + * Mon Jan 8 2024 Iker Pedrosa - 1.5.1-17 - pam_faillock: create tallydir before creating tallyfile. Resolves: RHEL-20943