summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-extended/pam
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-extended/pam')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/0001-run-xtests.sh-check-whether-files-exist.patch65
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/99_pam1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/CVE-2022-28321-0002.patch205
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.sh48
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/faillock.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/libpam-xtests.patch37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam-volatiles.conf1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-account27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-auth26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-password27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session-noninteractive19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/other24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/run-ptest32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend74
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_1.5.2.bb186
17 files changed, 800 insertions, 3 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/0001-run-xtests.sh-check-whether-files-exist.patch b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/0001-run-xtests.sh-check-whether-files-exist.patch
new file mode 100644
index 000000000..40040a873
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/0001-run-xtests.sh-check-whether-files-exist.patch
@@ -0,0 +1,65 @@
+From e8e8ccfd57e0274b431bc5717bf37c488285b07b Mon Sep 17 00:00:00 2001
+From: Mingli Yu <mingli.yu@windriver.com>
+Date: Wed, 27 Oct 2021 10:30:46 +0800
+Subject: [PATCH] run-xtests.sh: check whether files exist
+
+Fixes:
+ # ./run-xtests.sh . tst-pam_access1
+ mv: cannot stat '/etc/security/opasswd': No such file or directory
+ PASS: tst-pam_access1
+ mv: cannot stat '/etc/security/opasswd-pam-xtests': No such file or directory
+ ==================
+ 1 tests passed
+ 0 tests not run
+ ==================
+
+Upstream-Status: Backport [https://github.com/linux-pam/linux-pam/commit/e8e8ccfd57e0274b431bc5717bf37c488285b07b]
+
+Signed-off-by: Mingli Yu <mingli.yu@windriver.com>
+---
+ xtests/run-xtests.sh | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/xtests/run-xtests.sh b/xtests/run-xtests.sh
+index 14f585d9..ff9a4dc1 100755
+--- a/xtests/run-xtests.sh
++++ b/xtests/run-xtests.sh
+@@ -18,10 +18,12 @@ all=0
+
+ mkdir -p /etc/security
+ for config in access.conf group.conf time.conf limits.conf ; do
+- cp /etc/security/$config /etc/security/$config-pam-xtests
++ [ -f "/etc/security/$config" ] &&
++ mv /etc/security/$config /etc/security/$config-pam-xtests
+ install -m 644 "${SRCDIR}"/$config /etc/security/$config
+ done
+-mv /etc/security/opasswd /etc/security/opasswd-pam-xtests
++[ -f /etc/security/opasswd ] &&
++ mv /etc/security/opasswd /etc/security/opasswd-pam-xtests
+
+ for testname in $XTESTS ; do
+ for cfg in "${SRCDIR}"/$testname*.pamd ; do
+@@ -47,11 +49,15 @@ for testname in $XTESTS ; do
+ all=`expr $all + 1`
+ rm -f /etc/pam.d/$testname*
+ done
+-mv /etc/security/access.conf-pam-xtests /etc/security/access.conf
+-mv /etc/security/group.conf-pam-xtests /etc/security/group.conf
+-mv /etc/security/time.conf-pam-xtests /etc/security/time.conf
+-mv /etc/security/limits.conf-pam-xtests /etc/security/limits.conf
+-mv /etc/security/opasswd-pam-xtests /etc/security/opasswd
++
++for config in access.conf group.conf time.conf limits.conf opasswd ; do
++ if [ -f "/etc/security/$config-pam-xtests" ]; then
++ mv /etc/security/$config-pam-xtests /etc/security/$config
++ else
++ rm -f /etc/security/$config
++ fi
++done
++
+ if test "$failed" -ne 0; then
+ echo "==================="
+ echo "$failed of $all tests failed"
+--
+2.32.0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/99_pam b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/99_pam
new file mode 100644
index 000000000..a88247be1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/99_pam
@@ -0,0 +1 @@
+d root root 0755 /run/sepermit none
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/CVE-2022-28321-0002.patch b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/CVE-2022-28321-0002.patch
new file mode 100644
index 000000000..e7bf03f9f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/CVE-2022-28321-0002.patch
@@ -0,0 +1,205 @@
+From 23393bef92c1e768eda329813d7af55481c6ca9f Mon Sep 17 00:00:00 2001
+From: Thorsten Kukuk <kukuk@suse.com>
+Date: Thu, 24 Feb 2022 10:37:32 +0100
+Subject: [PATCH 2/2] pam_access: handle hostnames in access.conf
+
+According to the manual page, the following entry is valid but does not
+work:
+-:root:ALL EXCEPT localhost
+
+See https://bugzilla.suse.com/show_bug.cgi?id=1019866
+
+Patched is based on PR#226 from Josef Moellers
+
+Upstream-Status: Backport
+CVE: CVE-2022-28321
+
+Reference to upstream patch:
+[https://github.com/linux-pam/linux-pam/commit/23393bef92c1e768eda329813d7af55481c6ca9f]
+
+Signed-off-by: Stefan Ghinea <stefan.ghinea@windriver.com>
+---
+ modules/pam_access/pam_access.c | 95 ++++++++++++++++++++++++++-------
+ 1 file changed, 76 insertions(+), 19 deletions(-)
+
+diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c
+index 277192b..bca424f 100644
+--- a/modules/pam_access/pam_access.c
++++ b/modules/pam_access/pam_access.c
+@@ -637,7 +637,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item)
+ if ((str_len = strlen(string)) > tok_len
+ && strcasecmp(tok, string + str_len - tok_len) == 0)
+ return YES;
+- } else if (tok[tok_len - 1] == '.') {
++ } else if (tok[tok_len - 1] == '.') { /* internet network numbers (end with ".") */
+ struct addrinfo hint;
+
+ memset (&hint, '\0', sizeof (hint));
+@@ -678,7 +678,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item)
+ return NO;
+ }
+
+- /* Assume network/netmask with an IP of a host. */
++ /* Assume network/netmask, IP address or hostname. */
+ return network_netmask_match(pamh, tok, string, item);
+ }
+
+@@ -696,7 +696,7 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
+ /*
+ * 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 */
+@@ -714,7 +714,8 @@ string_match (pam_handle_t *pamh, const char *tok, const char *string,
+
+ /* 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,
+@@ -723,10 +724,12 @@ network_netmask_match (pam_handle_t *pamh,
+ 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)
+ {
+@@ -760,54 +763,108 @@ network_netmask_match (pam_handle_t *pamh,
+ 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;
+ }
+--
+2.37.3
+
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.service b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.service
new file mode 100644
index 000000000..099a5c6e0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Convert PAM config files
+
+[Service]
+RemainAfterExit=yes
+Type=oneshot
+ExecStart=/usr/bin/convert-pam-configs.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.sh b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.sh
new file mode 100644
index 000000000..f66f40beb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/convert-pam-configs.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Convert OpenBMC linux-PAM config files
+
+# Location of config files this script modifies:
+# PAM_CONF_DIR - path to the PAM config files
+# SECURITY_CONF_DIR - path to the security config files
+PAM_CONF_DIR=/etc/pam.d
+SECURITY_CONF_DIR=/etc/security
+
+# Handle common-password:
+# Change cracklib to pwquality and handle the minlen parameter
+pam_cracklib=$(grep "^password.*pam_cracklib.so" ${PAM_CONF_DIR}/common-password)
+if [ -n "${pam_cracklib}" ]
+then
+ echo "Changing ${PAM_CONF_DIR}/common-password to use pam_pwquality.so (was pam_cracklib.so)" >&2
+ minlen=$(echo ${pam_cracklib} | sed -e "s/.*minlen=\([[:alnum:]]*\).*/\1/")
+ echo " Converting parameter minlen=${minlen} to ${SECURITY_CONF_DIR}/pwquality.conf minlen" >&2
+ sed -i.bak -e "s/^minlen=.*/minlen=$minlen/" ${SECURITY_CONF_DIR}/pwquality.conf
+ pwquality='password [success=ok default=die] pam_pwquality.so debug'
+ sed -i.bak -e "s/^password.*pam_cracklib.so.*/$pwquality/" ${PAM_CONF_DIR}/common-password
+ echo "# This file was converted by $0" >>${PAM_CONF_DIR}/common-password
+fi
+
+# Handle common-auth:
+# Change tally2 to faillock and handle the deny & unlock_time parameters
+pam_tally2=$(grep "^auth.*pam_tally2.so" ${PAM_CONF_DIR}/common-auth)
+if [ -n "${pam_tally2}" ]
+then
+ echo "Changing ${PAM_CONF_DIR}/common-auth to use pam_faillock.so (was pam_tally2.so)" >&2
+ deny=$(echo ${pam_tally2} | sed -e "s/.*deny=\([[:alnum:]]*\).*/\1/")
+ unlock_time=$(echo ${pam_tally2} | sed -e "s/.*unlock_time=\([[:alnum:]]*\).*/\1/")
+ # Change faillock.conf parameters
+ echo " Converting parameter deny=${deny} to ${SECURITY_CONF_DIR}/faillock.conf deny" >&2
+ echo " Converting parameter unlock_time=${unlock_time} to ${SECURITY_CONF_DIR}/faillock.conf unlock_time" >&2
+ sed -i.bak \
+ -e "s/^deny=.*/deny=$deny/" \
+ -e "s/^unlock_time=.*/unlock_time=$unlock_time/" \
+ ${SECURITY_CONF_DIR}/faillock.conf
+ # Change pam_tally2 to pam_faillock (changes the overall auth stack)
+ authfail='auth [default=die] pam_faillock.so authfail'
+ authsucc='auth sufficient pam_faillock.so authsucc'
+ sed -i.bak \
+ -e "/^auth.*pam_tally2.so.*$/d" \
+ -e "/^auth.*pam_deny.so/i $authfail\n$authsucc" \
+ ${PAM_CONF_DIR}/common-auth
+ echo "# This file was converted by $0" >>${PAM_CONF_DIR}/common-auth
+fi
+
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/faillock.conf b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/faillock.conf
new file mode 100644
index 000000000..68a658411
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/faillock.conf
@@ -0,0 +1,2 @@
+deny=10
+unlock_time=300
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/libpam-xtests.patch b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/libpam-xtests.patch
new file mode 100644
index 000000000..ea145899b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/libpam-xtests.patch
@@ -0,0 +1,37 @@
+This patch is used to create a new sub package libpam-xtests to do more checks.
+
+Upstream-Status: Pending
+
+Signed-off-by: Kang Kai <kai.kang@windriver.com>
+Index: Linux-PAM-1.3.0/xtests/Makefile.am
+===================================================================
+--- Linux-PAM-1.3.0.orig/xtests/Makefile.am
++++ Linux-PAM-1.3.0/xtests/Makefile.am
+@@ -7,7 +7,7 @@ AM_CFLAGS = -DLIBPAM_COMPILE -I$(top_src
+ LDADD = $(top_builddir)/libpam/libpam.la \
+ $(top_builddir)/libpam_misc/libpam_misc.la
+
+-CLEANFILES = *~ $(XTESTS)
++CLEANFILES = *~
+
+ EXTRA_DIST = run-xtests.sh tst-pam_dispatch1.pamd tst-pam_dispatch2.pamd \
+ tst-pam_dispatch3.pamd tst-pam_dispatch4.pamd \
+@@ -51,3 +51,18 @@ EXTRA_PROGRAMS = $(XTESTS)
+
+ xtests: $(XTESTS) run-xtests.sh
+ "$(srcdir)"/run-xtests.sh "$(srcdir)" ${XTESTS} ${NOSRCTESTS}
++
++all: $(XTESTS)
++
++install: install_xtests
++
++install_xtests:
++ $(INSTALL) -d $(DESTDIR)$(pkgdatadir)/xtests
++ for file in $(EXTRA_DIST) ; do \
++ $(INSTALL) $(srcdir)/$$file $(DESTDIR)$(pkgdatadir)/xtests ; \
++ done
++ for file in $(XTESTS); do \
++ $(INSTALL) .libs/$$file $(DESTDIR)$(pkgdatadir)/xtests ; \
++ done
++
++.PHONY: all install_xtests
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam-volatiles.conf b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam-volatiles.conf
new file mode 100644
index 000000000..1263feb03
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam-volatiles.conf
@@ -0,0 +1 @@
+d /run/sepermit 0755 root root - -
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-account b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-account
new file mode 100644
index 000000000..4ebbca8d4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-account
@@ -0,0 +1,27 @@
+#
+# /etc/pam.d/common-account - authorization settings common to all services
+#
+# This file is included from other service-specific PAM config files,
+# and should contain a list of the authorization modules that define
+# the central access policy for use on the system. The default is to
+# only deny service to users whose accounts are expired in /etc/shadow.
+#
+# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
+# To take advantage of this, it is recommended that you configure any
+# local modules either before or after the default block, and use
+# pam-auth-update to manage selection of other modules. See
+# pam-auth-update(8) for details.
+#
+
+# here are the per-package modules (the "Primary" block)
+account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so
+# here's the fallback if no module succeeds
+account requisite pam_deny.so
+# Announce if faillock is blocking access
+account required pam_faillock.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+account required pam_permit.so
+# and here are more per-package modules (the "Additional" block)
+# end of pam-auth-update config
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-auth b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-auth
new file mode 100644
index 000000000..c051ab7e6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-auth
@@ -0,0 +1,26 @@
+#
+# /etc/pam.d/common-auth - authentication settings common to all services
+#
+# This file is included from other service-specific PAM config files,
+# and should contain a list of the authentication modules that define
+# the central authentication scheme for use on the system
+# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
+# traditional Unix authentication mechanisms.
+
+# here are the per-package modules (the "Primary" block)
+# Try for local user first, and then try for ldap
+auth [success=2 default=ignore] pam_unix.so quiet
+-auth [success=1 default=ignore] pam_ldap.so ignore_unknown_user ignore_authinfo_unavail
+# Control gets here when no authentication module succeeds. Increment the
+# failure tally and return failure status to PAM.
+auth [default=die] pam_faillock.so authfail
+# Control gets here when authentication succeeds. Check if the user is locked
+# out due to consecutive authentication failures and return status accordingly.
+auth sufficient pam_faillock.so authsucc
+# If authsucc failed, deny access
+auth requisite pam_deny.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+auth required pam_permit.so
+# and here are more per-package modules (the "Additional" block)
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-password b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-password
new file mode 100644
index 000000000..2fc4011b2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-password
@@ -0,0 +1,27 @@
+#
+# /etc/pam.d/common-password - password-related modules common to all services
+#
+# This file is included from other service-specific PAM config files,
+# and should contain a list of modules that define the services to be
+# used to change user passwords. The default is pam_unix.
+
+# Explanation of pam_unix options:
+#
+# The "sha512" option enables salted SHA512 passwords. Without this option,
+# the default is Unix crypt. Prior releases used the option "md5".
+#
+# See the pam_unix manpage for other options.
+
+# here are the per-package modules (the "Primary" block)
+password [success=ok default=die] pam_pwquality.so debug
+password [success=ok default=die] pam_ipmicheck.so spec_grp_name=ipmi use_authtok
+password [success=ok ignore=ignore default=die] pam_pwhistory.so debug enforce_for_root remember=0 use_authtok
+password [success=ok default=die] pam_unix.so sha512 use_authtok
+password [success=1 default=die] pam_ipmisave.so spec_grp_name=ipmi spec_pass_file=/etc/ipmi_pass key_file=/etc/key_file
+# here's the fallback if no module succeeds
+password requisite pam_deny.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+password required pam_permit.so
+# and here are more per-package modules (the "Additional" block)
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session
new file mode 100644
index 000000000..a4a551f71
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session
@@ -0,0 +1,19 @@
+#
+# /etc/pam.d/common-session - session-related modules common to all services
+#
+# This file is included from other service-specific PAM config files,
+# and should contain a list of modules that define tasks to be performed
+# at the start and end of sessions of *any* kind (both interactive and
+# non-interactive).
+#
+
+# here are the per-package modules (the "Primary" block)
+session [default=1] pam_permit.so
+# here's the fallback if no module succeeds
+session requisite pam_deny.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+session required pam_permit.so
+# and here are more per-package modules (the "Additional" block)
+session required pam_unix.so
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session-noninteractive b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session-noninteractive
new file mode 100644
index 000000000..b110bb2b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/common-session-noninteractive
@@ -0,0 +1,19 @@
+#
+# /etc/pam.d/common-session-noninteractive - session-related modules
+# common to all non-interactive services
+#
+# This file is included from other service-specific PAM config files,
+# and should contain a list of modules that define tasks to be performed
+# at the start and end of all non-interactive sessions.
+#
+
+# here are the per-package modules (the "Primary" block)
+session [default=1] pam_permit.so
+# here's the fallback if no module succeeds
+session requisite pam_deny.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+session required pam_permit.so
+# and here are more per-package modules (the "Additional" block)
+session required pam_unix.so
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/other b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/other
new file mode 100644
index 000000000..ec970ecbe
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/pam.d/other
@@ -0,0 +1,24 @@
+#
+# /etc/pam.d/other - specify the PAM fallback behaviour
+#
+# Note that this file is used for any unspecified service; for example
+#if /etc/pam.d/cron specifies no session modules but cron calls
+#pam_open_session, the session module out of /etc/pam.d/other is
+#used.
+
+# We use pam_warn.so to generate syslog notes that the 'other'
+#fallback rules are being used (as a hint to suggest you should setup
+#specific PAM rules for the service and aid to debugging). Then to be
+#secure, deny access to all services by default.
+
+auth required pam_warn.so
+auth required pam_deny.so
+
+account required pam_warn.so
+account required pam_deny.so
+
+password required pam_warn.so
+password required pam_deny.so
+
+session required pam_warn.so
+session required pam_deny.so
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/run-ptest b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/run-ptest
new file mode 100644
index 000000000..9c304aee4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam/run-ptest
@@ -0,0 +1,32 @@
+#! /bin/sh
+
+cd tests
+
+export srcdir=.
+
+failed=0
+all=0
+for f in tst-*; do
+ "./$f" > /dev/null 2>&1
+ case "$?" in
+ 0)
+ echo "PASS: $f"
+ all=$((all + 1))
+ ;;
+ 77)
+ echo "SKIP: $f"
+ ;;
+ *)
+ echo "FAIL: $f"
+ failed=$((failed + 1))
+ all=$((all + 1))
+ ;;
+ esac
+done
+
+if [ "$failed" -eq 0 ] ; then
+ echo "All $all tests passed"
+else
+ echo "$failed of $all tests failed"
+fi
+unset srcdir
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend
index 21e1d88ea..65a4d6d68 100644
--- a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_%.bbappend
@@ -1,7 +1,75 @@
RDEPENDS:${PN}-runtime += "${MLPREFIX}pam-plugin-localuser-${libpam_suffix}"
+RDEPENDS:${PN}-runtime += "${MLPREFIX}pam-plugin-faillock-${libpam_suffix}"
+RDEPENDS:${PN}-runtime += "libpwquality"
+RDEPENDS:${PN}-runtime:remove = "${MLPREFIX}pam-plugin-cracklib-${libpam_suffix}"
+RDEPENDS:${PN}-runtime:remove = "${MLPREFIX}pam-plugin-tally2-${libpam_suffix}"
+
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+SRC_URI += " file://pam.d/common-password \
+ file://pam.d/common-account \
+ file://pam.d/common-auth \
+ file://pam.d/common-session \
+ file://faillock.conf \
+ file://convert-pam-configs.service \
+ file://convert-pam-configs.sh \
+ "
+
+inherit systemd
+SYSTEMD_SERVICE:${PN} += "convert-pam-configs.service"
+
+FILES:${PN} += "${bindir}/convert-pam-configs.sh \
+ ${systemd_system_unitdir}/convert-pam-configs.service \
+ "
-#Default settings lockout duration to 300 seconds and threshold value to 10
do_install:append() {
- sed -i 's/deny=0/deny=10/' ${D}${sysconfdir}/pam.d/common-auth
- sed -i 's/unlock_time=0/unlock_time=300/' ${D}${sysconfdir}/pam.d/common-auth
+ install -d ${D}/etc/security
+ install -m 0644 ${WORKDIR}/faillock.conf ${D}/etc/security
+
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/convert-pam-configs.sh ${D}${bindir}
+
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/convert-pam-configs.service ${D}${systemd_system_unitdir}
}
+
+#
+# Background:
+# 1. Linux-PAM modules tally2 and cracklib were removed in libpam_1.5,
+# which prompted OpenBMC to change to the faillock and pwquality modules.
+# The PAM config files under /etc/pam.d were changed accordingly.
+# 2. OpenBMC implementations store Redfish property values in PAM config files.
+# For example, the D-Bus property maxLoginAttemptBeforeLockout is stored in
+# /etc/pam.d/common-auth as the pam_tally2.so deny= parameter value.
+# 3. The /etc directory is readonly and has a readwrite overlayfs. That
+# means when a config file changes, an overlay file is created which hides
+# the readonly version.
+#
+# Problem scenario:
+# 1. Begin with a BMC that has a firmware image which has the old PAM
+# modules and the old PAM config files which have modified parameters.
+# For example, there is an overlay file for /etc/pam.d/common-auth.
+# 2. Perform a firmware update to a firmware image which has the new PAM
+# modules. The updated image will have not have the old PAM modules.
+# It will have the new PAM config files in its readonly file system and
+# the old PAM config files in its readwrite overlay.
+# 3. Note that PAM authentication will always fail at this point because
+# the old PAM config files in the overlay tell PAM to use the old PAM
+# modules which are not present on the system.
+#
+# Two possible recoveries are:
+# A. Factory reset the BMC. This will clear the readwrite overlay,
+# allowing PAM to use the readonly version.
+# B. Convert the old PAM config files to the new style. See below.
+#
+# Service: The convert-pam-configs.service updates the old-style PAM config
+# files on the BMC: it changes uses of the old modules to the new modules
+# and carries forward configuration parameters. A key point is that files
+# are written to *only* as needed to convert uses of the old modules to the
+# new modules. See the conversion tool for details.
+#
+# This service can be removed when the BMC no longer supports a direct
+# firware update path from a version which has the old PAM configs to a
+# version which has the new PAM configs.
+#
+# In case of downgrade, Factory reset is recommended. Current logic in existing
+# images won't be able to take care of these settings during downgrade.
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_1.5.2.bb b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_1.5.2.bb
new file mode 100644
index 000000000..5197f1813
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/libpam_1.5.2.bb
@@ -0,0 +1,186 @@
+DISABLE_STATIC = ""
+SUMMARY = "Linux-PAM (Pluggable Authentication Modules)"
+DESCRIPTION = "Linux-PAM (Pluggable Authentication Modules for Linux), a flexible mechanism for authenticating users"
+HOMEPAGE = "https://fedorahosted.org/linux-pam/"
+BUGTRACKER = "https://fedorahosted.org/linux-pam/newticket"
+SECTION = "base"
+# PAM is dual licensed under GPL and BSD.
+# /etc/pam.d comes from Debian libpam-runtime in 2009-11 (at that time
+# libpam-runtime-1.0.1 is GPL-2.0-or-later), by openembedded
+LICENSE = "GPL-2.0-or-later | BSD-3-Clause"
+LIC_FILES_CHKSUM = "file://COPYING;md5=7eb5c1bf854e8881005d673599ee74d3 \
+ file://libpamc/License;md5=a4da476a14c093fdc73be3c3c9ba8fb3 \
+ "
+
+SRC_URI = "${GITHUB_BASE_URI}/download/v${PV}/Linux-PAM-${PV}.tar.xz \
+ file://99_pam \
+ file://pam.d/common-account \
+ file://pam.d/common-auth \
+ file://pam.d/common-password \
+ file://pam.d/common-session \
+ file://pam.d/common-session-noninteractive \
+ file://pam.d/other \
+ file://libpam-xtests.patch \
+ file://0001-run-xtests.sh-check-whether-files-exist.patch \
+ file://run-ptest \
+ file://pam-volatiles.conf \
+ file://CVE-2022-28321-0002.patch \
+ "
+
+SRC_URI[sha256sum] = "e4ec7131a91da44512574268f493c6d8ca105c87091691b8e9b56ca685d4f94d"
+
+DEPENDS = "bison-native flex-native cracklib libxml2-native virtual/crypt"
+
+EXTRA_OECONF = "--includedir=${includedir}/security \
+ --libdir=${base_libdir} \
+ --with-systemdunitdir=${systemd_system_unitdir} \
+ --disable-nis \
+ --disable-regenerate-docu \
+ --disable-doc \
+ --disable-prelude"
+
+CFLAGS:append = " -fPIC "
+
+S = "${WORKDIR}/Linux-PAM-${PV}"
+
+inherit autotools gettext pkgconfig systemd ptest github-releases
+
+PACKAGECONFIG ??= ""
+PACKAGECONFIG[audit] = "--enable-audit,--disable-audit,audit,"
+PACKAGECONFIG[userdb] = "--enable-db=db,--enable-db=no,db,"
+
+PACKAGES += "${PN}-runtime ${PN}-xtests"
+FILES:${PN} = "${base_libdir}/lib*${SOLIBS}"
+FILES:${PN}-dev += "${base_libdir}/security/*.la ${base_libdir}/*.la ${base_libdir}/lib*${SOLIBSDEV}"
+FILES:${PN}-runtime = "${sysconfdir} ${sbindir} ${systemd_system_unitdir}"
+FILES:${PN}-xtests = "${datadir}/Linux-PAM/xtests"
+
+PACKAGES_DYNAMIC += "^${MLPREFIX}pam-plugin-.*"
+
+def get_multilib_bit(d):
+ baselib = d.getVar('baselib') or ''
+ return baselib.replace('lib', '')
+
+libpam_suffix = "suffix${@get_multilib_bit(d)}"
+
+RPROVIDES:${PN} += "${PN}-${libpam_suffix}"
+RPROVIDES:${PN}-runtime += "${PN}-runtime-${libpam_suffix}"
+
+RDEPENDS:${PN}-runtime = "${PN}-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-deny-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-permit-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-warn-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-unix-${libpam_suffix} \
+ "
+RDEPENDS:${PN}-xtests = "${PN}-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-access-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-debug-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-pwhistory-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-succeed-if-${libpam_suffix} \
+ ${MLPREFIX}pam-plugin-time-${libpam_suffix} \
+ bash coreutils"
+
+# FIXME: Native suffix breaks here, disable it for now
+RRECOMMENDS:${PN} = "${PN}-runtime-${libpam_suffix}"
+RRECOMMENDS:${PN}:class-native = ""
+
+python populate_packages:prepend () {
+ def pam_plugin_hook(file, pkg, pattern, format, basename):
+ pn = d.getVar('PN')
+ libpam_suffix = d.getVar('libpam_suffix')
+
+ rdeps = d.getVar('RDEPENDS:' + pkg)
+ if rdeps:
+ rdeps = rdeps + " " + pn + "-" + libpam_suffix
+ else:
+ rdeps = pn + "-" + libpam_suffix
+ d.setVar('RDEPENDS:' + pkg, rdeps)
+
+ provides = d.getVar('RPROVIDES:' + pkg)
+ if provides:
+ provides = provides + " " + pkg + "-" + libpam_suffix
+ else:
+ provides = pkg + "-" + libpam_suffix
+ d.setVar('RPROVIDES:' + pkg, provides)
+
+ mlprefix = d.getVar('MLPREFIX') or ''
+ dvar = d.expand('${WORKDIR}/package')
+ pam_libdir = d.expand('${base_libdir}/security')
+ pam_sbindir = d.expand('${sbindir}')
+ pam_filterdir = d.expand('${base_libdir}/security/pam_filter')
+ pam_pkgname = mlprefix + 'pam-plugin%s'
+
+ do_split_packages(d, pam_libdir, r'^pam(.*)\.so$', pam_pkgname,
+ 'PAM plugin for %s', hook=pam_plugin_hook, extra_depends='')
+ do_split_packages(d, pam_filterdir, r'^(.*)$', 'pam-filter-%s', 'PAM filter for %s', extra_depends='')
+}
+
+do_compile_ptest() {
+ cd tests
+ sed -i -e 's/$(MAKE) $(AM_MAKEFLAGS) check-TESTS//' Makefile
+ oe_runmake check-am
+ cd -
+}
+
+do_install() {
+ autotools_do_install
+
+ # don't install /var/run when populating rootfs. Do it through volatile
+ rm -rf ${D}${localstatedir}
+
+ if ${@bb.utils.contains('DISTRO_FEATURES','sysvinit','false','true',d)}; then
+ rm -rf ${D}${sysconfdir}/init.d/
+ rm -rf ${D}${sysconfdir}/rc*
+ install -d ${D}${sysconfdir}/tmpfiles.d
+ install -m 0644 ${WORKDIR}/pam-volatiles.conf \
+ ${D}${sysconfdir}/tmpfiles.d/pam.conf
+ else
+ install -d ${D}${sysconfdir}/default/volatiles
+ install -m 0644 ${WORKDIR}/99_pam \
+ ${D}${sysconfdir}/default/volatiles/
+ fi
+
+ install -d ${D}${sysconfdir}/pam.d/
+ install -m 0644 ${WORKDIR}/pam.d/* ${D}${sysconfdir}/pam.d/
+
+ # The lsb requires unix_chkpwd has setuid permission
+ chmod 4755 ${D}${sbindir}/unix_chkpwd
+
+ if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ echo "session optional pam_systemd.so" >> ${D}${sysconfdir}/pam.d/common-session
+ fi
+ if ${@bb.utils.contains('DISTRO_FEATURES','usrmerge','false','true',d)}; then
+ install -d ${D}/${libdir}/
+ mv ${D}/${base_libdir}/pkgconfig ${D}/${libdir}/
+ fi
+}
+
+do_install_ptest() {
+ if [ ${PTEST_ENABLED} = "1" ]; then
+ mkdir -p ${D}${PTEST_PATH}/tests
+ install -m 0755 ${B}/tests/.libs/* ${D}${PTEST_PATH}/tests
+ install -m 0644 ${S}/tests/confdir ${D}${PTEST_PATH}/tests
+ fi
+}
+
+pkg_postinst:${PN}() {
+ if [ -z "$D" ] && [ -e /etc/init.d/populate-volatile.sh ] ; then
+ /etc/init.d/populate-volatile.sh update
+ fi
+}
+
+inherit features_check
+REQUIRED_DISTRO_FEATURES = "pam"
+
+BBCLASSEXTEND = "nativesdk native"
+
+CONFFILES:${PN}-runtime += "${sysconfdir}/pam.d/common-session"
+CONFFILES:${PN}-runtime += "${sysconfdir}/pam.d/common-auth"
+CONFFILES:${PN}-runtime += "${sysconfdir}/pam.d/common-password"
+CONFFILES:${PN}-runtime += "${sysconfdir}/pam.d/common-session-noninteractive"
+CONFFILES:${PN}-runtime += "${sysconfdir}/pam.d/common-account"
+CONFFILES:${PN}-runtime += "${sysconfdir}/security/limits.conf"
+
+GITHUB_BASE_URI = "https://github.com/linux-pam/linux-pam/releases"
+
+CVE_PRODUCT = "linux-pam"