diff --git a/README b/README index 9492d717dec06..2d6d30dc78e11 100644 --- a/README +++ b/README @@ -212,10 +212,10 @@ 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 (optional) 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..ff8cb279a8e32 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', @@ -1046,22 +1037,18 @@ 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 = [] + 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 - -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 +conf.set10('HAVE_LIBCRYPT', have) bpf_framework = get_option('bpf-framework') bpf_compiler = get_option('bpf-compiler') @@ -1180,7 +1167,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) @@ -1594,10 +1581,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 @@ -3124,6 +3112,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/core/exec-invoke.c b/src/core/exec-invoke.c index cf47d996b29a6..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(); @@ -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/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/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/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/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/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/libcrypt-util.c b/src/shared/libcrypt-util.c index 594963ac6b05f..85069314be497 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -1,168 +1,133 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include -#include +#if HAVE_LIBCRYPT +# include +#endif #include "alloc-util.h" +#include "dlfcn-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) { +#if HAVE_LIBCRYPT +static void *libcrypt_dl = NULL; -#if HAVE_CRYPT_GENSALT_RA - const char *e; - char *salt; +static DLSYM_PROTOTYPE(crypt_gensalt_ra) = NULL; +static DLSYM_PROTOTYPE(crypt_preferred_method) = NULL; +static DLSYM_PROTOTYPE(crypt_ra) = NULL; - /* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt). - * crypt_gensalt_ra() is usually provided by libxcrypt. */ +int dlopen_libcrypt(void) { +#ifdef __GLIBC__ + static int cached = 0; + int r; - e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); - if (!e) -#if HAVE_CRYPT_PREFERRED_METHOD - e = crypt_preferred_method(); + 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 - e = "$6$"; + 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 - - log_debug("Generating salt for hash prefix: %s", e); - - salt = crypt_gensalt_ra(e, 0, NULL, 0); - if (!salt) - return -errno; - - *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 make_salt(char **ret) { + const char *e; + char *salt; 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$"); + assert(ret); - /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ - r = crypto_random_bytes(raw, sizeof(raw)); + r = dlopen_libcrypt(); if (r < 0) return r; - salt = new(char, 3+sizeof(raw)+1+1); - if (!salt) - return -ENOMEM; + e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); + if (!e) + e = sym_crypt_preferred_method(); - /* 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; + log_debug("Generating salt for hash prefix: %s", e); + + salt = sym_crypt_gensalt_ra(e, 0, NULL, 0); + if (!salt) + return -errno; *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(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_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; + int r, cd_size = 0; - assert(!!cd_data == !!cd_size); + assert(password); + assert(ret); 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 = sym_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); } -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; + 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; @@ -176,6 +141,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) @@ -186,3 +153,20 @@ 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 + * 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..3f79916cbc0be 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -3,11 +3,21 @@ #include "shared-forward.h" +#if HAVE_LIBCRYPT +int dlopen_libcrypt(void); int make_salt(char **ret); -int hash_password_full(const char *password, void **cd_data, int *cd_size, 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 dlopen_libcrypt(void) { + return -EOPNOTSUPP; +} static inline int hash_password(const char *password, char **ret) { - return hash_password_full(password, NULL, NULL, ret); + return -EOPNOTSUPP; } +#endif + 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); 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/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 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/meson.build b/src/test/meson.build index a21f85c2ecb27..6a26eb3f87ce5 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -345,7 +345,7 @@ executables += [ }, test_template + { 'sources' : files('test-libcrypt-util.c'), - 'dependencies' : libcrypt, + 'conditions' : ['HAVE_LIBCRYPT'], 'timeout' : 120, }, test_template + { 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 92eda2e1a7cc1..792b2b2ef9026 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -1,41 +1,25 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "libcrypt-util.h" #include "strv.h" #include "tests.h" -static void test_crypt_preferred_method(void) { - log_info("/* %s */", __func__); - - log_info("crypt_preferred_method: %s", -#if HAVE_CRYPT_PREFERRED_METHOD - crypt_preferred_method() -#else - "(not available)" -#endif - ); -} - -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) { /* 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,80 +27,46 @@ 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; + } #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__); - - _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_OK(hash_password(i, &hashed)); + log_debug("\"%s\" → \"%s\"", i, hashed); + + 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-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); 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())); diff --git a/tools/setup-musl-build.sh b/tools/setup-musl-build.sh index b0fa764fe414d..d264cc7bd5fd8 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 @@ -53,7 +53,6 @@ LINKS=( security selinux sys/acl.h - sys/capability.h tss2 xen xkbcommon @@ -63,6 +62,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 +82,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}" "${@}"