From d2747481603a43b8f37470763fdd0944902f82da Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 18 Nov 2025 09:27:14 +0900 Subject: [PATCH 01/12] libcrypt-util: move looks_like_hashed_password() No functional change, just preparation for later change. --- src/shared/libcrypt-util.c | 32 ++++++++++++++++---------------- src/shared/libcrypt-util.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index 594963ac6b05f..f981c1b9973fc 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -140,22 +140,6 @@ int hash_password_full(const char *password, void **cd_data, int *cd_size, char return strdup_to(ret, p); } -bool looks_like_hashed_password(const char *s) { - /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists - * various hashing methods. We only reject (return false) strings which are documented to have - * different meanings. - * - * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!", - * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e. - */ - if (!s) - return false; - - s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */ - - return !STR_IN_SET(s, "x", "*"); -} - int test_password_one(const char *hashed_password, const char *password) { _cleanup_(erase_and_freep) void *cd_data = NULL; int cd_size = 0; @@ -186,3 +170,19 @@ int test_password_many(char **hashed_password, const char *password) { return false; } + +bool looks_like_hashed_password(const char *s) { + /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists + * various hashing methods. We only reject (return false) strings which are documented to have + * different meanings. + * + * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!", + * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e. + */ + if (!s) + return false; + + s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */ + + return !STR_IN_SET(s, "x", "*"); +} diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index 27c5f055a389f..ed2993f82cead 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -8,6 +8,6 @@ int hash_password_full(const char *password, void **cd_data, int *cd_size, char static inline int hash_password(const char *password, char **ret) { return hash_password_full(password, NULL, NULL, ret); } -bool looks_like_hashed_password(const char *s); int test_password_one(const char *hashed_password, const char *password); int test_password_many(char **hashed_password, const char *password); +bool looks_like_hashed_password(const char *s); From b26406c9c33f8e65afdf5c87a05e4f6c311ffb17 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 18 Nov 2025 09:52:37 +0900 Subject: [PATCH 02/12] libcrypt-util: drop unused hash_passwrod_full() It is only used by test cases. Not necessary to keep it. --- src/shared/libcrypt-util.c | 10 +++--- src/shared/libcrypt-util.h | 5 +-- src/test/test-libcrypt-util.c | 66 +++++++++++++++-------------------- 3 files changed, 34 insertions(+), 47 deletions(-) diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index f981c1b9973fc..cff3f586cfd28 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -119,20 +119,18 @@ static char* systemd_crypt_ra(const char *phrase, const char *setting, void **da #endif -int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) { +int hash_password(const char *password, char **ret) { _cleanup_free_ char *salt = NULL; - _cleanup_(erase_and_freep) void *_cd_data = NULL; + _cleanup_(erase_and_freep) void *cd_data = NULL; const char *p; - int r, _cd_size = 0; - - assert(!!cd_data == !!cd_size); + int r, cd_size = 0; r = make_salt(&salt); if (r < 0) return log_debug_errno(r, "Failed to generate salt: %m"); errno = 0; - p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size); + p = crypt_ra(password, salt, &cd_data, &cd_size); if (!p) return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), CRYPT_RA_NAME "() failed: %m"); diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index ed2993f82cead..e80cfcaf4e21f 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -4,10 +4,7 @@ #include "shared-forward.h" int make_salt(char **ret); -int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret); -static inline int hash_password(const char *password, char **ret) { - return hash_password_full(password, NULL, NULL, ret); -} +int hash_password(const char *password, char **ret); int test_password_one(const char *hashed_password, const char *password); int test_password_many(char **hashed_password, const char *password); bool looks_like_hashed_password(const char *s); diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c index 92eda2e1a7cc1..f4968d91deff6 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -62,45 +62,37 @@ static int test_hash_password(void) { static void test_hash_password_full(void) { log_info("/* %s */", __func__); - _cleanup_free_ void *cd_data = NULL; - int cd_size = 0; - log_info("sizeof(struct crypt_data): %zu bytes", sizeof(struct crypt_data)); - for (unsigned c = 0; c < 2; c++) - FOREACH_STRING(i, "abc123", "h⸿sło") { - _cleanup_free_ char *hashed; - - if (c == 0) - assert_se(hash_password_full(i, &cd_data, &cd_size, &hashed) == 0); - else - assert_se(hash_password_full(i, NULL, NULL, &hashed) == 0); - log_debug("\"%s\" → \"%s\"", i, hashed); - log_info("crypt_r[a] buffer size: %i bytes", cd_size); - - assert_se(test_password_one(hashed, i) == true); - assert_se(test_password_one(i, hashed) <= 0); /* We get an error for non-utf8 */ - assert_se(test_password_one(hashed, "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed), i) == true); - assert_se(test_password_many(STRV_MAKE(hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); - } + FOREACH_STRING(i, "abc123", "h⸿sło") { + _cleanup_free_ char *hashed; + + assert_se(hash_password(i, &hashed) == 0); + log_debug("\"%s\" → \"%s\"", i, hashed); + + assert_se(test_password_one(hashed, i) == true); + assert_se(test_password_one(i, hashed) <= 0); /* We get an error for non-utf8 */ + assert_se(test_password_one(hashed, "foobar") == false); + assert_se(test_password_many(STRV_MAKE(hashed), i) == true); + assert_se(test_password_many(STRV_MAKE(hashed), "foobar") == false); + assert_se(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar") == false); + assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i) == true); + assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i) == true); + assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "") == false); + assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "") == false); + } } int main(int argc, char *argv[]) { From d5267b22757a638e4f2c3b890e595f3a26041b6f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 18 Nov 2025 10:28:50 +0900 Subject: [PATCH 03/12] libcrypt-util: add missing assertions --- src/shared/libcrypt-util.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index cff3f586cfd28..26e907f866d96 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -12,6 +12,7 @@ #include "strv.h" int make_salt(char **ret) { + assert(ret); #if HAVE_CRYPT_GENSALT_RA const char *e; @@ -86,6 +87,8 @@ int make_salt(char **ret) { /* Provide a poor man's fallback that uses a fixed size buffer. */ static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) { + assert(phrase); + assert(setting); assert(data); assert(size); @@ -125,6 +128,9 @@ int hash_password(const char *password, char **ret) { const char *p; int r, cd_size = 0; + assert(password); + assert(ret); + r = make_salt(&salt); if (r < 0) return log_debug_errno(r, "Failed to generate salt: %m"); @@ -143,6 +149,9 @@ int test_password_one(const char *hashed_password, const char *password) { int cd_size = 0; const char *k; + assert(hashed_password); + assert(password); + errno = 0; k = crypt_ra(password, hashed_password, &cd_data, &cd_size); if (!k) { @@ -158,6 +167,8 @@ int test_password_one(const char *hashed_password, const char *password) { int test_password_many(char **hashed_password, const char *password) { int r; + assert(password); + STRV_FOREACH(hpw, hashed_password) { r = test_password_one(*hpw, password); if (r < 0) From 8608d2e910c2a007d4ce2c48aa6ab37523e3d1c2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 18 Aug 2025 00:13:27 +0900 Subject: [PATCH 04/12] test-libcrypt-util: use DEFINE_TEST_MAIN() and ASSERT_XYZ() Also, tests for make_salt() in test-user-util.c are moved to test-libcrypt-util.c. --- src/test/test-libcrypt-util.c | 115 ++++++++++++++-------------------- src/test/test-user-util.c | 13 ---- 2 files changed, 46 insertions(+), 82 deletions(-) diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c index f4968d91deff6..9f171a2415a29 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -6,9 +6,7 @@ #include "strv.h" #include "tests.h" -static void test_crypt_preferred_method(void) { - log_info("/* %s */", __func__); - +TEST(crypt_preferred_method) { log_info("crypt_preferred_method: %s", #if HAVE_CRYPT_PREFERRED_METHOD crypt_preferred_method() @@ -18,24 +16,26 @@ static void test_crypt_preferred_method(void) { ); } -static void test_make_salt(void) { - log_info("/* %s */", __func__); +TEST(make_salt) { + _cleanup_strv_free_ char **l = NULL; for (int i = 0; i < 10; i++) { _cleanup_free_ char *t; - assert_se(make_salt(&t) == 0); + ASSERT_OK(make_salt(&t)); log_info("%s", t); + + ASSERT_FALSE(strv_contains(l, t)); + ASSERT_OK(strv_consume(&l, TAKE_PTR(t))); } } -static int test_hash_password(void) { - log_info("/* %s */", __func__); +TEST(hash_password) { +#if defined(__powerpc__) && !defined(XCRYPT_VERSION_MAJOR) + return log_tests_skipped("crypt_r() causes a buffer overflow on ppc64el, see https://github.com/systemd/systemd/pull/16981#issuecomment-691203787"); +#endif /* As a warm-up exercise, check if we can hash passwords. */ - - bool have_sane_hash = false; - FOREACH_STRING(hash, "ew3bU1.hoKk4o", "$1$gc5rWpTB$wK1aul1PyBn9AX1z93stk1", @@ -43,72 +43,49 @@ static int test_hash_password(void) { "$5$lGhDrcrao9zb5oIK$05KlOVG3ocknx/ThreqXE/gk.XzFFBMTksc4t2CPDUD", "$6$c7wB/3GiRk0VHf7e$zXJ7hN0aLZapE.iO4mn/oHu6.prsXTUG/5k1AxpgR85ELolyAcaIGRgzfwJs3isTChMDBjnthZyaMCfCNxo9I.", "$y$j9T$$9cKOWsAm4m97WiYk61lPPibZpy3oaGPIbsL4koRe/XD") { - int b; - b = test_password_one(hash, "ppp"); - log_info("%s: %s", hash, yes_no(b)); -#if defined(XCRYPT_VERSION_MAJOR) - /* xcrypt is supposed to always implement all methods. */ - assert_se(b); +#ifndef __GLIBC__ + /* musl does not support yescrypt. */ + if (hash[1] == 'y') { + ASSERT_OK_ZERO(test_password_one(hash, "ppp")); + continue; + } +#elif !defined(XCRYPT_VERSION_MAJOR) + ASSERT_OK(test_password_one(hash, "ppp")); + continue; #endif - - if (b && IN_SET(hash[1], '6', 'y')) - have_sane_hash = true; + ASSERT_OK_POSITIVE(test_password_one(hash, "ppp")); } - return have_sane_hash; -} - -static void test_hash_password_full(void) { - log_info("/* %s */", __func__); - - log_info("sizeof(struct crypt_data): %zu bytes", sizeof(struct crypt_data)); - FOREACH_STRING(i, "abc123", "h⸿sło") { _cleanup_free_ char *hashed; - assert_se(hash_password(i, &hashed) == 0); + ASSERT_OK(hash_password(i, &hashed)); log_debug("\"%s\" → \"%s\"", i, hashed); - assert_se(test_password_one(hashed, i) == true); - assert_se(test_password_one(i, hashed) <= 0); /* We get an error for non-utf8 */ - assert_se(test_password_one(hashed, "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed), i) == true); - assert_se(test_password_many(STRV_MAKE(hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); - } + ASSERT_OK_POSITIVE(test_password_one(hashed, i)); + ASSERT_LE(test_password_one(i, hashed), 0); /* We get an error for non-utf8 */ + ASSERT_OK_ZERO(test_password_one(hashed, "foobar")); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE(hashed), i)); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed), "foobar")); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar")); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i)); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i)); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "")); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "")); + } } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - -#if defined(__powerpc__) && !defined(XCRYPT_VERSION_MAJOR) - return log_tests_skipped("crypt_r() causes a buffer overflow on ppc64el, see https://github.com/systemd/systemd/pull/16981#issuecomment-691203787"); -#endif - - test_crypt_preferred_method(); - test_make_salt(); - - if (!test_hash_password()) - return log_tests_skipped("crypt doesn't support yescrypt or sha512crypt"); - - test_hash_password_full(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index d822df61fb135..47bd01f9d0f80 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -4,7 +4,6 @@ #include "alloc-util.h" #include "format-util.h" -#include "libcrypt-util.h" #include "log.h" #include "memory-util.h" #include "path-util.h" @@ -342,18 +341,6 @@ TEST(get_group_creds) { test_get_group_creds_one("65534", NOBODY_GROUP_NAME, GID_NOBODY); } -TEST(make_salt) { - _cleanup_free_ char *s, *t; - - ASSERT_OK(make_salt(&s)); - log_info("got %s", s); - - ASSERT_OK(make_salt(&t)); - log_info("got %s", t); - - ASSERT_NOT_STREQ(s, t); -} - TEST(in_gid) { ASSERT_OK(in_gid(getgid())); ASSERT_OK(in_gid(getegid())); From 431fc656bcff3038fa257d7dcaf577f02361760a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 18 Aug 2025 00:58:56 +0900 Subject: [PATCH 05/12] Bump required minimum version of libseccomp to 2.4.0 Major distributions already have libseccomp 2.5.x or newer. Let's bump to the required minimum version to 2.4.0, which provides SCMP_ACT_KILL_PROCESS, SCMP_ACT_LOG, SCMP_ARCH_PARISC, and SCMP_ARCH_PARISC64. Note, libseccomp 2.4.0 was released on 2019-03-15. See also #38608. --- README | 2 +- meson.build | 2 +- src/core/exec-invoke.c | 10 +--------- src/nspawn/nspawn-oci.c | 10 ---------- src/shared/seccomp-util.c | 37 +++---------------------------------- src/shared/seccomp-util.h | 3 --- src/test/test-seccomp.c | 4 ++-- 7 files changed, 8 insertions(+), 60 deletions(-) diff --git a/README b/README index 9492d717dec06..83493b041776a 100644 --- a/README +++ b/README @@ -215,7 +215,7 @@ REQUIREMENTS: libxcrypt or glibc (<= 2.38 built with --enable-crypt) libmount >= 2.30 (from util-linux) (util-linux *must* be built without --enable-libmount-support-mtab) - libseccomp >= 2.3.1 (optional) + libseccomp >= 2.4.0 (optional) libblkid >= 2.37 (from util-linux) (optional) libkmod >= 15 (optional) PAM >= 1.1.2 (optional) diff --git a/meson.build b/meson.build index 26b6fea22ca50..cc26bbd63e2f6 100644 --- a/meson.build +++ b/meson.build @@ -1180,7 +1180,7 @@ conf.set10('HAVE_PWQUALITY', have) conf.set10('HAVE_PASSWDQC', not have and libpwquality.found()) libseccomp = dependency('libseccomp', - version : '>= 2.3.1', + version : '>= 2.4.0', required : get_option('seccomp')) conf.set10('HAVE_SECCOMP', libseccomp.found()) libseccomp_cflags = libseccomp.partial_dependency(includes: true, compile_args: true) diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index cf47d996b29a6..4adf8d00ce8b9 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -1673,7 +1673,7 @@ static int apply_syscall_filter(const ExecContext *c, const ExecParameters *p) { if (skip_seccomp_unavailable("SystemCallFilter=")) return 0; - negative_action = c->syscall_errno == SECCOMP_ERROR_NUMBER_KILL ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno); + negative_action = c->syscall_errno == SECCOMP_ERROR_NUMBER_KILL ? SCMP_ACT_KILL_PROCESS : SCMP_ACT_ERRNO(c->syscall_errno); if (c->syscall_allow_list) { default_action = negative_action; @@ -1694,9 +1694,7 @@ static int apply_syscall_filter(const ExecContext *c, const ExecParameters *p) { } static int apply_syscall_log(const ExecContext *c, const ExecParameters *p) { -#ifdef SCMP_ACT_LOG uint32_t default_action, action; -#endif assert(c); assert(p); @@ -1704,7 +1702,6 @@ static int apply_syscall_log(const ExecContext *c, const ExecParameters *p) { if (!context_has_syscall_logs(c)) return 0; -#ifdef SCMP_ACT_LOG if (skip_seccomp_unavailable("SystemCallLog=")) return 0; @@ -1719,11 +1716,6 @@ static int apply_syscall_log(const ExecContext *c, const ExecParameters *p) { } return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_log, action, false); -#else - /* old libseccomp */ - log_debug( "SECCOMP feature SCMP_ACT_LOG not available, skipping SystemCallLog="); - return 0; -#endif } static int apply_syscall_archs(const ExecContext *c, const ExecParameters *p) { diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index b0cc7a58cf8e2..29091bd82c8f5 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -1554,15 +1554,9 @@ static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) { { "SCMP_ACT_ALLOW", SCMP_ACT_ALLOW }, { "SCMP_ACT_ERRNO", SCMP_ACT_ERRNO(EPERM) }, /* the OCI spec doesn't document the error, but it appears EPERM is supposed to be used */ { "SCMP_ACT_KILL", SCMP_ACT_KILL }, -#ifdef SCMP_ACT_KILL_PROCESS { "SCMP_ACT_KILL_PROCESS", SCMP_ACT_KILL_PROCESS }, -#endif -#ifdef SCMP_ACT_KILL_THREAD { "SCMP_ACT_KILL_THREAD", SCMP_ACT_KILL_THREAD }, -#endif -#ifdef SCMP_ACT_LOG { "SCMP_ACT_LOG", SCMP_ACT_LOG }, -#endif { "SCMP_ACT_TRAP", SCMP_ACT_TRAP }, /* We don't support SCMP_ACT_TRACE because that requires a tracer, and that doesn't really make sense @@ -1596,12 +1590,8 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) { { "SCMP_ARCH_MIPSEL64", SCMP_ARCH_MIPSEL64 }, { "SCMP_ARCH_MIPSEL64N32", SCMP_ARCH_MIPSEL64N32 }, { "SCMP_ARCH_NATIVE", SCMP_ARCH_NATIVE }, -#ifdef SCMP_ARCH_PARISC { "SCMP_ARCH_PARISC", SCMP_ARCH_PARISC }, -#endif -#ifdef SCMP_ARCH_PARISC64 { "SCMP_ARCH_PARISC64", SCMP_ARCH_PARISC64 }, -#endif { "SCMP_ARCH_PPC", SCMP_ARCH_PPC }, { "SCMP_ARCH_PPC64", SCMP_ARCH_PPC64 }, { "SCMP_ARCH_PPC64LE", SCMP_ARCH_PPC64LE }, diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index c3eb9049e8d14..5719693a4fdb9 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -129,10 +129,10 @@ uint32_t seccomp_local_archs[] = { SCMP_ARCH_MIPSEL64, SCMP_ARCH_MIPS64N32, SCMP_ARCH_MIPSEL64N32, /* native */ -#elif defined(__hppa64__) && defined(SCMP_ARCH_PARISC) && defined(SCMP_ARCH_PARISC64) +#elif defined(__hppa64__) SCMP_ARCH_PARISC, SCMP_ARCH_PARISC64, /* native */ -#elif defined(__hppa__) && defined(SCMP_ARCH_PARISC) +#elif defined(__hppa__) SCMP_ARCH_PARISC, #elif defined(__powerpc64__) && __BYTE_ORDER == __BIG_ENDIAN SCMP_ARCH_PPC, @@ -190,14 +190,10 @@ const char* seccomp_arch_to_string(uint32_t c) { return "mips64-le"; case SCMP_ARCH_MIPSEL64N32: return "mips64-le-n32"; -#ifdef SCMP_ARCH_PARISC case SCMP_ARCH_PARISC: return "parisc"; -#endif -#ifdef SCMP_ARCH_PARISC64 case SCMP_ARCH_PARISC64: return "parisc64"; -#endif case SCMP_ARCH_PPC: return "ppc"; case SCMP_ARCH_PPC64: @@ -251,14 +247,10 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) { *ret = SCMP_ARCH_MIPSEL64; else if (streq(n, "mips64-le-n32")) *ret = SCMP_ARCH_MIPSEL64N32; -#ifdef SCMP_ARCH_PARISC else if (streq(n, "parisc")) *ret = SCMP_ARCH_PARISC; -#endif -#ifdef SCMP_ARCH_PARISC64 else if (streq(n, "parisc64")) *ret = SCMP_ARCH_PARISC64; -#endif else if (streq(n, "ppc")) *ret = SCMP_ARCH_PPC; else if (streq(n, "ppc64")) @@ -1159,10 +1151,8 @@ static uint32_t override_default_action(uint32_t default_action) { if (default_action == SCMP_ACT_ALLOW) return default_action; -#ifdef SCMP_ACT_LOG if (default_action == SCMP_ACT_LOG) return default_action; -#endif return SCMP_ACT_ERRNO(ENOSYS); } @@ -1264,11 +1254,9 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter int error = PTR_TO_INT(val); if (error == SECCOMP_ERROR_NUMBER_KILL) - a = scmp_act_kill_process(); -#ifdef SCMP_ACT_LOG + a = SCMP_ACT_KILL_PROCESS; else if (action == SCMP_ACT_LOG) a = SCMP_ACT_LOG; -#endif else if (error >= 0) a = SCMP_ACT_ERRNO(error); @@ -1677,12 +1665,8 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) { case SCMP_ARCH_X86: case SCMP_ARCH_MIPSEL: case SCMP_ARCH_MIPS: -#ifdef SCMP_ARCH_PARISC case SCMP_ARCH_PARISC: -#endif -#ifdef SCMP_ARCH_PARISC64 case SCMP_ARCH_PARISC64: -#endif case SCMP_ARCH_PPC: case SCMP_ARCH_PPC64: case SCMP_ARCH_PPC64LE: @@ -2488,21 +2472,6 @@ int seccomp_restrict_suid_sgid(void) { return 0; } -uint32_t scmp_act_kill_process(void) { - - /* Returns SCMP_ACT_KILL_PROCESS if it's supported, and SCMP_ACT_KILL_THREAD otherwise. We never - * actually want to use SCMP_ACT_KILL_THREAD as its semantics are nuts (killing arbitrary threads of - * a program is just a bad idea), but on old kernels/old libseccomp it is all we have, and at least - * for single-threaded apps does the right thing. */ - -#ifdef SCMP_ACT_KILL_PROCESS - if (dlopen_libseccomp() >= 0 && sym_seccomp_api_get() >= 3) - return SCMP_ACT_KILL_PROCESS; -#endif - - return SCMP_ACT_KILL; /* same as SCMP_ACT_KILL_THREAD */ -} - int parse_syscall_and_errno(const char *in, char **name, int *error) { _cleanup_free_ char *n = NULL; const char *p; diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 871135c85be41..51c2ba650501b 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -153,9 +153,6 @@ _DEFINE_ABS_WRAPPER(SECCOMP_FATAL); DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(scmp_filter_ctx, sym_seccomp_release, seccomp_releasep, NULL); int parse_syscall_archs(char **l, Set **ret_archs); - -uint32_t scmp_act_kill_process(void); - int parse_syscall_and_errno(const char *in, char **name, int *error); int seccomp_suppress_sync(void); diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 81eed6d89d698..fa05eecb95ad6 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -682,7 +682,7 @@ TEST(load_syscall_filter_set_raw) { assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL_PROCESS, true) >= 0); assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); @@ -791,7 +791,7 @@ TEST(native_syscalls_filtered) { assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); - assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, scmp_act_kill_process(), true) >= 0); + assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, NULL, SCMP_ACT_KILL_PROCESS, true) >= 0); assert_se(access("/", F_OK) >= 0); assert_se(poll(NULL, 0, 0) == 0); From 5863641bb718777c289d3693bfa9bddd8ffc32b6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 17 Aug 2025 23:03:44 +0900 Subject: [PATCH 06/12] Require libxcrypt-4.4.0 or newer and drop support of libcrypt libcrypt was no longer built by default since glibc-2.38, and it has been completely removed since glibc-2.39. Let's always use libxcrypt, unless when building with musl. As already major distribution already have libxcrypt-4.4.x, hence let's also bump the required minimum version to 4.4.0. libxcrypt cannot be built with musl, hence the previous fallback logic in libcrypt-util.c are moved to musl/crypt.c. Note, libxcrypt-4.4.0 was released on 2018-11-20. See also #38608. --- README | 2 +- meson.build | 21 ++----- src/include/musl/crypt.h | 13 ++++ src/libc/musl/crypt.c | 111 ++++++++++++++++++++++++++++++++++ src/libc/musl/meson.build | 1 + src/shared/libcrypt-util.c | 98 +----------------------------- src/test/test-libcrypt-util.c | 15 +---- 7 files changed, 135 insertions(+), 126 deletions(-) create mode 100644 src/include/musl/crypt.h create mode 100644 src/libc/musl/crypt.c diff --git a/README b/README index 83493b041776a..0fd153bebbbfc 100644 --- a/README +++ b/README @@ -212,7 +212,7 @@ REQUIREMENTS: newer though. TL;DR: turn audit off, still. glibc >= 2.31 - libxcrypt or glibc (<= 2.38 built with --enable-crypt) + libxcrypt >= 4.4.0 libmount >= 2.30 (from util-linux) (util-linux *must* be built without --enable-libmount-support-mtab) libseccomp >= 2.4.0 (optional) diff --git a/meson.build b/meson.build index cc26bbd63e2f6..cf23ed51efee5 100644 --- a/meson.build +++ b/meson.build @@ -1046,23 +1046,14 @@ else libatomic = [] endif -libcrypt = dependency('libcrypt', 'libxcrypt', required : false) -if not libcrypt.found() - # fallback to use find_library() if libcrypt is provided by glibc, e.g. for LibreELEC. - libcrypt = cc.find_library('crypt') +if get_option('libc') == 'musl' + libcrypt = [] +else + libcrypt = dependency('libcrypt', 'libxcrypt', + required : true, + version : '>=4.4.0') endif -foreach func : [ - 'crypt_ra', # since libxcrypt-4.0.0 - 'crypt_gensalt_ra', # since libxcrypt-4.0.0 - 'crypt_preferred_method', # since libxcrypt-4.4.0 -] - - have = cc.has_function(func, prefix : '''#include ''', args : '-D_GNU_SOURCE', - dependencies : libcrypt) - conf.set10('HAVE_' + func.to_upper(), have) -endforeach - bpf_framework = get_option('bpf-framework') bpf_compiler = get_option('bpf-compiler') libbpf = dependency('libbpf', diff --git a/src/include/musl/crypt.h b/src/include/musl/crypt.h new file mode 100644 index 0000000000000..64570f7046075 --- /dev/null +++ b/src/include/musl/crypt.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +const char* missing_crypt_preferred_method(void); +#define crypt_preferred_method missing_crypt_preferred_method + +char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes); +#define crypt_gensalt_ra missing_crypt_gensalt_ra + +char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size); +#define crypt_ra missing_crypt_ra diff --git a/src/libc/musl/crypt.c b/src/libc/musl/crypt.c new file mode 100644 index 0000000000000..d44113fdc6e40 --- /dev/null +++ b/src/libc/musl/crypt.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include + +const char* missing_crypt_preferred_method(void) { + return "$6$"; +} + +char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes) { + static const char table[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "./"; + + static_assert(sizeof(table) == 64U + 1U); + + /* This doesn't do anything but SHA512, and silently ignore all arguments, to make it legacy-free and + * minimize the implementation. */ + + /* Insist on the best randomness by getrandom(), this is about keeping passwords secret after all. */ + uint8_t raw[16]; + for (size_t i = 0; i < sizeof(raw);) { + size_t n = sizeof(raw) - i; + ssize_t l = getrandom(raw + i, n, 0); + if (l < 0) + return NULL; + if (l == 0) { + /* Weird, should never happen. */ + errno = EIO; + return NULL; + } + + if ((size_t) l == n) + break; /* Done reading, success. */ + + i += l; + /* Interrupted by a signal; keep going. */ + } + + /* "$6$" + salt + "$" + NUL */ + char *salt = malloc(3 + sizeof(raw) + 1 + 1); + if (!salt) { + errno = ENOMEM; + return NULL; + } + + /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ + char *p = stpcpy(salt, "$6$"); + for (size_t i = 0; i < sizeof(raw); i++) + *p++ = table[raw[i] & 63]; + *p++ = '$'; + *p = '\0'; + + return salt; +} + +char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size) { + struct crypt_data *buf = NULL; + bool allocated = false; + + if (!phrase || !setting || !data || !size) { + errno = EINVAL; + return NULL; + } + + if (*data) { + if (*size != sizeof(struct crypt_data)) { + errno = EINVAL; + return NULL; + } + + buf = *data; + } else { + if (*size != 0) { + errno = EINVAL; + return NULL; + } + + buf = calloc(1, sizeof(struct crypt_data)); + if (!buf) { + errno = ENOMEM; + return NULL; + } + + allocated = true; + } + + /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on + * error, so let's just return that. */ + + char *t = crypt_r(phrase, setting, buf); + if (!t || t[0] == '*') { + if (allocated) + free(buf); + return NULL; + } + + if (allocated) { + *data = buf; + *size = sizeof(struct crypt_data); + } + return t; +} diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index d40a2f19115ef..4fabac7bcc9df 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -5,6 +5,7 @@ if get_option('libc') != 'musl' endif libc_wrapper_sources += files( + 'crypt.c', 'getopt.c', 'printf.c', 'stdio.c', diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index 26e907f866d96..6910c5f5276a0 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -1,33 +1,23 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include #include "alloc-util.h" #include "errno-util.h" #include "libcrypt-util.h" #include "log.h" -#include "random-util.h" /* IWYU pragma: keep */ #include "string-util.h" #include "strv.h" int make_salt(char **ret) { - assert(ret); - -#if HAVE_CRYPT_GENSALT_RA const char *e; char *salt; - /* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt). - * crypt_gensalt_ra() is usually provided by libxcrypt. */ + assert(ret); e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); if (!e) -#if HAVE_CRYPT_PREFERRED_METHOD e = crypt_preferred_method(); -#else - e = "$6$"; -#endif log_debug("Generating salt for hash prefix: %s", e); @@ -37,91 +27,8 @@ int make_salt(char **ret) { *ret = salt; return 0; -#else - /* If crypt_gensalt_ra() is not available, we use SHA512 and generate the salt on our own. */ - - static const char table[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - "./"; - - uint8_t raw[16]; - char *salt, *j; - size_t i; - int r; - - /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but - * SHA512, i.e. is legacy-free and minimizes our deps. */ - - assert_cc(sizeof(table) == 64U + 1U); - - log_debug("Generating fallback salt for hash prefix: $6$"); - - /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ - r = crypto_random_bytes(raw, sizeof(raw)); - if (r < 0) - return r; - - salt = new(char, 3+sizeof(raw)+1+1); - if (!salt) - return -ENOMEM; - - /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ - j = stpcpy(salt, "$6$"); - for (i = 0; i < sizeof(raw); i++) - j[i] = table[raw[i] & 63]; - j[i++] = '$'; - j[i] = 0; - - *ret = salt; - return 0; -#endif -} - -#if HAVE_CRYPT_RA -# define CRYPT_RA_NAME "crypt_ra" -#else -# define CRYPT_RA_NAME "crypt_r" - -/* Provide a poor man's fallback that uses a fixed size buffer. */ - -static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) { - assert(phrase); - assert(setting); - assert(data); - assert(size); - - /* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this - * implementation of libcrypt; over 128kB in some other implementations). This is large enough that - * it may be unwise to allocate it on the stack. */ - - if (!*data) { - *data = new0(struct crypt_data, 1); - if (!*data) { - errno = ENOMEM; - return NULL; - } - - *size = (int) (sizeof(struct crypt_data)); - } - - char *t = crypt_r(phrase, setting, *data); - if (!t) - return NULL; - - /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on - * error, so let's just return that. */ - if (t[0] == '*') - return NULL; - - return t; } -#define crypt_ra systemd_crypt_ra - -#endif - int hash_password(const char *password, char **ret) { _cleanup_free_ char *salt = NULL; _cleanup_(erase_and_freep) void *cd_data = NULL; @@ -138,8 +45,7 @@ int hash_password(const char *password, char **ret) { errno = 0; p = crypt_ra(password, salt, &cd_data, &cd_size); if (!p) - return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), - CRYPT_RA_NAME "() failed: %m"); + return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), "crypt_ra() failed: %m"); return strdup_to(ret, p); } diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c index 9f171a2415a29..92142fc9efae5 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -7,13 +7,7 @@ #include "tests.h" TEST(crypt_preferred_method) { - log_info("crypt_preferred_method: %s", -#if HAVE_CRYPT_PREFERRED_METHOD - crypt_preferred_method() -#else - "(not available)" -#endif - ); + log_info("crypt_preferred_method: %s", crypt_preferred_method()); } TEST(make_salt) { @@ -31,10 +25,6 @@ TEST(make_salt) { } TEST(hash_password) { -#if defined(__powerpc__) && !defined(XCRYPT_VERSION_MAJOR) - return log_tests_skipped("crypt_r() causes a buffer overflow on ppc64el, see https://github.com/systemd/systemd/pull/16981#issuecomment-691203787"); -#endif - /* As a warm-up exercise, check if we can hash passwords. */ FOREACH_STRING(hash, "ew3bU1.hoKk4o", @@ -50,9 +40,6 @@ TEST(hash_password) { ASSERT_OK_ZERO(test_password_one(hash, "ppp")); continue; } -#elif !defined(XCRYPT_VERSION_MAJOR) - ASSERT_OK(test_password_one(hash, "ppp")); - continue; #endif ASSERT_OK_POSITIVE(test_password_one(hash, "ppp")); } From 8de783a288912a13b65ca269f01f3bc912d1aedb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 25 Oct 2025 14:59:54 +0900 Subject: [PATCH 07/12] libcrypt: allow to build systemd without libcrypt/libxcrypt libcrypt is only used by firstboot, homed, and sysusers, which can be disabled by meson option. Let's not require the library unconditionally. --- meson.build | 18 +++++++----------- meson_options.txt | 2 ++ src/shared/libcrypt-util.c | 6 +++++- src/shared/libcrypt-util.h | 9 +++++++++ src/test/meson.build | 1 + 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/meson.build b/meson.build index cf23ed51efee5..4f98dbd9da50b 100644 --- a/meson.build +++ b/meson.build @@ -685,15 +685,6 @@ conf.set('GPERF_LEN_TYPE', gperf_len_type, ##################################################################### -foreach header : [ - 'crypt.h', -] - - if not cc.has_header(header) - error(f'Header file @header@ not found') - endif -endforeach - foreach header : [ 'gshadow.h', 'nss.h', @@ -1048,11 +1039,14 @@ endif if get_option('libc') == 'musl' libcrypt = [] + have = get_option('libcrypt').allowed() else libcrypt = dependency('libcrypt', 'libxcrypt', - required : true, + required : get_option('libcrypt'), version : '>=4.4.0') + have = libcrypt.found() endif +conf.set10('HAVE_LIBCRYPT', have) bpf_framework = get_option('bpf-framework') bpf_compiler = get_option('bpf-compiler') @@ -1585,10 +1579,11 @@ conf.set10('ENABLE_SYSUPDATED', have2) conf.set10('ENABLE_STORAGETM', get_option('storagetm')) have = get_option('homed').require( + conf.get('HAVE_LIBCRYPT') == 1 and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_LIBFDISK') == 1 and conf.get('HAVE_LIBCRYPTSETUP') == 1, - error_message : 'openssl, fdisk and libcryptsetup required').allowed() + error_message : 'libcrypt, openssl, fdisk, and libcryptsetup required').allowed() conf.set10('ENABLE_HOMED', have) have = have and conf.get('HAVE_PAM') == 1 @@ -3115,6 +3110,7 @@ foreach tuple : [ ['gnutls'], ['libarchive'], ['libbpf'], + ['libcrypt'], ['libcryptsetup'], ['libcryptsetup-plugins'], ['libcurl'], diff --git a/meson_options.txt b/meson_options.txt index 4ce3c7faca0b3..5061869483b78 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -426,6 +426,8 @@ option('pwquality', type : 'feature', deprecated : { 'true' : 'enabled', 'false' description : 'libpwquality support') option('microhttpd', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libµhttpd support') +option('libcrypt', type : 'feature', + description : 'libcrypt/libxcrypt support') option('libcryptsetup', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libcryptsetup support') option('libcryptsetup-plugins', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index 6910c5f5276a0..e8b0b72e35394 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include +#if HAVE_LIBCRYPT +# include +#endif #include "alloc-util.h" #include "errno-util.h" @@ -9,6 +11,7 @@ #include "string-util.h" #include "strv.h" +#if HAVE_LIBCRYPT int make_salt(char **ret) { const char *e; char *salt; @@ -85,6 +88,7 @@ int test_password_many(char **hashed_password, const char *password) { return false; } +#endif bool looks_like_hashed_password(const char *s) { /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index e80cfcaf4e21f..626668c710faa 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -3,8 +3,17 @@ #include "shared-forward.h" +#if HAVE_LIBCRYPT int make_salt(char **ret); int hash_password(const char *password, char **ret); int test_password_one(const char *hashed_password, const char *password); int test_password_many(char **hashed_password, const char *password); + +#else + +static inline int hash_password(const char *password, char **ret) { + return -EOPNOTSUPP; +} +#endif + bool looks_like_hashed_password(const char *s); diff --git a/src/test/meson.build b/src/test/meson.build index a21f85c2ecb27..7b77f3bd587e8 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -346,6 +346,7 @@ executables += [ test_template + { 'sources' : files('test-libcrypt-util.c'), 'dependencies' : libcrypt, + 'conditions' : ['HAVE_LIBCRYPT'], 'timeout' : 120, }, test_template + { From d0b224f845ce001a28d8e8c77410732617ab5b65 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 25 Oct 2025 13:41:33 +0900 Subject: [PATCH 08/12] libcrypt-util: turn into dlopen() dependency Note, this drops logging only test case for crypt_preferred_method(), as that requires explicitly dlopen() the library. But, we should test that make_salt() and friends automatically dlopen() it. --- README | 2 +- meson.build | 2 + src/firstboot/meson.build | 1 - src/home/meson.build | 4 -- src/shared/libcrypt-util.c | 75 ++++++++++++++++++++++++++++++++--- src/shared/libcrypt-util.h | 4 ++ src/shared/meson.build | 2 +- src/test/meson.build | 1 - src/test/test-dlopen-so.c | 2 + src/test/test-libcrypt-util.c | 6 --- 10 files changed, 80 insertions(+), 19 deletions(-) diff --git a/README b/README index 0fd153bebbbfc..2d6d30dc78e11 100644 --- a/README +++ b/README @@ -212,7 +212,7 @@ REQUIREMENTS: newer though. TL;DR: turn audit off, still. glibc >= 2.31 - libxcrypt >= 4.4.0 + libxcrypt >= 4.4.0 (optional) libmount >= 2.30 (from util-linux) (util-linux *must* be built without --enable-libmount-support-mtab) libseccomp >= 2.4.0 (optional) diff --git a/meson.build b/meson.build index 4f98dbd9da50b..ff8cb279a8e32 100644 --- a/meson.build +++ b/meson.build @@ -1039,11 +1039,13 @@ endif if get_option('libc') == 'musl' libcrypt = [] + libcrypt_cflags = [] have = get_option('libcrypt').allowed() else libcrypt = dependency('libcrypt', 'libxcrypt', required : get_option('libcrypt'), version : '>=4.4.0') + libcrypt_cflags = libcrypt.partial_dependency(includes: true, compile_args: true) have = libcrypt.found() endif conf.set10('HAVE_LIBCRYPT', have) diff --git a/src/firstboot/meson.build b/src/firstboot/meson.build index 28c1d2703a865..e83eded6ada96 100644 --- a/src/firstboot/meson.build +++ b/src/firstboot/meson.build @@ -6,6 +6,5 @@ executables += [ 'public' : true, 'conditions' : ['ENABLE_FIRSTBOOT'], 'sources' : files('firstboot.c'), - 'dependencies' : libcrypt, }, ] diff --git a/src/home/meson.build b/src/home/meson.build index dbb374ce4a124..1efee1619ef9c 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -64,7 +64,6 @@ executables += [ 'sources' : systemd_homed_sources, 'extract' : systemd_homed_extract_sources, 'dependencies' : [ - libcrypt, libm, libopenssl, threads, @@ -80,7 +79,6 @@ executables += [ ], 'dependencies' : [ libblkid_cflags, - libcrypt, libfdisk, libopenssl, libp11kit_cflags, @@ -93,7 +91,6 @@ executables += [ 'sources' : homectl_sources, 'objects' : ['systemd-homed'], 'dependencies' : [ - libcrypt, libdl, libopenssl, libp11kit_cflags, @@ -112,7 +109,6 @@ modules += [ 'conditions' : ['HAVE_PAM'], 'sources' : pam_systemd_home_sources, 'dependencies' : [ - libcrypt, libintl, libpam_misc, libpam, diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index e8b0b72e35394..85069314be497 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -5,6 +5,7 @@ #endif #include "alloc-util.h" +#include "dlfcn-util.h" #include "errno-util.h" #include "libcrypt-util.h" #include "log.h" @@ -12,19 +13,79 @@ #include "strv.h" #if HAVE_LIBCRYPT +static void *libcrypt_dl = NULL; + +static DLSYM_PROTOTYPE(crypt_gensalt_ra) = NULL; +static DLSYM_PROTOTYPE(crypt_preferred_method) = NULL; +static DLSYM_PROTOTYPE(crypt_ra) = NULL; + +int dlopen_libcrypt(void) { +#ifdef __GLIBC__ + static int cached = 0; + int r; + + if (libcrypt_dl) + return 0; /* Already loaded */ + + if (cached < 0) + return cached; /* Already tried, and failed. */ + + /* Several distributions like Debian/Ubuntu and OpenSUSE provide libxcrypt as libcrypt.so.1, + * while others like Fedora/CentOS and Arch provide it as libcrypt.so.2. */ + ELF_NOTE_DLOPEN("crypt", + "Support for hashing passwords", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libcrypt.so.2", "libcrypt.so.1"); + + _cleanup_(dlclosep) void *dl = NULL; + r = dlopen_safe("libcrypt.so.2", &dl, /* reterr_dlerror= */ NULL); + if (r < 0) { + const char *dle = NULL; + r = dlopen_safe("libcrypt.so.1", &dl, &dle); + if (r < 0) { + log_debug_errno(r, "libcrypt.so.2/libcrypt.so.1 is not available: %s", dle ?: STRERROR(r)); + return (cached = -EOPNOTSUPP); /* turn into recognizable error */ + } + log_debug("Loaded 'libcrypt.so.1' via dlopen()"); + } else + log_debug("Loaded 'libcrypt.so.2' via dlopen()"); + + r = dlsym_many_or_warn( + dl, LOG_DEBUG, + DLSYM_ARG(crypt_gensalt_ra), + DLSYM_ARG(crypt_preferred_method), + DLSYM_ARG(crypt_ra)); + if (r < 0) + return (cached = r); + + libcrypt_dl = TAKE_PTR(dl); +#else + libcrypt_dl = NULL; + sym_crypt_gensalt_ra = missing_crypt_gensalt_ra; + sym_crypt_preferred_method = missing_crypt_preferred_method; + sym_crypt_ra = missing_crypt_ra; +#endif + return 0; +} + int make_salt(char **ret) { const char *e; char *salt; + int r; assert(ret); + r = dlopen_libcrypt(); + if (r < 0) + return r; + e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); if (!e) - e = crypt_preferred_method(); + e = sym_crypt_preferred_method(); log_debug("Generating salt for hash prefix: %s", e); - salt = crypt_gensalt_ra(e, 0, NULL, 0); + salt = sym_crypt_gensalt_ra(e, 0, NULL, 0); if (!salt) return -errno; @@ -46,7 +107,7 @@ int hash_password(const char *password, char **ret) { return log_debug_errno(r, "Failed to generate salt: %m"); errno = 0; - p = crypt_ra(password, salt, &cd_data, &cd_size); + p = sym_crypt_ra(password, salt, &cd_data, &cd_size); if (!p) return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), "crypt_ra() failed: %m"); @@ -55,14 +116,18 @@ int hash_password(const char *password, char **ret) { int test_password_one(const char *hashed_password, const char *password) { _cleanup_(erase_and_freep) void *cd_data = NULL; - int cd_size = 0; + int r, cd_size = 0; const char *k; assert(hashed_password); assert(password); + r = dlopen_libcrypt(); + if (r < 0) + return r; + errno = 0; - k = crypt_ra(password, hashed_password, &cd_data, &cd_size); + k = sym_crypt_ra(password, hashed_password, &cd_data, &cd_size); if (!k) { if (errno == ENOMEM) return -ENOMEM; diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index 626668c710faa..3f79916cbc0be 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -4,6 +4,7 @@ #include "shared-forward.h" #if HAVE_LIBCRYPT +int dlopen_libcrypt(void); int make_salt(char **ret); int hash_password(const char *password, char **ret); int test_password_one(const char *hashed_password, const char *password); @@ -11,6 +12,9 @@ int test_password_many(char **hashed_password, const char *password); #else +static inline int dlopen_libcrypt(void) { + return -EOPNOTSUPP; +} static inline int hash_password(const char *password, char **ret) { return -EOPNOTSUPP; } diff --git a/src/shared/meson.build b/src/shared/meson.build index e0b86e0b81ce1..36d38f4ed9e02 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -367,7 +367,7 @@ libshared_deps = [threads, libaudit_cflags, libblkid_cflags, libbpf_cflags, - libcrypt, + libcrypt_cflags, libcryptsetup_cflags, libdl, libdw_cflags, diff --git a/src/test/meson.build b/src/test/meson.build index 7b77f3bd587e8..6a26eb3f87ce5 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -345,7 +345,6 @@ executables += [ }, test_template + { 'sources' : files('test-libcrypt-util.c'), - 'dependencies' : libcrypt, 'conditions' : ['HAVE_LIBCRYPT'], 'timeout' : 120, }, diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 47b8470ffb588..10b8da1e9ca5c 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -11,6 +11,7 @@ #include "idn-util.h" #include "libarchive-util.h" #include "libaudit-util.h" +#include "libcrypt-util.h" #include "libfido2-util.h" #include "libmount-util.h" #include "main-func.h" @@ -52,6 +53,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libarchive, HAVE_LIBARCHIVE); ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT); ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID); + ASSERT_DLOPEN(dlopen_libcrypt, HAVE_LIBCRYPT); ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2); ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD); ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT); diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c index 92142fc9efae5..792b2b2ef9026 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -1,15 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "libcrypt-util.h" #include "strv.h" #include "tests.h" -TEST(crypt_preferred_method) { - log_info("crypt_preferred_method: %s", crypt_preferred_method()); -} - TEST(make_salt) { _cleanup_strv_free_ char **l = NULL; From fe3c790f71f3e8d6920e1fca4eff2a87efe9811c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Jan 2026 06:03:27 +0900 Subject: [PATCH 09/12] tools: allow to run setup-musl-build.sh for already set up directory --- tools/setup-musl-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/setup-musl-build.sh b/tools/setup-musl-build.sh index b0fa764fe414d..9b769b62f3d54 100755 --- a/tools/setup-musl-build.sh +++ b/tools/setup-musl-build.sh @@ -63,6 +63,7 @@ LINKS=( zstd_errors.h ) +rm -rf "${SETUP_DIR}" for t in "${LINKS[@]}"; do [[ -e /usr/include/"$t" ]] link="${SETUP_DIR}/usr/include/${t}" @@ -82,4 +83,4 @@ env \ CXX=musl-gcc \ CFLAGS="$CFLAGS" \ CXXFLAGS="$CFLAGS" \ - meson setup -Ddbus-interfaces-dir=no -Dlibc=musl "${BUILD_DIR}" "${@}" + meson setup --reconfigure -Ddbus-interfaces-dir=no -Dlibc=musl "${BUILD_DIR}" "${@}" From 6d2c9c220309dca86834b8bd55a2999b1290dfb1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Jan 2026 06:09:39 +0900 Subject: [PATCH 10/12] tools: show each command to make it easier to debug --- tools/setup-musl-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/setup-musl-build.sh b/tools/setup-musl-build.sh index 9b769b62f3d54..f51538f4435c2 100755 --- a/tools/setup-musl-build.sh +++ b/tools/setup-musl-build.sh @@ -6,7 +6,7 @@ # E.g. # tools/setup-musl-build.sh build-musl -Dbuildtype=debugoptimized && ninja -C build-musl -set -eu +set -eux BUILD_DIR="${1:?}" shift From 2553c53730e3f4ea63c9a5e5c52db2f8b0cbf696 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 2 Jan 2026 06:20:17 +0900 Subject: [PATCH 11/12] tools: drop unnecessary sys/capability.h header After 9b414a38fadb41c9ea056ed5d284ab5098251a37 (#39425), the header is not required. And after b295c166f94526aae830893612a1584840f2f087, the header is not installed in CI environments. --- tools/setup-musl-build.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/setup-musl-build.sh b/tools/setup-musl-build.sh index f51538f4435c2..d264cc7bd5fd8 100755 --- a/tools/setup-musl-build.sh +++ b/tools/setup-musl-build.sh @@ -53,7 +53,6 @@ LINKS=( security selinux sys/acl.h - sys/capability.h tss2 xen xkbcommon From 944ae1286b6e901505bec809cfbb75093a0b9320 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 19 Dec 2025 19:43:21 +0100 Subject: [PATCH 12/12] tree-wide: Use pamh as pam_handle_t parameter name libpam uses pamh in its function declarations for the plugin API so let's use the same name in our tree as well. Making sure the plugin function definitions match the plugin function declarations is required to enable clang-tidy's readability-inconsistent-declaration-parameter-name check, but to keep things consistent everywhere we opt to use pamh tree-wide. --- src/core/exec-invoke.c | 46 +-- src/home/pam_systemd_home.c | 425 ++++++++++++++-------------- src/login/pam_systemd.c | 487 ++++++++++++++++---------------- src/login/pam_systemd_loadkey.c | 28 +- src/shared/pam-util.c | 92 +++--- src/shared/pam-util.h | 30 +- 6 files changed, 547 insertions(+), 561 deletions(-) diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 4adf8d00ce8b9..1fa20d6763067 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -1192,18 +1192,18 @@ static int ask_password_conv( return PAM_SUCCESS; } -static int pam_close_session_and_delete_credentials(pam_handle_t *handle, int flags) { +static int pam_close_session_and_delete_credentials(pam_handle_t *pamh, int flags) { int r, s; - assert(handle); + assert(pamh); - r = sym_pam_close_session(handle, flags); + r = sym_pam_close_session(pamh, flags); if (r != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_DEBUG, r, "pam_close_session() failed: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_DEBUG, r, "pam_close_session() failed: @PAMERR@"); - s = sym_pam_setcred(handle, PAM_DELETE_CRED | flags); + s = sym_pam_setcred(pamh, PAM_DELETE_CRED | flags); if (s != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_DEBUG, r, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_DEBUG, r, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@"); return r != PAM_SUCCESS ? r : s; } @@ -1339,7 +1339,7 @@ static int setup_pam( _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_strv_free_ char **e = NULL; _cleanup_free_ char *tty = NULL; - pam_handle_t *handle = NULL; + pam_handle_t *pamh = NULL; sigset_t old_ss; int pam_code = PAM_SUCCESS, r; bool close_session = false; @@ -1369,9 +1369,9 @@ static int setup_pam( if (log_get_max_level() < LOG_DEBUG) flags |= PAM_SILENT; - pam_code = sym_pam_start(context->pam_name, user, &conv, &handle); + pam_code = sym_pam_start(context->pam_name, user, &conv, &pamh); if (pam_code != PAM_SUCCESS) { - handle = NULL; + pamh = NULL; goto fail; } @@ -1379,32 +1379,32 @@ static int setup_pam( if (r < 0) goto fail; if (r > 0) { - pam_code = sym_pam_set_item(handle, PAM_TTY, tty); + pam_code = sym_pam_set_item(pamh, PAM_TTY, tty); if (pam_code != PAM_SUCCESS) goto fail; } STRV_FOREACH(nv, *env) { - pam_code = sym_pam_putenv(handle, *nv); + pam_code = sym_pam_putenv(pamh, *nv); if (pam_code != PAM_SUCCESS) goto fail; } - pam_code = sym_pam_acct_mgmt(handle, flags); + pam_code = sym_pam_acct_mgmt(pamh, flags); if (pam_code != PAM_SUCCESS) goto fail; - pam_code = sym_pam_setcred(handle, PAM_ESTABLISH_CRED | flags); + pam_code = sym_pam_setcred(pamh, PAM_ESTABLISH_CRED | flags); if (pam_code != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_DEBUG, pam_code, "pam_setcred(PAM_ESTABLISH_CRED) failed, ignoring: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_DEBUG, pam_code, "pam_setcred(PAM_ESTABLISH_CRED) failed, ignoring: @PAMERR@"); - pam_code = sym_pam_open_session(handle, flags); + pam_code = sym_pam_open_session(pamh, flags); if (pam_code != PAM_SUCCESS) goto fail; close_session = true; - e = sym_pam_getenvlist(handle); + e = sym_pam_getenvlist(pamh); if (!e) { pam_code = PAM_BUF_ERR; goto fail; @@ -1479,7 +1479,7 @@ static int setup_pam( /* If our parent died we'll end the session */ if (getppid() != parent_pid) { - pam_code = pam_close_session_and_delete_credentials(handle, flags); + pam_code = pam_close_session_and_delete_credentials(pamh, flags); if (pam_code != PAM_SUCCESS) goto child_finish; } @@ -1489,7 +1489,7 @@ static int setup_pam( child_finish: /* NB: pam_end() when called in child processes should set PAM_DATA_SILENT to let the module * know about this. See pam_end(3) */ - (void) sym_pam_end(handle, pam_code | flags | PAM_DATA_SILENT); + (void) sym_pam_end(pamh, pam_code | flags | PAM_DATA_SILENT); _exit(ret); } @@ -1497,7 +1497,7 @@ static int setup_pam( /* If the child was forked off successfully it will do all the cleanups, so forget about the handle * here. */ - handle = NULL; + pamh = NULL; /* Unblock SIGTERM again in the parent */ assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0); @@ -1515,16 +1515,16 @@ static int setup_pam( fail: if (pam_code != PAM_SUCCESS) { - pam_syslog_pam_error(handle, LOG_ERR, pam_code, "PAM failed: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_ERR, pam_code, "PAM failed: @PAMERR@"); r = -EPERM; /* PAM errors do not map to errno */ } else log_error_errno(r, "PAM failed: %m"); - if (handle) { + if (pamh) { if (close_session) - pam_code = pam_close_session_and_delete_credentials(handle, flags); + pam_code = pam_close_session_and_delete_credentials(pamh, flags); - (void) sym_pam_end(handle, pam_code | flags); + (void) sym_pam_end(pamh, pam_code | flags); } closelog(); diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index 54702a53ecc8d..c9891af697551 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -29,7 +29,7 @@ typedef enum AcquireHomeFlags { } AcquireHomeFlags; static int parse_argv( - pam_handle_t *handle, + pam_handle_t *pamh, int argc, const char **argv, AcquireHomeFlags *flags, bool *debug) { @@ -45,7 +45,7 @@ static int parse_argv( k = parse_boolean(v); if (k < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse suspend= argument, ignoring: %s", v); + pam_syslog(pamh, LOG_WARNING, "Failed to parse suspend= argument, ignoring: %s", v); else if (flags) SET_FLAG(*flags, ACQUIRE_PLEASE_SUSPEND, k); @@ -57,21 +57,18 @@ static int parse_argv( int k; k = parse_boolean(v); if (k < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", v); + pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", v); else if (debug) *debug = k; } else - pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } return 0; } -static int parse_env( - pam_handle_t *handle, - AcquireHomeFlags *flags) { - +static int parse_env(pam_handle_t *pamh, AcquireHomeFlags *flags) { const char *v; int r; @@ -79,7 +76,7 @@ static int parse_env( * easy to declare the features of a display manager in code rather than configuration, and this is * really a feature of code */ - v = pam_getenv(handle, "SYSTEMD_HOME_SUSPEND"); + v = pam_getenv(pamh, "SYSTEMD_HOME_SUSPEND"); if (!v) { /* Also check the process env block, so that people can control this via an env var from the * outside of our process. */ @@ -90,7 +87,7 @@ static int parse_env( r = parse_boolean(v); if (r < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v); + pam_syslog(pamh, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v); else if (flags) SET_FLAG(*flags, ACQUIRE_PLEASE_SUSPEND, r); @@ -98,7 +95,7 @@ static int parse_env( } static int acquire_user_record( - pam_handle_t *handle, + pam_handle_t *pamh, const char *username, bool debug, UserRecord **ret_record, @@ -106,14 +103,14 @@ static int acquire_user_record( int r; - assert(handle); + assert(pamh); if (!username) { - r = pam_get_user(handle, &username, NULL); + r = pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get user name: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); } /* Possibly split out the area name */ @@ -122,12 +119,12 @@ static int acquire_user_record( if (carea && (filename_is_valid(carea + 1) || isempty(carea + 1))) { username_without_area = strndup(username, carea - username); if (!username_without_area) - return pam_log_oom(handle); + return pam_log_oom(pamh); username = username_without_area; area = strdup(carea + 1); if (!area) - return pam_log_oom(handle); + return pam_log_oom(pamh); } /* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for @@ -149,12 +146,12 @@ static int acquire_user_record( * caching separate. */ _cleanup_free_ char *homed_field = strjoin("systemd-home-user-record-", username); if (!homed_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); /* Let's use the cache, so that we can share it between the session and the authentication hooks */ - r = pam_get_data(handle, homed_field, (const void**) &json); + r = pam_get_data(pamh, homed_field, (const void**) &json); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); if (r == PAM_SUCCESS && json) { /* We determined earlier that this is not a homed user? Then exit early. (We use -1 as * negative cache indicator) */ @@ -166,52 +163,52 @@ static int acquire_user_record( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; - r = pam_acquire_bus_connection(handle, "pam-systemd-home", debug, &bus, bus_data); + r = pam_acquire_bus_connection(pamh, "pam-systemd-home", debug, &bus, bus_data); if (r != PAM_SUCCESS) return r; r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username); if (r < 0) { if (bus_error_is_unknown_service(&error)) { - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "systemd-homed is not available: %s", bus_error_message(&error, r)); goto user_unknown; } if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_HOME)) { - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Not a user managed by systemd-homed: %s", bus_error_message(&error, r)); goto user_unknown; } - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Failed to query user record: %s", bus_error_message(&error, r)); } r = sd_bus_message_read(reply, "sbo", &json, NULL, NULL); if (r < 0) - return pam_bus_log_parse_error(handle, r); + return pam_bus_log_parse_error(pamh, r); fresh_data = true; } r = sd_json_parse(json, /* flags= */ 0, &v, NULL, NULL); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse JSON user record: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to parse JSON user record: %m"); ur = user_record_new(); if (!ur) - return pam_log_oom(handle); + return pam_log_oom(pamh); r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to load user record: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to load user record: %m"); /* Safety check if cached record actually matches what we are looking for */ if (!user_record_matches_user_name(ur, username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Acquired user record does not match user name."); /* Update the 'username' pointer to point to our own record now. The pam_set_item() call below is @@ -220,9 +217,9 @@ static int acquire_user_record( /* We passed all checks. Let's now make sure the rest of the PAM stack continues with the primary, * normalized name of the user record (i.e. not an alias or so). */ - r = pam_set_item(handle, PAM_USER, ur->user_name); + r = pam_set_item(pamh, PAM_USER, ur->user_name); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to update username PAM item to '%s': @PAMERR@", ur->user_name); /* Everything seems to be good, let's cache this data now */ @@ -231,11 +228,11 @@ static int acquire_user_record( * homed */ _cleanup_free_ char *json_copy = strdup(json); if (!json_copy) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_set_data(handle, homed_field, json_copy, pam_cleanup_free); + r = pam_set_data(pamh, homed_field, json_copy, pam_cleanup_free); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", homed_field); /* Take a second copy: for the generic data field, the one which we share with @@ -243,15 +240,15 @@ static int acquire_user_record( * and non-homed user records. */ json_copy = strdup(json); if (!json_copy) - return pam_log_oom(handle); + return pam_log_oom(pamh); _cleanup_free_ char *generic_field = strjoin("systemd-user-record-", username); if (!generic_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_set_data(handle, generic_field, json_copy, pam_cleanup_free); + r = pam_set_data(pamh, generic_field, json_copy, pam_cleanup_free); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", generic_field); TAKE_PTR(json_copy); @@ -259,9 +256,9 @@ static int acquire_user_record( /* Let's store the area we parsed out of the name in an env var, so that pam_systemd later can honour it. */ if (area) { - r = pam_misc_setenv(handle, "XDG_AREA", area, /* readonly= */ 0); + r = pam_misc_setenv(pamh, "XDG_AREA", area, /* readonly= */ 0); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable $XDG_AREA to '%s': @PAMERR@", area); } @@ -272,49 +269,49 @@ static int acquire_user_record( user_unknown: /* Cache this, so that we don't check again */ - r = pam_set_data(handle, homed_field, POINTER_MAX, NULL); + r = pam_set_data(pamh, homed_field, POINTER_MAX, NULL); if (r != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_ERR, r, + pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s' to invalid, ignoring: @PAMERR@", homed_field); return PAM_USER_UNKNOWN; } -static int release_user_record(pam_handle_t *handle, const char *username) { +static int release_user_record(pam_handle_t *pamh, const char *username) { _cleanup_free_ char *homed_field = NULL, *generic_field = NULL; int r, k; - assert(handle); + assert(pamh); assert(username); homed_field = strjoin("systemd-home-user-record-", username); if (!homed_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_set_data(handle, homed_field, NULL, NULL); + r = pam_set_data(pamh, homed_field, NULL, NULL); if (r != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_ERR, r, + pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM user record data '%s': @PAMERR@", homed_field); generic_field = strjoin("systemd-user-record-", username); if (!generic_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); - k = pam_set_data(handle, generic_field, NULL, NULL); + k = pam_set_data(pamh, generic_field, NULL, NULL); if (k != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_ERR, k, + pam_syslog_pam_error(pamh, LOG_ERR, k, "Failed to release PAM user record data '%s': @PAMERR@", generic_field); return IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA) ? k : r; } -static void cleanup_home_fd(pam_handle_t *handle, void *data, int error_status) { +static void cleanup_home_fd(pam_handle_t *pamh, void *data, int error_status) { safe_close(PTR_TO_FD(data)); } static int handle_generic_user_record_error( - pam_handle_t *handle, + pam_handle_t *pamh, const char *user_name, UserRecord *secret, int ret, @@ -329,14 +326,14 @@ static int handle_generic_user_record_error( /* Logs about all errors, except for PAM_CONV_ERR, i.e. when requesting more info failed. */ if (sd_bus_error_has_name(error, BUS_ERROR_HOME_ABSENT)) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Home of user %s is currently absent, please plug in the necessary storage device or backing file system."), user_name); - return pam_syslog_pam_error(handle, LOG_ERR, PAM_PERM_DENIED, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_PERM_DENIED, "Failed to acquire home for user %s: %s", user_name, bus_error_message(error, ret)); } else if (sd_bus_error_has_name(error, BUS_ERROR_AUTHENTICATION_LIMIT_HIT)) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Too frequent login attempts for user %s, try again later."), user_name); - return pam_syslog_pam_error(handle, LOG_ERR, PAM_MAXTRIES, + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Too frequent login attempts for user %s, try again later."), user_name); + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_MAXTRIES, "Failed to acquire home for user %s: %s", user_name, bus_error_message(error, ret)); } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD)) { @@ -347,22 +344,22 @@ static int handle_generic_user_record_error( /* This didn't work? Ask for an (additional?) password */ if (strv_isempty(secret->password)) - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Password: ")); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Password: ")); else { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password incorrect or not sufficient for authentication of user %s."), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, try again: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password incorrect or not sufficient for authentication of user %s."), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, try again: ")); } if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "Password request aborted."); + pam_debug_syslog(pamh, debug, "Password request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_password(secret, STRV_MAKE(newp), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store password: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store password: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_RECOVERY_KEY)) { _cleanup_(erase_and_freep) char *newp = NULL; @@ -372,22 +369,22 @@ static int handle_generic_user_record_error( /* Hmm, homed asks for recovery key (because no regular password is defined maybe)? Provide it. */ if (strv_isempty(secret->password)) - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Recovery key: ")); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Recovery key: ")); else { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password/recovery key incorrect or not sufficient for authentication of user %s."), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, reenter recovery key: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password/recovery key incorrect or not sufficient for authentication of user %s."), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, reenter recovery key: ")); } if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "Recovery key request aborted."); + pam_debug_syslog(pamh, debug, "Recovery key request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_password(secret, STRV_MAKE(newp), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store recovery key: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store recovery key: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) { _cleanup_(erase_and_freep) char *newp = NULL; @@ -395,78 +392,78 @@ static int handle_generic_user_record_error( assert(secret); if (strv_isempty(secret->password)) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Security token of user %s not inserted."), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Try again with password: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Security token of user %s not inserted."), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Try again with password: ")); } else { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password incorrect or not sufficient, and configured security token of user %s not inserted."), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Try again with password: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password incorrect or not sufficient, and configured security token of user %s not inserted."), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Try again with password: ")); } if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "Password request aborted."); + pam_debug_syslog(pamh, debug, "Password request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_password(secret, STRV_MAKE(newp), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store password: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store password: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_NEEDED)) { _cleanup_(erase_and_freep) char *newp = NULL; assert(secret); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Security token PIN: ")); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Security token PIN: ")); if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "PIN request aborted."); + pam_debug_syslog(pamh, debug, "PIN request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_token_pin(secret, STRV_MAKE(newp), false); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store PIN: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store PIN: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED)) { assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Please authenticate physically on security token of user %s."), user_name); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Please authenticate physically on security token of user %s."), user_name); r = user_record_set_pkcs11_protected_authentication_path_permitted(secret, true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set PKCS#11 protected authentication path permitted flag: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) { assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Please confirm presence on security token of user %s."), user_name); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Please confirm presence on security token of user %s."), user_name); r = user_record_set_fido2_user_presence_permitted(secret, true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set FIDO2 user presence permitted flag: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) { assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Please verify user on security token of user %s."), user_name); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Please verify user on security token of user %s."), user_name); r = user_record_set_fido2_user_verification_permitted(secret, true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set FIDO2 user verification permitted flag: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED)) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)")); return PAM_SERVICE_ERR; } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN)) { @@ -474,67 +471,67 @@ static int handle_generic_user_record_error( assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Security token PIN incorrect for user %s."), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Security token PIN incorrect for user %s."), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "PIN request aborted."); + pam_debug_syslog(pamh, debug, "PIN request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_token_pin(secret, STRV_MAKE(newp), false); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store PIN: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store PIN: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT)) { _cleanup_(erase_and_freep) char *newp = NULL; assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Security token PIN of user %s incorrect (only a few tries left!)"), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Security token PIN of user %s incorrect (only a few tries left!)"), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "PIN request aborted."); + pam_debug_syslog(pamh, debug, "PIN request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_token_pin(secret, STRV_MAKE(newp), false); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store PIN: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store PIN: %m"); } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT)) { _cleanup_(erase_and_freep) char *newp = NULL; assert(secret); - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Security token PIN of user %s incorrect (only one try left!)"), user_name); - r = pam_prompt_graceful(handle, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Security token PIN of user %s incorrect (only one try left!)"), user_name); + r = pam_prompt_graceful(pamh, PAM_PROMPT_ECHO_OFF, &newp, _("Sorry, retry security token PIN: ")); if (r != PAM_SUCCESS) return PAM_CONV_ERR; /* no logging here */ if (isempty(newp)) { - pam_debug_syslog(handle, debug, "PIN request aborted."); + pam_debug_syslog(pamh, debug, "PIN request aborted."); return PAM_AUTHTOK_ERR; } r = user_record_set_token_pin(secret, STRV_MAKE(newp), false); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store PIN: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store PIN: %m"); } else - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Failed to acquire home for user %s: %s", user_name, bus_error_message(error, ret)); return PAM_SUCCESS; } static int acquire_home( - pam_handle_t *handle, + pam_handle_t *pamh, AcquireHomeFlags flags, bool debug, PamBusData **bus_data) { @@ -548,7 +545,7 @@ static int acquire_home( unsigned n_attempts = 0; int r; - assert(handle); + assert(pamh); /* This acquires a reference to a home directory in the following ways: * @@ -572,25 +569,25 @@ static int acquire_home( * prompt the user for the missing unlock credentials, and then chainload the real shell. */ - r = pam_get_user(handle, &username, NULL); + r = pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get user name: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); /* If we already have acquired the fd, let's shortcut this */ fd_field = strjoin("systemd-home-fd-", username); if (!fd_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_get_data(handle, fd_field, &home_fd_ptr); + r = pam_get_data(pamh, fd_field, &home_fd_ptr); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to retrieve PAM home reference fd: @PAMERR@"); if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0) return PAM_SUCCESS; - r = acquire_user_record(handle, username, debug, &ur, bus_data); + r = acquire_user_record(pamh, username, debug, &ur, bus_data); if (r != PAM_SUCCESS) return r; @@ -602,7 +599,7 @@ static int acquire_home( * request to collect one more password and pass the new and all previously used passwords again. */ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; - r = pam_acquire_bus_connection(handle, "pam-systemd-home", debug, &bus, bus_data); + r = pam_acquire_bus_connection(pamh, "pam-systemd-home", debug, &bus, bus_data); if (r != PAM_SUCCESS) return r; @@ -616,20 +613,20 @@ static int acquire_home( secret = user_record_new(); if (!secret) - return pam_log_oom(handle); + return pam_log_oom(pamh); /* If there's already a cached password, use it. But if not let's authenticate * without anything, maybe some other authentication mechanism systemd-homed * implements (such as PKCS#11) allows us to authenticate without anything else. */ - r = pam_get_item(handle, PAM_AUTHTOK, (const void**) &cached_password); + r = pam_get_item(pamh, PAM_AUTHTOK, (const void**) &cached_password); if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get cached password: @PAMERR@"); if (!isempty(cached_password)) { r = user_record_set_password(secret, STRV_MAKE(cached_password), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store password: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store password: %m"); } } @@ -642,21 +639,21 @@ static int acquire_home( r = bus_message_new_method_call(bus, &m, bus_home_mgr, method); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_message_append(m, "s", ur->user_name); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); if (do_auth) { r = bus_message_append_secret(m, secret); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); } r = sd_bus_message_append(m, "b", FLAGS_SET(flags, ACQUIRE_PLEASE_SUSPEND)); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { @@ -670,7 +667,7 @@ static int acquire_home( home_locked = true; /* Similar */ do_auth = true; } else { - r = handle_generic_user_record_error(handle, ur->user_name, secret, r, &error, debug); + r = handle_generic_user_record_error(pamh, ur->user_name, secret, r, &error, debug); if (r == PAM_CONV_ERR) { /* Password/PIN prompts will fail in certain environments, for example when * we are called from OpenSSH's account or session hooks, or in systemd's @@ -679,14 +676,14 @@ static int acquire_home( if (!FLAGS_SET(flags, ACQUIRE_REF_ANYWAY)) { if (home_not_active) - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Home of user %s is currently not active, please log in locally first."), ur->user_name); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Home of user %s is currently not active, please log in locally first."), ur->user_name); if (home_locked) - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Home of user %s is currently locked, please unlock locally first."), ur->user_name); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Home of user %s is currently locked, please unlock locally first."), ur->user_name); if (FLAGS_SET(flags, ACQUIRE_MUST_AUTHENTICATE)) - pam_syslog(handle, LOG_ERR, "Failed to prompt for password/prompt."); + pam_syslog(pamh, LOG_ERR, "Failed to prompt for password/prompt."); else if (debug) - pam_debug_syslog(handle, debug, "Failed to prompt for password/prompt."); + pam_debug_syslog(pamh, debug, "Failed to prompt for password/prompt."); return home_not_active || home_locked ? PAM_PERM_DENIED : PAM_CONV_ERR; } @@ -704,40 +701,40 @@ static int acquire_home( r = sd_bus_message_read(reply, "h", &fd); if (r < 0) - return pam_bus_log_parse_error(handle, r); + return pam_bus_log_parse_error(pamh, r); acquired_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); if (acquired_fd < 0) - return pam_syslog_errno(handle, LOG_ERR, errno, + return pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to duplicate acquired fd: %m"); break; } if (++n_attempts >= 5) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Too many unsuccessful login attempts for user %s, refusing."), ur->user_name); - return pam_syslog_pam_error(handle, LOG_ERR, PAM_MAXTRIES, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_MAXTRIES, "Failed to acquire home for user %s: %s", ur->user_name, bus_error_message(&error, r)); } } /* Later PAM modules may need the auth token, but only during pam_authenticate. */ if (FLAGS_SET(flags, ACQUIRE_MUST_AUTHENTICATE) && !strv_isempty(secret->password)) { - r = pam_set_item(handle, PAM_AUTHTOK, *secret->password); + r = pam_set_item(pamh, PAM_AUTHTOK, *secret->password); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); } - r = pam_set_data(handle, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd); + r = pam_set_data(pamh, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); TAKE_FD(acquired_fd); if (do_auth) { /* We likely just activated the home directory, let's flush out the user record, since a * newer embedded user record might have been acquired from the activation. */ - r = release_user_record(handle, ur->user_name); + r = release_user_record(pamh, ur->user_name); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) return r; } @@ -747,44 +744,44 @@ static int acquire_home( * manager for us (since it would see an inaccessible home directory). Hence set an environment * variable that pam_systemd looks for). */ if (unrestricted) { - r = pam_putenv(handle, "XDG_SESSION_INCOMPLETE=1"); + r = pam_putenv(pamh, "XDG_SESSION_INCOMPLETE=1"); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_WARNING, r, "Failed to set XDG_SESSION_INCOMPLETE= environment variable: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_WARNING, r, "Failed to set XDG_SESSION_INCOMPLETE= environment variable: @PAMERR@"); - pam_syslog(handle, LOG_NOTICE, "Home for user %s acquired in incomplete mode, requires later activation.", ur->user_name); + pam_syslog(pamh, LOG_NOTICE, "Home for user %s acquired in incomplete mode, requires later activation.", ur->user_name); } else - pam_syslog(handle, LOG_NOTICE, "Home for user %s successfully acquired.", ur->user_name); + pam_syslog(pamh, LOG_NOTICE, "Home for user %s successfully acquired.", ur->user_name); return PAM_SUCCESS; } -static int release_home_fd(pam_handle_t *handle, const char *username) { +static int release_home_fd(pam_handle_t *pamh, const char *username) { _cleanup_free_ char *fd_field = NULL; const void *home_fd_ptr = NULL; int r; - assert(handle); + assert(pamh); assert(username); fd_field = strjoin("systemd-home-fd-", username); if (!fd_field) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_get_data(handle, fd_field, &home_fd_ptr); + r = pam_get_data(pamh, fd_field, &home_fd_ptr); if (r == PAM_NO_MODULE_DATA || (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) < 0)) return PAM_NO_MODULE_DATA; if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to retrieve PAM home reference fd: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to retrieve PAM home reference fd: @PAMERR@"); - r = pam_set_data(handle, fd_field, NULL, NULL); + r = pam_set_data(pamh, fd_field, NULL, NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to release PAM home reference fd: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM home reference fd: @PAMERR@"); return PAM_SUCCESS; } _public_ PAM_EXTERN int pam_sm_authenticate( - pam_handle_t *handle, + pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { @@ -798,40 +795,38 @@ _public_ PAM_EXTERN int pam_sm_authenticate( pam_log_setup(); - if (parse_env(handle, &flags) < 0) + if (parse_env(pamh, &flags) < 0) return PAM_AUTH_ERR; - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, &flags, &debug) < 0) return PAM_AUTH_ERR; - pam_debug_syslog(handle, debug, "pam-systemd-homed: authenticating..."); + pam_debug_syslog(pamh, debug, "pam-systemd-homed: authenticating..."); - return acquire_home(handle, ACQUIRE_MUST_AUTHENTICATE|flags, debug, /* bus_data= */ NULL); + return acquire_home(pamh, ACQUIRE_MUST_AUTHENTICATE|flags, debug, /* bus_data= */ NULL); } _public_ PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { return PAM_SUCCESS; } -static int fallback_shell_can_work( - pam_handle_t *handle, - AcquireHomeFlags *flags) { +static int fallback_shell_can_work(pam_handle_t *pamh, AcquireHomeFlags *flags) { const char *tty = NULL, *display = NULL; int r; - assert(handle); + assert(pamh); assert(flags); r = pam_get_item_many( - handle, + pamh, PAM_TTY, &tty, PAM_XDISPLAY, &display); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM items: @PAMERR@"); /* The fallback shell logic only works on TTY logins, hence only allow it if there's no X11 display * set, and a TTY field is set that is neither "cron" (which is what crond sets, god knows why) not @@ -847,7 +842,7 @@ static int fallback_shell_can_work( } _public_ PAM_EXTERN int pam_sm_open_session( - pam_handle_t *handle, + pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { @@ -865,48 +860,48 @@ _public_ PAM_EXTERN int pam_sm_open_session( pam_log_setup(); - if (parse_env(handle, &flags) < 0) + if (parse_env(pamh, &flags) < 0) return PAM_SESSION_ERR; - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, &flags, &debug) < 0) return PAM_SESSION_ERR; - pam_debug_syslog(handle, debug, "pam-systemd-homed: starting session..."); + pam_debug_syslog(pamh, debug, "pam-systemd-homed: starting session..."); - r = fallback_shell_can_work(handle, &flags); + r = fallback_shell_can_work(pamh, &flags); if (r != PAM_SUCCESS) return r; /* Explicitly get saved PamBusData here. Otherwise, this function may succeed without setting 'd' * even if there is an opened sd-bus connection, and it will be leaked. See issue #31375. */ - r = pam_get_bus_data(handle, "pam-systemd-home", &d); + r = pam_get_bus_data(pamh, "pam-systemd-home", &d); if (r != PAM_SUCCESS) return r; - r = acquire_home(handle, flags, debug, &d); + r = acquire_home(pamh, flags, debug, &d); if (r == PAM_USER_UNKNOWN) /* Not managed by us? Don't complain. */ return PAM_SUCCESS; if (r != PAM_SUCCESS) return r; - r = pam_putenv(handle, "SYSTEMD_HOME=1"); + r = pam_putenv(pamh, "SYSTEMD_HOME=1"); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable $SYSTEMD_HOME: @PAMERR@"); - r = pam_putenv(handle, FLAGS_SET(flags, ACQUIRE_PLEASE_SUSPEND) ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0"); + r = pam_putenv(pamh, FLAGS_SET(flags, ACQUIRE_PLEASE_SUSPEND) ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0"); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: @PAMERR@"); return PAM_SUCCESS; } _public_ PAM_EXTERN int pam_sm_close_session( - pam_handle_t *handle, + pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { @@ -918,55 +913,55 @@ _public_ PAM_EXTERN int pam_sm_close_session( pam_log_setup(); - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, NULL, &debug) < 0) return PAM_SESSION_ERR; - pam_debug_syslog(handle, debug, "pam-systemd-homed: closing session..."); + pam_debug_syslog(pamh, debug, "pam-systemd-homed: closing session..."); - r = pam_get_user(handle, &username, NULL); + r = pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get user name: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "User name not set."); /* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome() * call will be able to do its thing. */ - r = release_home_fd(handle, username); + r = release_home_fd(pamh, username); if (r == PAM_NO_MODULE_DATA) /* Nothing to do, we never acquired an fd */ return PAM_SUCCESS; if (r != PAM_SUCCESS) return r; _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; - r = pam_acquire_bus_connection(handle, "pam-systemd-home", debug, &bus, NULL); + r = pam_acquire_bus_connection(pamh, "pam-systemd-home", debug, &bus, NULL); if (r != PAM_SUCCESS) return r; r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome"); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_message_append(m, "s", username); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL); if (r < 0) { if (!sd_bus_error_has_name(&error, BUS_ERROR_HOME_BUSY)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SESSION_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SESSION_ERR, "Failed to release user home: %s", bus_error_message(&error, r)); - pam_syslog(handle, LOG_NOTICE, "Not deactivating home directory of %s, as it is still used.", username); + pam_syslog(pamh, LOG_NOTICE, "Not deactivating home directory of %s, as it is still used.", username); } return PAM_SUCCESS; } _public_ PAM_EXTERN int pam_sm_acct_mgmt( - pam_handle_t *handle, + pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { @@ -983,26 +978,26 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( pam_log_setup(); - if (parse_env(handle, &flags) < 0) + if (parse_env(pamh, &flags) < 0) return PAM_AUTH_ERR; - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, &flags, &debug) < 0) return PAM_AUTH_ERR; - pam_debug_syslog(handle, debug, "pam-systemd-homed: starting account management..."); + pam_debug_syslog(pamh, debug, "pam-systemd-homed: starting account management..."); - r = fallback_shell_can_work(handle, &flags); + r = fallback_shell_can_work(pamh, &flags); if (r != PAM_SUCCESS) return r; - r = acquire_home(handle, flags, debug, /* bus_data= */ NULL); + r = acquire_home(pamh, flags, debug, /* bus_data= */ NULL); if (r != PAM_SUCCESS) return r; - r = acquire_user_record(handle, /* username= */ NULL, debug, &ur, /* bus_data= */ NULL); + r = acquire_user_record(pamh, /* username= */ NULL, debug, &ur, /* bus_data= */ NULL); if (r != PAM_SUCCESS) return r; @@ -1010,24 +1005,24 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( switch (r) { case -ESTALE: - pam_syslog(handle, LOG_WARNING, "User record for '%s' is newer than current system time, assuming incorrect system clock, allowing access.", ur->user_name); + pam_syslog(pamh, LOG_WARNING, "User record for '%s' is newer than current system time, assuming incorrect system clock, allowing access.", ur->user_name); break; case -ENOLCK: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("User record is blocked, prohibiting access.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("User record is blocked, prohibiting access.")); return PAM_ACCT_EXPIRED; case -EL2HLT: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("User record is not valid yet, prohibiting access.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("User record is not valid yet, prohibiting access.")); return PAM_ACCT_EXPIRED; case -EL3HLT: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("User record is not valid anymore, prohibiting access.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("User record is not valid anymore, prohibiting access.")); return PAM_ACCT_EXPIRED; default: if (r < 0) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("User record not valid, prohibiting access.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("User record not valid, prohibiting access.")); return PAM_ACCT_EXPIRED; } } @@ -1037,7 +1032,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( usec_t n = now(CLOCK_REALTIME); if (t > n) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Too many logins, try again in %s."), + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Too many logins, try again in %s."), FORMAT_TIMESPAN(t - n, USEC_PER_SEC)); return PAM_MAXTRIES; @@ -1048,26 +1043,26 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( switch (r) { case -EKEYREVOKED: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password change required.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password change required.")); return PAM_NEW_AUTHTOK_REQD; case -EOWNERDEAD: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password expired, change required.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password expired, change required.")); return PAM_NEW_AUTHTOK_REQD; /* Strictly speaking this is only about password expiration, and we might want to allow * authentication via PKCS#11 or so, but let's ignore this fine distinction for now. */ case -EKEYREJECTED: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password is expired, but can't change, refusing login.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password is expired, but can't change, refusing login.")); return PAM_AUTHTOK_EXPIRED; case -EKEYEXPIRED: - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("Password will expire soon, please change.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("Password will expire soon, please change.")); break; case -ESTALE: /* If the system clock is wrong, let's log but continue */ - pam_syslog(handle, LOG_WARNING, "Couldn't check if password change is required, last change is in the future, system clock likely wrong."); + pam_syslog(pamh, LOG_WARNING, "Couldn't check if password change is required, last change is in the future, system clock likely wrong."); break; case -EROFS: @@ -1076,7 +1071,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( default: if (r < 0) { - (void) pam_prompt_graceful(handle, PAM_ERROR_MSG, NULL, _("User record not valid, prohibiting access.")); + (void) pam_prompt_graceful(pamh, PAM_ERROR_MSG, NULL, _("User record not valid, prohibiting access.")); return PAM_AUTHTOK_EXPIRED; } } @@ -1085,7 +1080,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( } _public_ PAM_EXTERN int pam_sm_chauthtok( - pam_handle_t *handle, + pam_handle_t *pamh, int sm_flags, int argc, const char **argv) { @@ -1102,42 +1097,42 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( pam_log_setup(); - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, NULL, &debug) < 0) return PAM_AUTH_ERR; - pam_debug_syslog(handle, debug, "pam-systemd-homed: starting authentication token management..."); + pam_debug_syslog(pamh, debug, "pam-systemd-homed: starting authentication token management..."); - r = acquire_user_record(handle, /* username= */ NULL, debug, &ur, /* bus_data= */ NULL); + r = acquire_user_record(pamh, /* username= */ NULL, debug, &ur, /* bus_data= */ NULL); if (r != PAM_SUCCESS) return r; /* Start with cached credentials */ r = pam_get_item_many( - handle, + pamh, PAM_OLDAUTHTOK, &old_password, PAM_AUTHTOK, &new_password); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get cached passwords: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get cached passwords: @PAMERR@"); if (isempty(new_password)) { /* No, it's not cached, then let's ask for the password and its verification, and cache * it. */ - r = pam_get_authtok_noverify(handle, &new_password, "New password: "); + r = pam_get_authtok_noverify(pamh, &new_password, "New password: "); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get new password: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get new password: @PAMERR@"); if (isempty(new_password)) { - pam_debug_syslog(handle, debug, "Password request aborted."); + pam_debug_syslog(pamh, debug, "Password request aborted."); return PAM_AUTHTOK_ERR; } - r = pam_get_authtok_verify(handle, &new_password, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */ + r = pam_get_authtok_verify(pamh, &new_password, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */ if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get password again: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get password again: @PAMERR@"); // FIXME: pam_pwquality will ask for the password a third time. It really shouldn't do // that, and instead assume the password was already verified once when it is found to be @@ -1150,24 +1145,24 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( old_secret = user_record_new(); if (!old_secret) - return pam_log_oom(handle); + return pam_log_oom(pamh); if (!isempty(old_password)) { r = user_record_set_password(old_secret, STRV_MAKE(old_password), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store old password: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store old password: %m"); } new_secret = user_record_new(); if (!new_secret) - return pam_log_oom(handle); + return pam_log_oom(pamh); r = user_record_set_password(new_secret, STRV_MAKE(new_password), true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to store new password: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to store new password: %m"); _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; - r = pam_acquire_bus_connection(handle, "pam-systemd-home", debug, &bus, NULL); + r = pam_acquire_bus_connection(pamh, "pam-systemd-home", debug, &bus, NULL); if (r != PAM_SUCCESS) return r; @@ -1177,30 +1172,30 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome"); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_message_append(m, "s", ur->user_name); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = bus_message_append_secret(m, new_secret); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = bus_message_append_secret(m, old_secret); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL); if (r < 0) { - r = handle_generic_user_record_error(handle, ur->user_name, old_secret, r, &error, debug); + r = handle_generic_user_record_error(pamh, ur->user_name, old_secret, r, &error, debug); if (r == PAM_CONV_ERR) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to prompt for password/prompt."); if (r != PAM_SUCCESS) return r; } else - return pam_syslog_pam_error(handle, LOG_NOTICE, PAM_SUCCESS, + return pam_syslog_pam_error(pamh, LOG_NOTICE, PAM_SUCCESS, "Successfully changed password for user %s.", ur->user_name); if (++n_attempts >= 5) @@ -1209,6 +1204,6 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( /* Try again */ }; - return pam_syslog_pam_error(handle, LOG_NOTICE, PAM_MAXTRIES, + return pam_syslog_pam_error(pamh, LOG_NOTICE, PAM_MAXTRIES, "Failed to change password for user %s: @PAMERR@", ur->user_name); } diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 173da87e273e9..5ae3313eb894c 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -55,14 +55,14 @@ #define LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC (2*USEC_PER_MINUTE) static int parse_caps( - pam_handle_t *handle, + pam_handle_t *pamh, const char *value, uint64_t *caps) { bool subtract; int r; - assert(handle); + assert(pamh); assert(value); if (value[0] == '~') { @@ -87,7 +87,7 @@ static int parse_caps( c = capability_from_name(s); if (c < 0) { - pam_syslog(handle, LOG_WARNING, "Unknown capability, ignoring: %s", s); + pam_syslog(pamh, LOG_WARNING, "Unknown capability, ignoring: %s", s); continue; } @@ -111,7 +111,7 @@ static int parse_caps( } static int parse_argv( - pam_handle_t *handle, + pam_handle_t *pamh, int argc, const char **argv, const char **class, const char **type, @@ -123,7 +123,7 @@ static int parse_argv( int r; - assert(handle); + assert(pamh); assert(argc >= 0); assert(argc == 0 || argv); @@ -145,7 +145,7 @@ static int parse_argv( } else if ((p = startswith(argv[i], "area="))) { if (!isempty(p) && !filename_is_valid(p)) - pam_syslog(handle, LOG_WARNING, "Area name specified among PAM module parameters is not valid, ignoring: %s", p); + pam_syslog(pamh, LOG_WARNING, "Area name specified among PAM module parameters is not valid, ignoring: %s", p); else if (area) *area = p; @@ -156,72 +156,69 @@ static int parse_argv( } else if ((p = startswith(argv[i], "debug="))) { r = parse_boolean(p); if (r < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", p); + pam_syslog(pamh, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", p); else if (debug) *debug = r; } else if ((p = startswith(argv[i], "default-capability-bounding-set="))) { - r = parse_caps(handle, p, default_capability_bounding_set); + r = parse_caps(pamh, p, default_capability_bounding_set); if (r < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse default-capability-bounding-set= argument, ignoring: %s", p); + pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-bounding-set= argument, ignoring: %s", p); } else if ((p = startswith(argv[i], "default-capability-ambient-set="))) { - r = parse_caps(handle, p, default_capability_ambient_set); + r = parse_caps(pamh, p, default_capability_ambient_set); if (r < 0) - pam_syslog(handle, LOG_WARNING, "Failed to parse default-capability-ambient-set= argument, ignoring: %s", p); + pam_syslog(pamh, LOG_WARNING, "Failed to parse default-capability-ambient-set= argument, ignoring: %s", p); } else - pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } return 0; } -static int acquire_user_record( - pam_handle_t *handle, - UserRecord **ret_record) { - +static int acquire_user_record(pam_handle_t *pamh, UserRecord **ret_record) { int r; - assert(handle); + assert(pamh); const char *username = NULL; - r = pam_get_user(handle, &username, NULL); + r = pam_get_user(pamh, &username, NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get user name: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get user name: @PAMERR@"); if (isempty(username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, "User name not valid."); + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "User name not valid."); /* If pam_systemd_homed (or some other module) already acquired the user record we can reuse it * here. */ _cleanup_free_ char *field = strjoin("systemd-user-record-", username); if (!field) - return pam_log_oom(handle); + return pam_log_oom(pamh); _cleanup_(user_record_unrefp) UserRecord *ur = NULL; const char *json = NULL; - r = pam_get_data(handle, field, (const void**) &json); + r = pam_get_data(pamh, field, (const void**) &json); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM user record data: @PAMERR@"); if (r == PAM_SUCCESS && json) { _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; /* Parse cached record */ r = sd_json_parse(json, SD_JSON_PARSE_SENSITIVE, &v, NULL, NULL); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse JSON user record: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to parse JSON user record: %m"); ur = user_record_new(); if (!ur) - return pam_log_oom(handle); + return pam_log_oom(pamh); r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to load user record: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to load user record: %m"); /* Safety check if cached record actually matches what we are looking for */ if (!user_record_matches_user_name(ur, username)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Acquired user record does not match user name."); } else { _cleanup_free_ char *formatted = NULL; @@ -229,28 +226,28 @@ static int acquire_user_record( /* Request the record ourselves */ r = userdb_by_name(username, /* match= */ NULL, /* flags= */ 0, &ur); if (r < 0) { - pam_syslog_errno(handle, LOG_ERR, r, "Failed to get user record: %m"); + pam_syslog_errno(pamh, LOG_ERR, r, "Failed to get user record: %m"); return PAM_USER_UNKNOWN; } if (!uid_is_valid(ur->uid)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_USER_UNKNOWN, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_USER_UNKNOWN, "User record of user '%s' has no UID, refusing.", username); r = sd_json_variant_format(ur->json, 0, &formatted); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to format user JSON: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to format user JSON: %m"); /* And cache it for everyone else */ - r = pam_set_data(handle, field, formatted, pam_cleanup_free); + r = pam_set_data(pamh, field, formatted, pam_cleanup_free); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM user record data '%s': @PAMERR@", field); TAKE_PTR(formatted); } if (!uid_is_valid(ur->uid)) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SERVICE_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SERVICE_ERR, "Acquired user record does not have a UID."); if (ret_record) @@ -365,10 +362,10 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_ return 0; } -static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { +static int append_session_memory_max(pam_handle_t *pamh, sd_bus_message *m, const char *limit) { int r; - assert(handle); + assert(pamh); assert(m); if (isempty(limit)) @@ -384,17 +381,17 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co uint64_t val; r = parse_size(limit, 1024, &val); if (r < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit); + pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit); return 0; } return sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val); } -static int append_session_runtime_max_sec(pam_handle_t *handle, sd_bus_message *m, const char *limit) { +static int append_session_runtime_max_sec(pam_handle_t *pamh, sd_bus_message *m, const char *limit) { int r; - assert(handle); + assert(pamh); assert(m); /* No need to parse "infinity" here, it will be set by default later in scope_init() */ @@ -404,17 +401,17 @@ static int append_session_runtime_max_sec(pam_handle_t *handle, sd_bus_message * usec_t val; r = parse_sec(limit, &val); if (r < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit); + pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit); return 0; } return sd_bus_message_append(m, "(sv)", "RuntimeMaxUSec", "t", (uint64_t) val); } -static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { +static int append_session_tasks_max(pam_handle_t *pamh, sd_bus_message *m, const char *limit) { int r; - assert(handle); + assert(pamh); assert(m); /* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */ @@ -424,17 +421,17 @@ static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, con uint64_t val; r = safe_atou64(limit, &val); if (r < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit); + pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit); return 0; } return sd_bus_message_append(m, "(sv)", "TasksMax", "t", val); } -static int append_session_cpu_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) { +static int append_session_cpu_weight(pam_handle_t *pamh, sd_bus_message *m, const char *limit) { int r; - assert(handle); + assert(pamh); assert(m); if (isempty(limit)) @@ -443,17 +440,17 @@ static int append_session_cpu_weight(pam_handle_t *handle, sd_bus_message *m, co uint64_t val; r = cg_cpu_weight_parse(limit, &val); if (r < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit); + pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit); return 0; } return sd_bus_message_append(m, "(sv)", "CPUWeight", "t", val); } -static int append_session_io_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) { +static int append_session_io_weight(pam_handle_t *pamh, sd_bus_message *m, const char *limit) { int r; - assert(handle); + assert(pamh); assert(m); if (isempty(limit)) @@ -462,17 +459,17 @@ static int append_session_io_weight(pam_handle_t *handle, sd_bus_message *m, con uint64_t val; r = cg_weight_parse(limit, &val); if (r < 0) { - pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit); + pam_syslog(pamh, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit); return 0; } return sd_bus_message_append(m, "(sv)", "IOWeight", "t", val); } -static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) { +static const char* getenv_harder(pam_handle_t *pamh, const char *key, const char *fallback) { const char *v; - assert(handle); + assert(pamh); assert(key); /* Looks for an environment variable, preferably in the environment block associated with the @@ -481,7 +478,7 @@ static const char* getenv_harder(pam_handle_t *handle, const char *key, const ch * PAM services don't have to be reworked to set systemd-specific properties, but these properties * can still be set from the unit file Environment= block. */ - v = pam_getenv(handle, key); + v = pam_getenv(pamh, key); if (!isempty(v)) return v; @@ -496,20 +493,20 @@ static const char* getenv_harder(pam_handle_t *handle, const char *key, const ch return fallback; } -static bool getenv_harder_bool(pam_handle_t *handle, const char *key, bool fallback) { +static bool getenv_harder_bool(pam_handle_t *pamh, const char *key, bool fallback) { const char *v; int r; - assert(handle); + assert(pamh); assert(key); - v = getenv_harder(handle, key, NULL); + v = getenv_harder(pamh, key, NULL); if (isempty(v)) return fallback; r = parse_boolean(v); if (r < 0) { - pam_syslog(handle, LOG_WARNING, + pam_syslog(pamh, LOG_WARNING, "Failed to parse environment variable value '%s' of '%s', falling back to using '%s'.", v, key, true_false(fallback)); return fallback; @@ -518,20 +515,20 @@ static bool getenv_harder_bool(pam_handle_t *handle, const char *key, bool fallb return r; } -static uint32_t getenv_harder_uint32(pam_handle_t *handle, const char *key, uint32_t fallback) { +static uint32_t getenv_harder_uint32(pam_handle_t *pamh, const char *key, uint32_t fallback) { int r; - assert(handle); + assert(pamh); assert(key); - const char *v = getenv_harder(handle, key, NULL); + const char *v = getenv_harder(pamh, key, NULL); if (isempty(v)) return fallback; uint32_t u; r = safe_atou32(v, &u); if (r < 0) { - pam_syslog(handle, LOG_WARNING, + pam_syslog(pamh, LOG_WARNING, "Failed to parse environment variable value '%s' of '%s' as unsigned integer, falling back to using %" PRIu32 ".", v, key, fallback); return fallback; @@ -540,10 +537,10 @@ static uint32_t getenv_harder_uint32(pam_handle_t *handle, const char *key, uint return u; } -static int update_environment(pam_handle_t *handle, const char *key, const char *value) { +static int update_environment(pam_handle_t *pamh, const char *key, const char *value) { int r; - assert(handle); + assert(pamh); assert(key); /* Updates the environment, and removes environment variables if value is NULL or empty. Also, log @@ -554,29 +551,29 @@ static int update_environment(pam_handle_t *handle, const char *key, const char * call it without the variable actually being set. Hence we check explicitly if it's set * before. */ - if (!pam_getenv(handle, key)) + if (!pam_getenv(pamh, key)) return PAM_SUCCESS; - r = pam_putenv(handle, key); + r = pam_putenv(pamh, key); if (!IN_SET(r, PAM_SUCCESS, PAM_BAD_ITEM)) - return pam_syslog_pam_error(handle, LOG_WARNING, r, + return pam_syslog_pam_error(pamh, LOG_WARNING, r, "Failed to unset %s environment variable: @PAMERR@", key); return PAM_SUCCESS; } - r = pam_misc_setenv(handle, key, value, /* readonly= */ false); + r = pam_misc_setenv(pamh, key, value, /* readonly= */ false); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable %s: @PAMERR@", key); return PAM_SUCCESS; } -static int propagate_credential_to_environment(pam_handle_t *handle, bool debug, const char *credential, const char *varname) { +static int propagate_credential_to_environment(pam_handle_t *pamh, bool debug, const char *credential, const char *varname) { int r; - assert(handle); + assert(pamh); assert(credential); assert(varname); @@ -586,22 +583,22 @@ static int propagate_credential_to_environment(pam_handle_t *handle, bool debug, r = read_credential(credential, (void**) &value, /* ret_size= */ NULL); if (r < 0) { - pam_debug_syslog_errno(handle, debug, r, "Failed to read credential '%s', ignoring: %m", credential); + pam_debug_syslog_errno(pamh, debug, r, "Failed to read credential '%s', ignoring: %m", credential); return PAM_SUCCESS; } - r = pam_misc_setenv(handle, varname, value, 0); + r = pam_misc_setenv(pamh, varname, value, 0); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set environment variable %s: @PAMERR@", varname); return PAM_SUCCESS; } -static bool validate_runtime_directory(pam_handle_t *handle, const char *path, uid_t uid) { +static bool validate_runtime_directory(pam_handle_t *pamh, const char *path, uid_t uid) { struct stat st; - assert(handle); + assert(pamh); assert(path); /* Some extra paranoia: let's not set $XDG_RUNTIME_DIR if the directory we'd set it to isn't actually @@ -612,49 +609,49 @@ static bool validate_runtime_directory(pam_handle_t *handle, const char *path, u * otherwise we might end up setting $XDG_RUNTIME_DIR to some directory owned by the wrong user. */ if (!path_is_absolute(path)) { - pam_syslog(handle, LOG_ERR, "Provided runtime directory '%s' is not absolute.", path); + pam_syslog(pamh, LOG_ERR, "Provided runtime directory '%s' is not absolute.", path); goto fail; } if (lstat(path, &st) < 0) { - pam_syslog_errno(handle, LOG_ERR, errno, "Failed to stat() runtime directory '%s': %m", path); + pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to stat() runtime directory '%s': %m", path); goto fail; } if (!S_ISDIR(st.st_mode)) { - pam_syslog(handle, LOG_ERR, "Runtime directory '%s' is not actually a directory.", path); + pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not actually a directory.", path); goto fail; } if (st.st_uid != uid) { - pam_syslog(handle, LOG_ERR, "Runtime directory '%s' is not owned by UID " UID_FMT ", as it should.", path, uid); + pam_syslog(pamh, LOG_ERR, "Runtime directory '%s' is not owned by UID " UID_FMT ", as it should.", path, uid); goto fail; } return true; fail: - pam_syslog(handle, LOG_WARNING, "Not setting $XDG_RUNTIME_DIR, as the directory is not in order."); + pam_syslog(pamh, LOG_WARNING, "Not setting $XDG_RUNTIME_DIR, as the directory is not in order."); return false; } -static int pam_putenv_and_log(pam_handle_t *handle, const char *e, bool debug) { +static int pam_putenv_and_log(pam_handle_t *pamh, const char *e, bool debug) { int r; - assert(handle); + assert(pamh); assert(e); - r = pam_putenv(handle, e); + r = pam_putenv(pamh, e); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM environment variable %s: @PAMERR@", e); - pam_debug_syslog(handle, debug, "PAM environment variable %s set based on user record.", e); + pam_debug_syslog(pamh, debug, "PAM environment variable %s set based on user record.", e); return PAM_SUCCESS; } static int apply_user_record_settings( - pam_handle_t *handle, + pam_handle_t *pamh, UserRecord *ur, bool debug, uint64_t default_capability_bounding_set, @@ -662,16 +659,16 @@ static int apply_user_record_settings( _cleanup_strv_free_ char **langs = NULL; int r; - assert(handle); + assert(pamh); assert(ur); if (ur->umask != MODE_INVALID) { umask(ur->umask); - pam_debug_syslog(handle, debug, "Set user umask to %04o based on user record.", ur->umask); + pam_debug_syslog(pamh, debug, "Set user umask to %04o based on user record.", ur->umask); } STRV_FOREACH(i, ur->environment) { - r = pam_putenv_and_log(handle, *i, debug); + r = pam_putenv_and_log(pamh, *i, debug); if (r != PAM_SUCCESS) return r; } @@ -681,25 +678,25 @@ static int apply_user_record_settings( joined = strjoin("EMAIL=", ur->email_address); if (!joined) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_putenv_and_log(handle, joined, debug); + r = pam_putenv_and_log(pamh, joined, debug); if (r != PAM_SUCCESS) return r; } if (ur->time_zone) { if (!timezone_is_valid(ur->time_zone, LOG_DEBUG)) - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Time zone specified in user record is not valid locally, not setting $TZ."); else { _cleanup_free_ char *joined = NULL; joined = strjoin("TZ=:", ur->time_zone); if (!joined) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_putenv_and_log(handle, joined, debug); + r = pam_putenv_and_log(pamh, joined, debug); if (r != PAM_SUCCESS) return r; } @@ -707,21 +704,21 @@ static int apply_user_record_settings( r = user_record_languages(ur, &langs); if (r < 0) - pam_syslog_errno(handle, LOG_ERR, r, + pam_syslog_errno(pamh, LOG_ERR, r, "Failed to acquire user's language preferences, ignoring: %m"); else if (strv_isempty(langs)) ; /* User has no preference set so we do nothing */ else if (locale_is_installed(langs[0]) <= 0) - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Preferred languages specified in user record are not installed locally, not setting $LANG or $LANGUAGE."); else { _cleanup_free_ char *lang = NULL; lang = strjoin("LANG=", langs[0]); if (!lang) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_putenv_and_log(handle, lang, debug); + r = pam_putenv_and_log(pamh, lang, debug); if (r != PAM_SUCCESS) return r; @@ -730,13 +727,13 @@ static int apply_user_record_settings( joined = strv_join(langs, ":"); if (!joined) - return pam_log_oom(handle); + return pam_log_oom(pamh); language = strjoin("LANGUAGE=", joined); if (!language) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_putenv_and_log(handle, language, debug); + r = pam_putenv_and_log(pamh, language, debug); if (r != PAM_SUCCESS) return r; } @@ -744,10 +741,10 @@ static int apply_user_record_settings( if (nice_is_valid(ur->nice_level)) { if (nice(ur->nice_level) < 0) - pam_syslog_errno(handle, LOG_WARNING, errno, + pam_syslog_errno(pamh, LOG_WARNING, errno, "Failed to set nice level to %i, ignoring: %m", ur->nice_level); else - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Nice level set to %i, based on user record.", ur->nice_level); } @@ -757,10 +754,10 @@ static int apply_user_record_settings( r = setrlimit_closest(rl, ur->rlimits[rl]); if (r < 0) - pam_syslog_errno(handle, LOG_ERR, r, + pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set resource limit %s, ignoring: %m", rlimit_to_string(rl)); else - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Resource limit %s set, based on user record.", rlimit_to_string(rl)); } @@ -778,14 +775,14 @@ static int apply_user_record_settings( r = capability_ambient_set_apply(a, /* also_inherit= */ true); if (r < 0) - pam_syslog_errno(handle, LOG_ERR, r, + pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set ambient capabilities, ignoring: %m"); } if (b != CAP_MASK_UNSET && !cap_test_all(b)) { r = capability_bounding_set_drop(b, /* right_now= */ false); if (r < 0) - pam_syslog_errno(handle, LOG_ERR, r, + pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set bounding capabilities, ignoring: %m"); } @@ -830,7 +827,7 @@ typedef struct SessionContext { static int create_session_message( sd_bus *bus, - pam_handle_t *handle, + pam_handle_t *pamh, UserRecord *ur, const SessionContext *context, bool avoid_pidfd, @@ -841,7 +838,7 @@ static int create_session_message( int r; assert(bus); - assert(handle); + assert(pamh); assert(ur); assert(context); assert(ret); @@ -885,23 +882,23 @@ static int create_session_message( if (r < 0) return r; - r = append_session_memory_max(handle, m, context->memory_max); + r = append_session_memory_max(pamh, m, context->memory_max); if (r < 0) return r; - r = append_session_runtime_max_sec(handle, m, context->runtime_max_sec); + r = append_session_runtime_max_sec(pamh, m, context->runtime_max_sec); if (r < 0) return r; - r = append_session_tasks_max(handle, m, context->tasks_max); + r = append_session_tasks_max(pamh, m, context->tasks_max); if (r < 0) return r; - r = append_session_cpu_weight(handle, m, context->cpu_weight); + r = append_session_cpu_weight(pamh, m, context->cpu_weight); if (r < 0) return r; - r = append_session_io_weight(handle, m, context->io_weight); + r = append_session_io_weight(pamh, m, context->io_weight); if (r < 0) return r; @@ -914,12 +911,12 @@ static int create_session_message( } static void session_context_mangle( - pam_handle_t *handle, + pam_handle_t *pamh, SessionContext *c, UserRecord *ur, bool debug) { - assert(handle); + assert(pamh); assert(c); assert(ur); @@ -975,21 +972,21 @@ static void session_context_mangle( } if (c->seat && !streq(c->seat, "seat0") && c->vtnr != 0) { - pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0.", c->vtnr, c->seat); + pam_debug_syslog(pamh, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0.", c->vtnr, c->seat); c->vtnr = 0; } if (isempty(c->type)) { c->type = !isempty(c->display) ? "x11" : !isempty(c->tty) ? "tty" : "unspecified"; - pam_debug_syslog(handle, debug, "Automatically chose session type '%s'.", c->type); + pam_debug_syslog(pamh, debug, "Automatically chose session type '%s'.", c->type); } if (!c->area) c->area = ur->default_area; if (!isempty(c->area) && !filename_is_valid(c->area)) { - pam_syslog(handle, LOG_WARNING, "Specified area '%s' is not a valid filename, ignoring area request.", c->area); + pam_syslog(pamh, LOG_WARNING, "Specified area '%s' is not a valid filename, ignoring area request.", c->area); c->area = NULL; } @@ -1038,14 +1035,14 @@ static void session_context_mangle( ; } - pam_debug_syslog(handle, debug, "Automatically chose session class '%s'.", c->class); + pam_debug_syslog(pamh, debug, "Automatically chose session class '%s'.", c->class); } if (c->incomplete) { if (streq(c->class, "user")) c->class = "user-incomplete"; else - pam_syslog(handle, LOG_WARNING, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class); + pam_syslog(pamh, LOG_WARNING, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class); } c->remote = !isempty(c->remote_host) && !is_localhost(c->remote_host); @@ -1062,7 +1059,7 @@ static bool can_use_varlink(const SessionContext *c) { } static int register_session( - pam_handle_t *handle, + pam_handle_t *pamh, SessionContext *c, UserRecord *ur, bool debug, @@ -1072,7 +1069,7 @@ static int register_session( int r; - assert(handle); + assert(pamh); assert(c); assert(ur); assert(ret_seat); @@ -1081,19 +1078,19 @@ static int register_session( /* We don't register session class none with logind */ if (streq(c->class, "none")) { - pam_debug_syslog(handle, debug, "Skipping logind registration for session class none."); + pam_debug_syslog(pamh, debug, "Skipping logind registration for session class none."); *ret_seat = *ret_type = *ret_runtime_dir = NULL; return PAM_SUCCESS; } /* Make most of this a NOP on non-logind systems */ if (!logind_running()) { - pam_debug_syslog(handle, debug, "Skipping logind registration as logind is not running."); + pam_debug_syslog(pamh, debug, "Skipping logind registration as logind is not running."); *ret_seat = *ret_type = *ret_runtime_dir = NULL; return PAM_SUCCESS; } - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Asking logind to create session: " "uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s", ur->uid, getpid_cached(), @@ -1101,7 +1098,7 @@ static int register_session( c->type, c->class, strempty(c->desktop), strempty(c->seat), c->vtnr, strempty(c->tty), strempty(c->display), yes_no(c->remote), strempty(c->remote_user), strempty(c->remote_host)); - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Session limits: " "memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s runtime_max_sec=%s", strna(c->memory_max), strna(c->tasks_max), strna(c->cpu_weight), strna(c->io_weight), strna(c->runtime_max_sec)); @@ -1117,20 +1114,20 @@ static int register_session( r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.Login"); if (r < 0) - pam_debug_syslog_errno(handle, debug, r, "Failed to connect to logind via Varlink, falling back to D-Bus: %m"); + pam_debug_syslog_errno(pamh, debug, r, "Failed to connect to logind via Varlink, falling back to D-Bus: %m"); else { r = sd_varlink_set_allow_fd_passing_output(vl, true); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to enable output fd passing on Varlink socket: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to enable output fd passing on Varlink socket: %m"); r = sd_varlink_set_relative_timeout(vl, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to set relative timeout on Varlink socket: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to set relative timeout on Varlink socket: %m"); _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; r = pidref_set_self(&pidref); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to acquire PID reference on ourselves: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to acquire PID reference on ourselves: %m"); sd_json_variant *vreply = NULL; const char *error_id = NULL; @@ -1153,16 +1150,16 @@ static int register_session( JSON_BUILD_PAIR_STRING_NON_EMPTY("RemoteUser", c->remote_user), JSON_BUILD_PAIR_STRING_NON_EMPTY("RemoteHost", c->remote_host)); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to issue io.systemd.Login.CreateSession varlink call: %m"); if (streq_ptr(error_id, "io.systemd.Login.AlreadySessionMember")) { /* We are already in a session, don't do anything */ - pam_debug_syslog(handle, debug, "Not creating session: %s", error_id); + pam_debug_syslog(pamh, debug, "Not creating session: %s", error_id); *ret_seat = *ret_type= *ret_runtime_dir = NULL; return PAM_SUCCESS; } if (error_id) - return pam_syslog_errno(handle, LOG_ERR, sd_varlink_error_to_errno(error_id, vreply), + return pam_syslog_errno(pamh, LOG_ERR, sd_varlink_error_to_errno(error_id, vreply), "Varlink call io.systemd.Login.CreateSession failed: %s", error_id); struct { @@ -1187,7 +1184,7 @@ static int register_session( r = sd_json_dispatch(vreply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse CreateSession() reply: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to parse CreateSession() reply: %m"); id = p.id; runtime_path = p.runtime_path; @@ -1209,50 +1206,50 @@ static int register_session( _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; /* Talk to logind over the message bus */ - r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d); + r = pam_acquire_bus_connection(pamh, "pam-systemd", debug, &bus, &d); if (r != PAM_SUCCESS) return r; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = create_session_message( bus, - handle, + pamh, ur, c, /* avoid_pidfd= */ false, &m); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; r = sd_bus_call(bus, m, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { sd_bus_error_free(&error); - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "CreateSessionWithPIDFD() API is not available, retrying with CreateSession()."); m = sd_bus_message_unref(m); r = create_session_message(bus, - handle, + pamh, ur, c, /* avoid_pidfd= */ true, &m); if (r < 0) - return pam_bus_log_create_error(handle, r); + return pam_bus_log_create_error(pamh, r); r = sd_bus_call(bus, m, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply); } if (r < 0) { if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { /* We are already in a session, don't do anything */ - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Not creating session: %s", bus_error_message(&error, r)); *ret_seat = *ret_type = *ret_runtime_dir = NULL; return PAM_SUCCESS; } - pam_syslog(handle, LOG_ERR, + pam_syslog(pamh, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); return PAM_SESSION_ERR; } @@ -1269,10 +1266,10 @@ static int register_session( &real_vtnr, &existing); if (r < 0) - return pam_bus_log_parse_error(handle, r); + return pam_bus_log_parse_error(pamh, r); } - pam_debug_syslog(handle, debug, + pam_debug_syslog(pamh, debug, "Reply from logind: " "id=%s object_path=%s runtime_path=%s seat=%s vtnr=%u original_uid=%u", id, strna(object_path), runtime_path, real_seat, real_vtnr, original_uid); @@ -1280,7 +1277,7 @@ static int register_session( /* Please update manager_default_environment() in core/manager.c accordingly if more session envvars * shall be added. */ - r = update_environment(handle, "XDG_SESSION_ID", id); + r = update_environment(pamh, "XDG_SESSION_ID", id); if (r != PAM_SUCCESS) return r; @@ -1290,21 +1287,21 @@ static int register_session( _cleanup_free_ char *real_type = strdup(c->type); /* make copy because this might point to env block, which we are going to update shortly */ if (!real_type) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = update_environment(handle, "XDG_SESSION_TYPE", c->type); + r = update_environment(pamh, "XDG_SESSION_TYPE", c->type); if (r != PAM_SUCCESS) return r; - r = update_environment(handle, "XDG_SESSION_CLASS", c->class); + r = update_environment(pamh, "XDG_SESSION_CLASS", c->class); if (r != PAM_SUCCESS) return r; - r = update_environment(handle, "XDG_SESSION_DESKTOP", c->desktop); + r = update_environment(pamh, "XDG_SESSION_DESKTOP", c->desktop); if (r != PAM_SUCCESS) return r; - r = update_environment(handle, "XDG_SEAT", real_seat); + r = update_environment(pamh, "XDG_SEAT", real_seat); if (r != PAM_SUCCESS) return r; @@ -1312,28 +1309,28 @@ static int register_session( char buf[DECIMAL_STR_MAX(real_vtnr)]; xsprintf(buf, "%u", real_vtnr); - r = update_environment(handle, "XDG_VTNR", buf); + r = update_environment(pamh, "XDG_VTNR", buf); if (r != PAM_SUCCESS) return r; } - r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL); + r = pam_set_data(pamh, "systemd.existing", INT_TO_PTR(!!existing), NULL); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to install existing flag: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to install existing flag: @PAMERR@"); /* Don't set $XDG_RUNTIME_DIR if the user we now authenticated for does not match the * original user of the session. We do this in order not to result in privileged apps * clobbering the runtime directory unnecessarily. */ _cleanup_free_ char *rt = NULL; - if (original_uid == ur->uid && validate_runtime_directory(handle, runtime_path, ur->uid)) + if (original_uid == ur->uid && validate_runtime_directory(pamh, runtime_path, ur->uid)) if (strdup_to(&rt, runtime_path) < 0) - return pam_log_oom(handle); + return pam_log_oom(pamh); /* Everything worked, hence let's patch in the data we learned. Since 'real_set' points into the * D-Bus message, let's copy it and return it as a buffer */ _cleanup_free_ char *rs = NULL; if (strdup_to(&rs, real_seat) < 0) - return pam_log_oom(handle); + return pam_log_oom(pamh); c->vtnr = real_vtnr; c->seat = *ret_seat = TAKE_PTR(rs); @@ -1343,7 +1340,7 @@ static int register_session( return PAM_SUCCESS; } -static int import_shell_credentials(pam_handle_t *handle, bool debug) { +static int import_shell_credentials(pam_handle_t *pamh, bool debug) { static const char *const propagate[] = { "shell.prompt.prefix", "SHELL_PROMPT_PREFIX", @@ -1353,10 +1350,10 @@ static int import_shell_credentials(pam_handle_t *handle, bool debug) { }; int r; - assert(handle); + assert(pamh); STRV_FOREACH_PAIR(k, v, propagate) { - r = propagate_credential_to_environment(handle, debug, *k, *v); + r = propagate_credential_to_environment(pamh, debug, *k, *v); if (r != PAM_SUCCESS) return r; } @@ -1422,13 +1419,13 @@ static int mkdir_chown_open_directory( } static int make_area_runtime_directory( - pam_handle_t *handle, + pam_handle_t *pamh, UserRecord *ur, const char *runtime_directory, const char *area, char **ret) { - assert(handle); + assert(pamh); assert(ur); assert(runtime_directory); assert(area); @@ -1439,29 +1436,27 @@ static int make_area_runtime_directory( _cleanup_close_ int fd = open(runtime_directory, O_CLOEXEC|O_PATH|O_DIRECTORY); if (fd < 0) - return pam_syslog_errno(handle, LOG_ERR, errno, "Unable to open runtime directory '%s': %m", runtime_directory); + return pam_syslog_errno(pamh, LOG_ERR, errno, "Unable to open runtime directory '%s': %m", runtime_directory); _cleanup_close_ int fd_areas = mkdir_chown_open_directory(fd, "Areas", ur->uid, user_record_gid(ur), 0755); if (fd_areas < 0) - return pam_syslog_errno(handle, LOG_ERR, fd_areas, "Unable to create 'Areas' directory below '%s': %m", runtime_directory); + return pam_syslog_errno(pamh, LOG_ERR, fd_areas, "Unable to create 'Areas' directory below '%s': %m", runtime_directory); _cleanup_close_ int fd_area = mkdir_chown_open_directory(fd_areas, area, ur->uid, user_record_gid(ur), 0755); if (fd_area < 0) - return pam_syslog_errno(handle, LOG_ERR, fd_area, "Unable to create '%s' directory below '%s/Areas': %m", area, runtime_directory); + return pam_syslog_errno(pamh, LOG_ERR, fd_area, "Unable to create '%s' directory below '%s/Areas': %m", area, runtime_directory); char *j = path_join(runtime_directory, "Areas", area); if (!j) - return pam_log_oom(handle); + return pam_log_oom(pamh); *ret = j; return 0; } -static int export_legacy_dbus_address( - pam_handle_t *handle, - const char *runtime) { +static int export_legacy_dbus_address(pam_handle_t *pamh, const char *runtime) { - assert(handle); + assert(pamh); assert(runtime); /* We need to export $DBUS_SESSION_BUS_ADDRESS because various applications will not connect @@ -1479,34 +1474,34 @@ static int export_legacy_dbus_address( const char *s = strjoina(runtime, "/bus"); if (access(s, F_OK) < 0) { if (errno != ENOENT) - pam_syslog_errno(handle, LOG_WARNING, errno, "Failed to check if %s/bus exists, ignoring: %m", runtime); + pam_syslog_errno(pamh, LOG_WARNING, errno, "Failed to check if %s/bus exists, ignoring: %m", runtime); return PAM_SUCCESS; } _cleanup_free_ char *t = NULL; if (asprintf(&t, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0) - return pam_log_oom(handle); + return pam_log_oom(pamh); - return update_environment(handle, "DBUS_SESSION_BUS_ADDRESS", t); + return update_environment(pamh, "DBUS_SESSION_BUS_ADDRESS", t); } static int setup_runtime_directory( - pam_handle_t *handle, + pam_handle_t *pamh, UserRecord *ur, const char *runtime_directory, const char *area) { int r; - assert(handle); + assert(pamh); assert(ur); if (!runtime_directory) { /* If this is an area switch request, always reset $XDG_RUNTIME_DIR if we got nothing * to ensure the main runtime dir won't be clobbered. */ if (area) - return update_environment(handle, "XDG_RUNTIME_DIR", NULL); + return update_environment(pamh, "XDG_RUNTIME_DIR", NULL); return PAM_SUCCESS; } @@ -1517,22 +1512,22 @@ static int setup_runtime_directory( * clean-up of the whole $XDG_RUNTIME_DIR hierarchy when the user finally logs out. */ _cleanup_free_ char *per_area_runtime_directory = NULL; if (area) { - r = make_area_runtime_directory(handle, ur, runtime_directory, area, &per_area_runtime_directory); + r = make_area_runtime_directory(pamh, ur, runtime_directory, area, &per_area_runtime_directory); if (r != PAM_SUCCESS) return r; runtime_directory = per_area_runtime_directory; } - r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_directory); + r = update_environment(pamh, "XDG_RUNTIME_DIR", runtime_directory); if (r != PAM_SUCCESS) return r; - return export_legacy_dbus_address(handle, runtime_directory); + return export_legacy_dbus_address(pamh, runtime_directory); } static int setup_environment( - pam_handle_t *handle, + pam_handle_t *pamh, UserRecord *ur, const char *runtime_directory, const char *area, @@ -1540,7 +1535,7 @@ static int setup_environment( int r; - assert(handle); + assert(pamh); assert(ur); const char *h = ASSERT_PTR(user_record_home_directory(ur)); @@ -1552,28 +1547,28 @@ static int setup_environment( if (area) { _cleanup_free_ char *j = path_join(h, "Areas", area); if (!j) - return pam_log_oom(handle); + return pam_log_oom(pamh); _cleanup_close_ int fd = -EBADF; r = chase(j, /* root= */ NULL, CHASE_MUST_BE_DIRECTORY, &ha, &fd); if (r < 0) { /* Log the precise error */ - pam_syslog_errno(handle, LOG_WARNING, r, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory: %m", j, area); + pam_syslog_errno(pamh, LOG_WARNING, r, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory: %m", j, area); /* Also tell the user directly at login, but a bit more vague */ - pam_info(handle, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory.", j, area); + pam_info(pamh, "Path '%s' of requested user area '%s' is not accessible, reverting to regular home directory.", j, area); area = NULL; } else { /* Validate that the target is definitely owned by user */ struct stat st; if (fstat(fd, &st) < 0) - return pam_syslog_errno(handle, LOG_ERR, errno, "Unable to fstat() target area directory '%s': %m", ha); + return pam_syslog_errno(pamh, LOG_ERR, errno, "Unable to fstat() target area directory '%s': %m", ha); if (st.st_uid != ur->uid) { - pam_syslog(handle, LOG_ERR, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); + pam_syslog(pamh, LOG_ERR, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); /* Also tell the user directly at login. */ - pam_info(handle, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); + pam_info(pamh, "Path '%s' of requested user area '%s' is not owned by user, reverting to regular home directory.", ha, area); area = NULL; } else { /* All good, now make a copy of the area string, since we quite likely are @@ -1581,30 +1576,30 @@ static int setup_environment( * update_environment() call below */ area_copy = strdup(area); if (!area_copy) - return pam_log_oom(handle); + return pam_log_oom(pamh); - pam_debug_syslog(handle, debug, "Area '%s' selected, setting $HOME to '%s'.", area, ha); + pam_debug_syslog(pamh, debug, "Area '%s' selected, setting $HOME to '%s'.", area, ha); h = ha; area = area_copy; } } } - r = update_environment(handle, "XDG_AREA", area); + r = update_environment(pamh, "XDG_AREA", area); if (r != PAM_SUCCESS) return r; - r = update_environment(handle, "HOME", h); + r = update_environment(pamh, "HOME", h); if (r != PAM_SUCCESS) return r; - return setup_runtime_directory(handle, ur, runtime_directory, area); + return setup_runtime_directory(pamh, ur, runtime_directory, area); } -static int open_osc_context(pam_handle_t *handle, const char *session_type, UserRecord *ur, bool debug) { +static int open_osc_context(pam_handle_t *pamh, const char *session_type, UserRecord *ur, bool debug) { int r; - assert(handle); + assert(pamh); assert(ur); /* If this is a TTY session, then output the session start OSC sequence */ @@ -1612,7 +1607,7 @@ static int open_osc_context(pam_handle_t *handle, const char *session_type, User if (!streq_ptr(session_type, "tty")) return PAM_SUCCESS; - const char *e = pam_getenv(handle, "TERM"); + const char *e = pam_getenv(pamh, "TERM"); if (!e) e = getenv("TERM"); if (streq_ptr(e, "dumb")) @@ -1630,7 +1625,7 @@ static int open_osc_context(pam_handle_t *handle, const char *session_type, User * so that we don't delay tty hang-up. */ _cleanup_close_ int tty_opath_fd = fd_reopen(STDOUT_FILENO, O_PATH|O_CLOEXEC); if (tty_opath_fd < 0) - pam_debug_syslog_errno(handle, debug, tty_opath_fd, "Failed to pin TTY, ignoring: %m"); + pam_debug_syslog_errno(pamh, debug, tty_opath_fd, "Failed to pin TTY, ignoring: %m"); else tty_opath_fd = fd_move_above_stdio(tty_opath_fd); @@ -1638,32 +1633,32 @@ static int open_osc_context(pam_handle_t *handle, const char *session_type, User sd_id128_t osc_id; r = osc_context_open_session( ur->user_name, - pam_getenv(handle, "XDG_SESSION_ID"), + pam_getenv(pamh, "XDG_SESSION_ID"), &osc, &osc_id); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to prepare OSC sequence: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to prepare OSC sequence: %m"); r = loop_write(STDOUT_FILENO, osc, SIZE_MAX); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to write OSC sequence to TTY: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to write OSC sequence to TTY: %m"); /* Remember the OSC context id, so that we can close it cleanly later */ _cleanup_free_ sd_id128_t *osc_id_copy = newdup(sd_id128_t, &osc_id, 1); if (!osc_id_copy) - return pam_log_oom(handle); + return pam_log_oom(pamh); - r = pam_set_data(handle, "systemd.osc-context-id", osc_id_copy, pam_cleanup_free); + r = pam_set_data(pamh, "systemd.osc-context-id", osc_id_copy, pam_cleanup_free); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM OSC sequence ID data: @PAMERR@"); TAKE_PTR(osc_id_copy); if (tty_opath_fd >= 0) { - r = pam_set_data(handle, "systemd.osc-context-fd", FD_TO_PTR(tty_opath_fd), pam_cleanup_close); + r = pam_set_data(pamh, "systemd.osc-context-fd", FD_TO_PTR(tty_opath_fd), pam_cleanup_close); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM OSC sequence fd data: @PAMERR@"); TAKE_FD(tty_opath_fd); @@ -1672,32 +1667,32 @@ static int open_osc_context(pam_handle_t *handle, const char *session_type, User return PAM_SUCCESS; } -static int close_osc_context(pam_handle_t *handle, bool debug) { +static int close_osc_context(pam_handle_t *pamh, bool debug) { int r; - assert(handle); + assert(pamh); const void *p; int tty_opath_fd = -EBADF; - r = pam_get_data(handle, "systemd.osc-context-fd", &p); + r = pam_get_data(pamh, "systemd.osc-context-fd", &p); if (r == PAM_SUCCESS) tty_opath_fd = PTR_TO_FD(p); else if (r != PAM_NO_MODULE_DATA) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM OSC context fd: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM OSC context fd: @PAMERR@"); if (tty_opath_fd < 0) return PAM_SUCCESS; const sd_id128_t *osc_id = NULL; - r = pam_get_data(handle, "systemd.osc-context-id", (const void**) &osc_id); + r = pam_get_data(pamh, "systemd.osc-context-id", (const void**) &osc_id); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM OSC context id data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM OSC context id data: @PAMERR@"); if (!osc_id) return PAM_SUCCESS; /* Now open the original TTY again, so that we can write on it */ _cleanup_close_ int fd = fd_reopen(tty_opath_fd, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); if (fd < 0) { - pam_debug_syslog_errno(handle, debug, fd, "Failed to reopen TTY, ignoring: %m"); + pam_debug_syslog_errno(pamh, debug, fd, "Failed to reopen TTY, ignoring: %m"); return PAM_SUCCESS; } @@ -1712,24 +1707,24 @@ static int close_osc_context(pam_handle_t *handle, bool debug) { _cleanup_free_ char *osc = NULL; r = osc_context_close(*osc_id, &osc); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to prepare OSC sequence: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to prepare OSC sequence: %m"); /* When we are closing things, the TTY might not take our writes anymore. Accept that gracefully. */ r = loop_write(fd, osc, SIZE_MAX); if (r < 0) - pam_debug_syslog_errno(handle, debug, r, "Failed to write OSC sequence to TTY, ignoring: %m"); + pam_debug_syslog_errno(pamh, debug, r, "Failed to write OSC sequence to TTY, ignoring: %m"); return PAM_SUCCESS; } _public_ PAM_EXTERN int pam_sm_open_session( - pam_handle_t *handle, + pam_handle_t *pamh, int flags, int argc, const char **argv) { int r; - assert(handle); + assert(pamh); r = dlopen_libpam(); if (r < 0) @@ -1740,7 +1735,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( uint64_t default_capability_bounding_set = CAP_MASK_UNSET, default_capability_ambient_set = CAP_MASK_UNSET; const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL, *area_pam = NULL; bool debug = false; - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, &class_pam, &type_pam, @@ -1751,69 +1746,69 @@ _public_ PAM_EXTERN int pam_sm_open_session( &default_capability_ambient_set) < 0) return PAM_SESSION_ERR; - pam_debug_syslog(handle, debug, "pam-systemd: initializing..."); + pam_debug_syslog(pamh, debug, "pam-systemd: initializing..."); _cleanup_(user_record_unrefp) UserRecord *ur = NULL; - r = acquire_user_record(handle, &ur); + r = acquire_user_record(pamh, &ur); if (r != PAM_SUCCESS) return r; SessionContext c = {}; r = pam_get_item_many( - handle, + pamh, PAM_SERVICE, &c.service, PAM_XDISPLAY, &c.display, PAM_TTY, &c.tty, PAM_RUSER, &c.remote_user, PAM_RHOST, &c.remote_host); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM items: @PAMERR@"); - c.seat = getenv_harder(handle, "XDG_SEAT", NULL); - c.vtnr = getenv_harder_uint32(handle, "XDG_VTNR", 0); - c.type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam); - c.class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam); - c.desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam); - c.area = getenv_harder(handle, "XDG_AREA", area_pam); - c.incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false); + c.seat = getenv_harder(pamh, "XDG_SEAT", NULL); + c.vtnr = getenv_harder_uint32(pamh, "XDG_VTNR", 0); + c.type = getenv_harder(pamh, "XDG_SESSION_TYPE", type_pam); + c.class = getenv_harder(pamh, "XDG_SESSION_CLASS", class_pam); + c.desktop = getenv_harder(pamh, "XDG_SESSION_DESKTOP", desktop_pam); + c.area = getenv_harder(pamh, "XDG_AREA", area_pam); + c.incomplete = getenv_harder_bool(pamh, "XDG_SESSION_INCOMPLETE", false); r = pam_get_data_many( - handle, + pamh, "systemd.memory_max", &c.memory_max, "systemd.tasks_max", &c.tasks_max, "systemd.cpu_weight", &c.cpu_weight, "systemd.io_weight", &c.io_weight, "systemd.runtime_max_sec", &c.runtime_max_sec); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM data: @PAMERR@"); - session_context_mangle(handle, &c, ur, debug); + session_context_mangle(pamh, &c, ur, debug); _cleanup_free_ char *seat_buffer = NULL, *type_buffer = NULL, *runtime_dir = NULL; - r = register_session(handle, &c, ur, debug, &seat_buffer, &type_buffer, &runtime_dir); + r = register_session(pamh, &c, ur, debug, &seat_buffer, &type_buffer, &runtime_dir); if (r != PAM_SUCCESS) return r; - r = import_shell_credentials(handle, debug); + r = import_shell_credentials(pamh, debug); if (r != PAM_SUCCESS) return r; - r = setup_environment(handle, ur, runtime_dir, c.area, debug); + r = setup_environment(pamh, ur, runtime_dir, c.area, debug); if (r != PAM_SUCCESS) return r; if (default_capability_ambient_set == CAP_MASK_UNSET) default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat); - r = apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set); + r = apply_user_record_settings(pamh, ur, debug, default_capability_bounding_set, default_capability_ambient_set); if (r != PAM_SUCCESS) return r; - return open_osc_context(handle, c.type, ur, debug); + return open_osc_context(pamh, c.type, ur, debug); } _public_ PAM_EXTERN int pam_sm_close_session( - pam_handle_t *handle, + pam_handle_t *pamh, int flags, int argc, const char **argv) { @@ -1822,11 +1817,11 @@ _public_ PAM_EXTERN int pam_sm_close_session( const char *id; int r; - assert(handle); + assert(pamh); pam_log_setup(); - if (parse_argv(handle, + if (parse_argv(pamh, argc, argv, /* class= */ NULL, /* type= */ NULL, @@ -1837,25 +1832,25 @@ _public_ PAM_EXTERN int pam_sm_close_session( /* default_capability_ambient_set= */ NULL) < 0) return PAM_SESSION_ERR; - pam_debug_syslog(handle, debug, "pam-systemd: shutting down..."); + pam_debug_syslog(pamh, debug, "pam-systemd: shutting down..."); /* Only release session if it wasn't pre-existing when we * tried to create it */ - r = pam_get_data(handle, "systemd.existing", &existing); + r = pam_get_data(pamh, "systemd.existing", &existing); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get PAM systemd.existing data: @PAMERR@"); - (void) close_osc_context(handle, debug); + (void) close_osc_context(pamh, debug); - id = pam_getenv(handle, "XDG_SESSION_ID"); + id = pam_getenv(pamh, "XDG_SESSION_ID"); if (id && !existing) { _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; bool done = false; r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.Login"); if (r < 0) - pam_debug_syslog_errno(handle, debug, r, "Failed to connect to logind via Varlink, falling back to D-Bus: %m"); + pam_debug_syslog_errno(pamh, debug, r, "Failed to connect to logind via Varlink, falling back to D-Bus: %m"); else { _cleanup_(sd_json_variant_unrefp) sd_json_variant *vreply = NULL; const char *error_id = NULL; @@ -1866,10 +1861,10 @@ _public_ PAM_EXTERN int pam_sm_close_session( &error_id, SD_JSON_BUILD_PAIR_STRING("Id", id)); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to issue io.systemd.Login.ReleaseSession varlink call: %m"); if (error_id) - return pam_syslog_errno(handle, LOG_ERR, sd_varlink_error_to_errno(error_id, vreply), + return pam_syslog_errno(pamh, LOG_ERR, sd_varlink_error_to_errno(error_id, vreply), "Varlink call io.systemd.Login.ReleaseSession failed: %s", error_id); done = true; @@ -1883,13 +1878,13 @@ _public_ PAM_EXTERN int pam_sm_close_session( /* Before we go and close the FIFO we need to tell logind that this is a clean session * shutdown, so that it doesn't just go and slaughter us immediately after closing the fd */ - r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d); + r = pam_acquire_bus_connection(pamh, "pam-systemd", debug, &bus, &d); if (r != PAM_SUCCESS) return r; r = bus_call_method(bus, bus_login_mgr, "ReleaseSession", &error, NULL, "s", id); if (r < 0) - return pam_syslog_pam_error(handle, LOG_ERR, PAM_SESSION_ERR, + return pam_syslog_pam_error(pamh, LOG_ERR, PAM_SESSION_ERR, "Failed to release session: %s", bus_error_message(&error, r)); } } diff --git a/src/login/pam_systemd_loadkey.c b/src/login/pam_systemd_loadkey.c index 62e3881a2caee..3e0df8c86b31b 100644 --- a/src/login/pam_systemd_loadkey.c +++ b/src/login/pam_systemd_loadkey.c @@ -11,13 +11,13 @@ static const char DEFAULT_KEYNAME[] = "cryptsetup"; _public_ PAM_EXTERN int pam_sm_authenticate( - pam_handle_t *handle, + pam_handle_t *pamh, int flags, int argc, const char **argv) { int r; - assert(handle); + assert(pamh); r = dlopen_libpam(); if (r < 0) @@ -41,10 +41,10 @@ _public_ PAM_EXTERN int pam_sm_authenticate( else if (streq(argv[i], "debug")) debug = true; else - pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); + pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]); } - pam_debug_syslog(handle, debug, "pam-systemd-loadkey: initializing..."); + pam_debug_syslog(pamh, debug, "pam-systemd-loadkey: initializing..."); /* Retrieve the key. */ @@ -52,13 +52,13 @@ _public_ PAM_EXTERN int pam_sm_authenticate( serial = request_key("user", keyname, NULL, 0); if (serial < 0) { if (errno == ENOKEY) { - pam_debug_syslog(handle, debug, "Key not found: %s", keyname); + pam_debug_syslog(pamh, debug, "Key not found: %s", keyname); return PAM_AUTHINFO_UNAVAIL; } else if (errno == EKEYEXPIRED) { - pam_debug_syslog(handle, debug, "Key expired: %s", keyname); + pam_debug_syslog(pamh, debug, "Key expired: %s", keyname); return PAM_AUTHINFO_UNAVAIL; } else - return pam_syslog_errno(handle, LOG_ERR, errno, "Failed to look up the key: %m"); + return pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to look up the key: %m"); } _cleanup_(erase_and_freep) void *p = NULL; @@ -66,30 +66,30 @@ _public_ PAM_EXTERN int pam_sm_authenticate( r = keyring_read(serial, &p, &n); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to read the key: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to read the key: %m"); /* Split the key by NUL. Set the last item as authtok. */ _cleanup_strv_free_erase_ char **passwords = strv_parse_nulstr(p, n); if (!passwords) - return pam_log_oom(handle); + return pam_log_oom(pamh); size_t passwords_len = strv_length(passwords); if (passwords_len == 0) { - pam_debug_syslog(handle, debug, "Key is empty."); + pam_debug_syslog(pamh, debug, "Key is empty."); return PAM_AUTHINFO_UNAVAIL; } else if (passwords_len > 1) - pam_debug_syslog(handle, debug, "Multiple passwords found in the key. Using the last one."); + pam_debug_syslog(pamh, debug, "Multiple passwords found in the key. Using the last one."); - r = pam_set_item(handle, PAM_AUTHTOK, passwords[passwords_len - 1]); + r = pam_set_item(pamh, PAM_AUTHTOK, passwords[passwords_len - 1]); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@"); return PAM_SUCCESS; } _public_ PAM_EXTERN int pam_sm_setcred( - pam_handle_t *handle, + pam_handle_t *pamh, int flags, int argc, const char **argv) { diff --git a/src/shared/pam-util.c b/src/shared/pam-util.c index 711bb22769177..d6158ec8caec4 100644 --- a/src/shared/pam-util.c +++ b/src/shared/pam-util.c @@ -73,20 +73,20 @@ int errno_to_pam_error(int error) { return ERRNO_VALUE(error) == ENOMEM ? PAM_BUF_ERR : PAM_SERVICE_ERR; } -int pam_syslog_errno(pam_handle_t *handle, int level, int error, const char *format, ...) { +int pam_syslog_errno(pam_handle_t *pamh, int level, int error, const char *format, ...) { va_list ap; error = ERRNO_VALUE(error); LOCAL_ERRNO(error); va_start(ap, format); - sym_pam_vsyslog(handle, level, format, ap); + sym_pam_vsyslog(pamh, level, format, ap); va_end(ap); return errno_to_pam_error(error); } -int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char *format, ...) { +int pam_syslog_pam_error(pam_handle_t *pamh, int level, int error, const char *format, ...) { /* This wraps pam_syslog() but will replace @PAMERR@ with a string from pam_strerror(). * @PAMERR@ must be at the very end. */ @@ -95,7 +95,7 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char const char *p = endswith(format, "@PAMERR@"); if (p) { - const char *pamerr = sym_pam_strerror(handle, error); + const char *pamerr = sym_pam_strerror(pamh, error); if (strchr(pamerr, '%')) pamerr = "n/a"; /* We cannot have any formatting chars */ @@ -103,10 +103,10 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char xsprintf(buf, "%.*s%s", (int)(p - format), format, pamerr); DISABLE_WARNING_FORMAT_NONLITERAL; - sym_pam_vsyslog(handle, level, buf, ap); + sym_pam_vsyslog(pamh, level, buf, ap); REENABLE_WARNING; } else - sym_pam_vsyslog(handle, level, format, ap); + sym_pam_vsyslog(pamh, level, format, ap); va_end(ap); @@ -142,7 +142,7 @@ static PamBusData *pam_bus_data_free(PamBusData *d) { DEFINE_TRIVIAL_CLEANUP_FUNC(PamBusData*, pam_bus_data_free); -static void pam_bus_data_destroy(pam_handle_t *handle, void *data, int error_status) { +static void pam_bus_data_destroy(pam_handle_t *pamh, void *data, int error_status) { /* Destructor when called from PAM. Note that error_status is supposed to tell us via PAM_DATA_SILENT * whether we are called in a forked off child of the PAM session or in the original parent. We don't * bother with that however, and instead rely on the PID checks that sd_bus_flush_close_unref() does @@ -156,7 +156,7 @@ static void pam_bus_data_destroy(pam_handle_t *handle, void *data, int error_sta if (FLAGS_SET(error_status, PAM_DATA_SILENT) && d->bus && bus_origin_changed(d->bus)) /* Please adjust test/units/end.sh when updating the log message. */ - sym_pam_syslog(handle, LOG_DEBUG, + sym_pam_syslog(pamh, LOG_DEBUG, "Warning: cannot close sd-bus connection (%s) after fork when it was opened before the fork.", strna(d->cache_id)); @@ -180,7 +180,7 @@ static char* pam_make_bus_cache_id(const char *module_name) { void pam_bus_data_disconnectp(PamBusData **_d) { PamBusData *d = *ASSERT_PTR(_d); - pam_handle_t *handle; + pam_handle_t *pamh; int r; /* Disconnects the connection explicitly (for use via _cleanup_()) when called */ @@ -188,17 +188,17 @@ void pam_bus_data_disconnectp(PamBusData **_d) { if (!d) return; - handle = ASSERT_PTR(d->pam_handle); /* Keep a reference to the session even after 'd' might be invalidated */ + pamh = ASSERT_PTR(d->pam_handle); /* Keep a reference to the session even after 'd' might be invalidated */ - r = sym_pam_set_data(handle, ASSERT_PTR(d->cache_id), NULL, NULL); + r = sym_pam_set_data(pamh, ASSERT_PTR(d->cache_id), NULL, NULL); if (r != PAM_SUCCESS) - pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to release PAM user record data, ignoring: @PAMERR@"); + pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM user record data, ignoring: @PAMERR@"); /* Note, the pam_set_data() call will invalidate 'd', don't access here anymore */ } int pam_acquire_bus_connection( - pam_handle_t *handle, + pam_handle_t *pamh, const char *module_name, bool debug, sd_bus **ret_bus, @@ -208,39 +208,39 @@ int pam_acquire_bus_connection( _cleanup_free_ char *cache_id = NULL; int r; - assert(handle); + assert(pamh); assert(module_name); assert(ret_bus); cache_id = pam_make_bus_cache_id(module_name); if (!cache_id) - return pam_log_oom(handle); + return pam_log_oom(pamh); /* We cache the bus connection so that we can share it between the session and the authentication hooks */ - r = sym_pam_get_data(handle, cache_id, (const void**) &d); + r = sym_pam_get_data(pamh, cache_id, (const void**) &d); if (r == PAM_SUCCESS && d) goto success; if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get bus connection: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get bus connection: @PAMERR@"); d = new(PamBusData, 1); if (!d) - return pam_log_oom(handle); + return pam_log_oom(pamh); *d = (PamBusData) { .cache_id = TAKE_PTR(cache_id), - .pam_handle = handle, + .pam_handle = pamh, }; r = sd_bus_open_system(&d->bus); if (r < 0) - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to connect to system bus: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to connect to system bus: %m"); - r = sym_pam_set_data(handle, d->cache_id, d, pam_bus_data_destroy); + r = sym_pam_set_data(pamh, d->cache_id, d, pam_bus_data_destroy); if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); - pam_debug_syslog(handle, debug, "New sd-bus connection (%s) opened.", d->cache_id); + pam_debug_syslog(pamh, debug, "New sd-bus connection (%s) opened.", d->cache_id); success: *ret_bus = sd_bus_ref(d->bus); @@ -253,38 +253,34 @@ int pam_acquire_bus_connection( return PAM_SUCCESS; } -int pam_get_bus_data( - pam_handle_t *handle, - const char *module_name, - PamBusData **ret) { - +int pam_get_bus_data(pam_handle_t *pamh, const char *module_name, PamBusData **ret) { PamBusData *d = NULL; _cleanup_free_ char *cache_id = NULL; int r; - assert(handle); + assert(pamh); assert(module_name); assert(ret); cache_id = pam_make_bus_cache_id(module_name); if (!cache_id) - return pam_log_oom(handle); + return pam_log_oom(pamh); /* We cache the bus connection so that we can share it between the session and the authentication hooks */ - r = sym_pam_get_data(handle, cache_id, (const void**) &d); + r = sym_pam_get_data(pamh, cache_id, (const void**) &d); if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) - return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get bus connection: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get bus connection: @PAMERR@"); *ret = d; return PAM_SUCCESS; } -void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status) { +void pam_cleanup_free(pam_handle_t *pamh, void *data, int error_status) { /* A generic destructor for pam_set_data() that just frees the specified data */ free(data); } -void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status) { +void pam_cleanup_close(pam_handle_t *pamh, void *data, int error_status) { /* A generic destructor for pam_set_data() that just closes the specified fd. * @@ -298,13 +294,13 @@ void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status) { safe_close(PTR_TO_FD(data)); } -int pam_get_item_many_internal(pam_handle_t *handle, ...) { +int pam_get_item_many_internal(pam_handle_t *pamh, ...) { va_list ap; int r; - assert(handle); + assert(pamh); - va_start(ap, handle); + va_start(ap, pamh); for (;;) { int item_type = va_arg(ap, int); if (item_type <= 0) { @@ -313,7 +309,7 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) { } const void **value = ASSERT_PTR(va_arg(ap, const void **)); - r = sym_pam_get_item(handle, item_type, value); + r = sym_pam_get_item(pamh, item_type, value); if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS)) break; } @@ -322,13 +318,13 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) { return r; } -int pam_get_data_many_internal(pam_handle_t *handle, ...) { +int pam_get_data_many_internal(pam_handle_t *pamh, ...) { va_list ap; int r; - assert(handle); + assert(pamh); - va_start(ap, handle); + va_start(ap, pamh); for (;;) { const char *data_name = va_arg(ap, const char *); if (!data_name) { @@ -337,7 +333,7 @@ int pam_get_data_many_internal(pam_handle_t *handle, ...) { } const void **value = ASSERT_PTR(va_arg(ap, const void **)); - r = sym_pam_get_data(handle, data_name, value); + r = sym_pam_get_data(pamh, data_name, value); if (!IN_SET(r, PAM_NO_MODULE_DATA, PAM_SUCCESS)) break; } @@ -346,11 +342,11 @@ int pam_get_data_many_internal(pam_handle_t *handle, ...) { return r; } -int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) { +int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, const char *fmt, ...) { va_list args; int r; - assert(handle); + assert(pamh); assert(fmt); /* This is just like pam_prompt(), but does not noisily (i.e. beyond LOG_DEBUG) log on its own, but leaves that to the caller */ @@ -363,11 +359,11 @@ int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, co return PAM_BUF_ERR; const struct pam_conv *conv = NULL; - r = sym_pam_get_item(handle, PAM_CONV, (const void**) &conv); + r = sym_pam_get_item(pamh, PAM_CONV, (const void**) &conv); if (!IN_SET(r, PAM_SUCCESS, PAM_BAD_ITEM)) - return pam_syslog_pam_error(handle, LOG_DEBUG, r, "Failed to get conversation function structure: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_DEBUG, r, "Failed to get conversation function structure: @PAMERR@"); if (!conv || !conv->conv) { - sym_pam_syslog(handle, LOG_DEBUG, "No conversation function."); + sym_pam_syslog(pamh, LOG_DEBUG, "No conversation function."); return PAM_SYSTEM_ERR; } @@ -380,7 +376,7 @@ int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, co r = conv->conv(1, &pmessage, &response, conv->appdata_ptr); _cleanup_(erase_and_freep) char *rr = response ? response->resp : NULL; /* make sure string is freed + erased */ if (r != PAM_SUCCESS) - return pam_syslog_pam_error(handle, LOG_DEBUG, r, "Conversation function failed: @PAMERR@"); + return pam_syslog_pam_error(pamh, LOG_DEBUG, r, "Conversation function failed: @PAMERR@"); if (ret_response) *ret_response = TAKE_PTR(rr); diff --git a/src/shared/pam-util.h b/src/shared/pam-util.h index 15204eb9394bc..2464e144fb4e7 100644 --- a/src/shared/pam-util.h +++ b/src/shared/pam-util.h @@ -33,9 +33,9 @@ void pam_log_setup(void); int errno_to_pam_error(int error) _const_; -int pam_syslog_errno(pam_handle_t *handle, int level, int error, const char *format, ...) _printf_(4,5); +int pam_syslog_errno(pam_handle_t *pamh, int level, int error, const char *format, ...) _printf_(4,5); -int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char *format, ...) _printf_(4,5); +int pam_syslog_pam_error(pam_handle_t *pamh, int level, int error, const char *format, ...) _printf_(4,5); /* Call sym_pam_syslog if debug is enabled */ #define pam_debug_syslog(handle, debug, fmt, ...) \ @@ -53,19 +53,19 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char errno_to_pam_error(_error); \ }) -static inline int pam_log_oom(pam_handle_t *handle) { +static inline int pam_log_oom(pam_handle_t *pamh) { /* This is like log_oom(), but uses PAM logging */ - return pam_syslog_errno(handle, LOG_ERR, ENOMEM, "Out of memory."); + return pam_syslog_errno(pamh, LOG_ERR, ENOMEM, "Out of memory."); } -static inline int pam_bus_log_create_error(pam_handle_t *handle, int r) { +static inline int pam_bus_log_create_error(pam_handle_t *pamh, int r) { /* This is like bus_log_create_error(), but uses PAM logging */ - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to create bus message: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to create bus message: %m"); } -static inline int pam_bus_log_parse_error(pam_handle_t *handle, int r) { +static inline int pam_bus_log_parse_error(pam_handle_t *pamh, int r) { /* This is like bus_log_parse_error(), but uses PAM logging */ - return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse bus message: %m"); + return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to parse bus message: %m"); } typedef struct PamBusData PamBusData; @@ -74,23 +74,23 @@ void pam_bus_data_disconnectp(PamBusData **d); /* Use a different module name per different PAM module. They are all loaded in the same namespace, and this * helps avoid a clash in the internal data structures of sd-bus. It will be used as key for cache items. */ int pam_acquire_bus_connection( - pam_handle_t *handle, + pam_handle_t *pamh, const char *module_name, bool debug, sd_bus **ret_bus, PamBusData **ret_pam_bus_data); -int pam_get_bus_data(pam_handle_t *handle, const char *module_name, PamBusData **ret); +int pam_get_bus_data(pam_handle_t *pamh, const char *module_name, PamBusData **ret); -void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status); -void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status); +void pam_cleanup_free(pam_handle_t *pamh, void *data, int error_status); +void pam_cleanup_close(pam_handle_t *pamh, void *data, int error_status); -int pam_get_item_many_internal(pam_handle_t *handle, ...); +int pam_get_item_many_internal(pam_handle_t *pamh, ...); #define pam_get_item_many(handle, ...) pam_get_item_many_internal(handle, __VA_ARGS__, -1) -int pam_get_data_many_internal(pam_handle_t *handle, ...) _sentinel_; +int pam_get_data_many_internal(pam_handle_t *pamh, ...) _sentinel_; #define pam_get_data_many(handle, ...) pam_get_data_many_internal(handle, __VA_ARGS__, NULL) -int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) _printf_(4,5); +int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, const char *fmt, ...) _printf_(4,5); #else