From f5d545ab7766fbf127544d8802b957c146628588 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2026 12:02:58 +0200 Subject: [PATCH 1/2] core: fix error code passed to pam_syslog_pam_error() --- src/core/exec-invoke.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 2fabfe3410..c706e017a4 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -1163,7 +1163,7 @@ static int pam_close_session_and_delete_credentials(pam_handle_t *pamh, int flag s = sym_pam_setcred(pamh, PAM_DELETE_CRED | flags); if (s != PAM_SUCCESS) - pam_syslog_pam_error(pamh, LOG_DEBUG, r, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_DEBUG, s, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@"); return r != PAM_SUCCESS ? r : s; } From 34e5f14c3496097c4157a5ed8a13ed4c4b1c48a9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2026 12:06:11 +0200 Subject: [PATCH 2/2] pam: use "pam_rootok" rather than "pam_deny" in the "auth" stacks of our PAM configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PAM is a bit quirky: the main libpam calls are pam_authenticate(), pam_open_session(), pam_acctmgmt(), pam_chauthtok(), pam_setcred() and each have their own PAM "management group" in PAM configuration files that configure the modules to call: "auth", "account", "session", "password" – except for pam_setcred() which shares its grpup with pam_authenticate() and uses "auth". Both our PAM configuration files we ship by default are never used for authentication (they just appear in PAMname= in a service to get a PAM session set up, and PAMName= never calls pam_authenticate()). However, they end up being used for pam_setcreds() (because some modules want to use that the service manager calls it). So far we used the pam_deny module for the "auth" management group for these two PA; configurations (since d6aed1dca8ff3d5a4b7da996fef89b0c6c6440ec) but that's not ideal, since it means we'll always cause pam_setcreds() to fail which will create debug log noise (since the service manager debug logs pam_secreds() failures). Let's switch to pam_rootok for this instead. This has the benefit that pam_setcred() will always succeed for this, and pam_authenticate() only if the caller is root anyway. This is great, because it means our PAM configuration cannot be misused for other purposes accidentally (authentication will fail, unless you are already root), but won't result in any log noise (debug or otherwise). Follow-up for: d6aed1dca8ff3d5a4b7da996fef89b0c6c6440ec Fixes: #39617 --- src/login/systemd-user.in | 7 ++++++- src/run/systemd-run0.in | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/login/systemd-user.in b/src/login/systemd-user.in index 70ca709f51..6a4bc058e6 100644 --- a/src/login/systemd-user.in +++ b/src/login/systemd-user.in @@ -8,7 +8,12 @@ {% endif %} account required pam_unix.so no_pass_expiry -auth required pam_deny.so +# systemd never invokes pam_authenticate() on this stack, but it does invoke pam_setcred(), which runs the +# "auth" stack too. Hence an "auth" entry is needed that lets pam_setcred() succeed, without falling back to +# the "other" service (which typically consists of pam_warn/pam_deny, and thus generates log noise). +# pam_rootok's pam_sm_setcred() unconditionally succeeds, while its pam_sm_authenticate() only succeeds for +# callers running as root (which the service manager does). +auth required pam_rootok.so {% if HAVE_SELINUX %} session required pam_selinux.so close diff --git a/src/run/systemd-run0.in b/src/run/systemd-run0.in index 6ad114f0de..db9f2b4587 100644 --- a/src/run/systemd-run0.in +++ b/src/run/systemd-run0.in @@ -8,7 +8,12 @@ {% endif %} account required pam_unix.so -auth required pam_deny.so +# systemd never invokes pam_authenticate() on this stack (authorization for run0 is done via polkit), but it +# does invoke pam_setcred(), which runs the "auth" stack too. Hence an "auth" entry is needed that lets +# pam_setcred() succeed, without falling back to the "other" service (which typically consists of +# pam_warn/pam_deny, and thus generates log noise). pam_rootok's pam_sm_setcred() unconditionally succeeds, +# while its pam_sm_authenticate() only succeeds for callers running as root (which the service manager does). +auth required pam_rootok.so {% if HAVE_SELINUX %} session required pam_selinux.so close