From fc53809803cd2bc2434e312b19a18fa36776da12 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 05:50:40 +0200 Subject: Adding upstream version 256. Signed-off-by: Daniel Baumann --- src/userdb/20-systemd-userdb.conf.in | 6 ++ src/userdb/meson.build | 17 ++++++ src/userdb/userdbctl.c | 79 ++++++++++++------------- src/userdb/userdbd-manager.c | 108 +++++++++++++++++++++++------------ src/userdb/userdbd.c | 2 +- src/userdb/userwork.c | 32 ++++++----- 6 files changed, 150 insertions(+), 94 deletions(-) create mode 100644 src/userdb/20-systemd-userdb.conf.in (limited to 'src/userdb') diff --git a/src/userdb/20-systemd-userdb.conf.in b/src/userdb/20-systemd-userdb.conf.in new file mode 100644 index 0000000..031fc3a --- /dev/null +++ b/src/userdb/20-systemd-userdb.conf.in @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Make sure SSH authorized keys recorded in user records can be consumed by SSH +# +AuthorizedKeysCommand {{BINDIR}}/userdbctl ssh-authorized-keys %u +AuthorizedKeysCommandUser root diff --git a/src/userdb/meson.build b/src/userdb/meson.build index 2d701c8..413f2be 100644 --- a/src/userdb/meson.build +++ b/src/userdb/meson.build @@ -23,3 +23,20 @@ executables += [ 'dependencies' : threads, }, ] + +if conf.get('ENABLE_SSH_USERDB_CONFIG') == 1 + custom_target( + '20-systemd-userdb.conf', + input : '20-systemd-userdb.conf.in', + output : '20-systemd-userdb.conf', + command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'], + install : true, + install_dir : sshdconfdir.startswith('/usr/') ? sshdconfdir : libexecdir / 'sshd_config.d') + + if not sshdconfdir.startswith('/usr/') + install_emptydir(sshdconfdir) + + meson.add_install_script(sh, '-c', + ln_s.format(libexecdir / 'sshd_config.d' / '20-systemd-userdb.conf', sshdconfdir / '20-systemd-userdb.conf')) + endif +endif diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index 238a71d..1718419 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -169,24 +169,24 @@ static const struct { }, }; -static int table_add_uid_boundaries(Table *table, const UidRange *p) { +static int table_add_uid_boundaries(Table *table, const UIDRange *p) { int r; assert(table); - for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { + FOREACH_ELEMENT(i, uid_range_table) { _cleanup_free_ char *name = NULL, *comment = NULL; - if (!uid_range_covers(p, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1)) + if (!uid_range_covers(p, i->first, i->last - i->first + 1)) continue; name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), - " begin ", uid_range_table[i].name, " users ", + " begin ", i->name, " users ", special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); if (!name) return log_oom(); - comment = strjoin("First ", uid_range_table[i].name, " user"); + comment = strjoin("First ", i->name, " user"); if (!comment) return log_oom(); @@ -195,9 +195,9 @@ static int table_add_uid_boundaries(Table *table, const UidRange *p) { TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP), TABLE_STRING, name, TABLE_SET_COLOR, ansi_grey(), - TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_STRING, user_disposition_to_string(i->disposition), TABLE_SET_COLOR, ansi_grey(), - TABLE_UID, uid_range_table[i].first, + TABLE_UID, i->first, TABLE_SET_COLOR, ansi_grey(), TABLE_EMPTY, TABLE_STRING, comment, @@ -210,13 +210,13 @@ static int table_add_uid_boundaries(Table *table, const UidRange *p) { free(name); name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP), - " end ", uid_range_table[i].name, " users ", + " end ", i->name, " users ", special_glyph(SPECIAL_GLYPH_ARROW_UP)); if (!name) return log_oom(); free(comment); - comment = strjoin("Last ", uid_range_table[i].name, " user"); + comment = strjoin("Last ", i->name, " user"); if (!comment) return log_oom(); @@ -225,9 +225,9 @@ static int table_add_uid_boundaries(Table *table, const UidRange *p) { TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT), TABLE_STRING, name, TABLE_SET_COLOR, ansi_grey(), - TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_STRING, user_disposition_to_string(i->disposition), TABLE_SET_COLOR, ansi_grey(), - TABLE_UID, uid_range_table[i].last, + TABLE_UID, i->last, TABLE_SET_COLOR, ansi_grey(), TABLE_EMPTY, TABLE_STRING, comment, @@ -301,7 +301,7 @@ static int add_unavailable_uid(Table *table, uid_t start, uid_t end) { static int table_add_uid_map( Table *table, - const UidRange *p, + const UIDRange *p, int (*add_unavailable)(Table *t, uid_t start, uid_t end)) { uid_t focus = 0; @@ -313,9 +313,7 @@ static int table_add_uid_map( if (!p) return 0; - for (size_t i = 0; p && i < p->n_entries; i++) { - UidRangeEntry *x = p->entries + i; - + FOREACH_ARRAY(x, p->entries, p->n_entries) { if (focus < x->start) { r = add_unavailable(table, focus, x->start-1); if (r < 0) @@ -428,10 +426,10 @@ static int display_user(int argc, char *argv[], void *userdata) { } if (table) { - _cleanup_(uid_range_freep) UidRange *uid_range = NULL; + _cleanup_(uid_range_freep) UIDRange *uid_range = NULL; int boundary_lines, uid_map_lines; - r = uid_range_load_userns(&uid_range, "/proc/self/uid_map"); + r = uid_range_load_userns(/* path = */ NULL, UID_RANGE_USERNS_INSIDE, &uid_range); if (r < 0) log_debug_errno(r, "Failed to load /proc/self/uid_map, ignoring: %m"); @@ -443,7 +441,7 @@ static int display_user(int argc, char *argv[], void *userdata) { if (uid_map_lines < 0) return uid_map_lines; - if (table_get_rows(table) > 1) { + if (!table_isempty(table)) { r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) return table_log_print_error(r); @@ -529,25 +527,24 @@ static int show_group(GroupRecord *gr, Table *table) { return 0; } -static int table_add_gid_boundaries(Table *table, const UidRange *p) { +static int table_add_gid_boundaries(Table *table, const UIDRange *p) { int r; assert(table); - for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) { + FOREACH_ELEMENT(i, uid_range_table) { _cleanup_free_ char *name = NULL, *comment = NULL; - if (!uid_range_covers(p, uid_range_table[i].first, - uid_range_table[i].last - uid_range_table[i].first + 1)) + if (!uid_range_covers(p, i->first, i->last - i->first + 1)) continue; name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN), - " begin ", uid_range_table[i].name, " groups ", + " begin ", i->name, " groups ", special_glyph(SPECIAL_GLYPH_ARROW_DOWN)); if (!name) return log_oom(); - comment = strjoin("First ", uid_range_table[i].name, " group"); + comment = strjoin("First ", i->name, " group"); if (!comment) return log_oom(); @@ -556,9 +553,9 @@ static int table_add_gid_boundaries(Table *table, const UidRange *p) { TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_TOP), TABLE_STRING, name, TABLE_SET_COLOR, ansi_grey(), - TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_STRING, user_disposition_to_string(i->disposition), TABLE_SET_COLOR, ansi_grey(), - TABLE_GID, uid_range_table[i].first, + TABLE_GID, i->first, TABLE_SET_COLOR, ansi_grey(), TABLE_STRING, comment, TABLE_SET_COLOR, ansi_grey(), @@ -568,13 +565,13 @@ static int table_add_gid_boundaries(Table *table, const UidRange *p) { free(name); name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP), - " end ", uid_range_table[i].name, " groups ", + " end ", i->name, " groups ", special_glyph(SPECIAL_GLYPH_ARROW_UP)); if (!name) return log_oom(); free(comment); - comment = strjoin("Last ", uid_range_table[i].name, " group"); + comment = strjoin("Last ", i->name, " group"); if (!comment) return log_oom(); @@ -583,9 +580,9 @@ static int table_add_gid_boundaries(Table *table, const UidRange *p) { TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT), TABLE_STRING, name, TABLE_SET_COLOR, ansi_grey(), - TABLE_STRING, user_disposition_to_string(uid_range_table[i].disposition), + TABLE_STRING, user_disposition_to_string(i->disposition), TABLE_SET_COLOR, ansi_grey(), - TABLE_GID, uid_range_table[i].last, + TABLE_GID, i->last, TABLE_SET_COLOR, ansi_grey(), TABLE_STRING, comment, TABLE_SET_COLOR, ansi_grey(), @@ -732,10 +729,10 @@ static int display_group(int argc, char *argv[], void *userdata) { } if (table) { - _cleanup_(uid_range_freep) UidRange *gid_range = NULL; + _cleanup_(uid_range_freep) UIDRange *gid_range = NULL; int boundary_lines, gid_map_lines; - r = uid_range_load_userns(&gid_range, "/proc/self/gid_map"); + r = uid_range_load_userns(/* path = */ NULL, GID_RANGE_USERNS_INSIDE, &gid_range); if (r < 0) log_debug_errno(r, "Failed to load /proc/self/gid_map, ignoring: %m"); @@ -747,7 +744,7 @@ static int display_group(int argc, char *argv[], void *userdata) { if (gid_map_lines < 0) return gid_map_lines; - if (table_get_rows(table) > 1) { + if (!table_isempty(table)) { r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) return table_log_print_error(r); @@ -895,17 +892,17 @@ static int display_memberships(int argc, char *argv[], void *userdata) { } if (table) { - if (table_get_rows(table) > 1) { + if (!table_isempty(table)) { r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) return table_log_print_error(r); } if (arg_legend) { - if (table_get_rows(table) > 1) - printf("\n%zu memberships listed.\n", table_get_rows(table) - 1); - else + if (table_isempty(table)) printf("No memberships.\n"); + else + printf("\n%zu memberships listed.\n", table_get_rows(table) - 1); } } @@ -960,17 +957,17 @@ static int display_services(int argc, char *argv[], void *userdata) { return table_log_add_error(r); } - if (table_get_rows(t) > 1) { + if (!table_isempty(t)) { r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) return table_log_print_error(r); } if (arg_legend && arg_output != OUTPUT_JSON) { - if (table_get_rows(t) > 1) - printf("\n%zu services listed.\n", table_get_rows(t) - 1); - else + if (table_isempty(t)) printf("No services.\n"); + else + printf("\n%zu services listed.\n", table_get_rows(t) - 1); } return 0; diff --git a/src/userdb/userdbd-manager.c b/src/userdb/userdbd-manager.c index 359c827..5925602 100644 --- a/src/userdb/userdbd-manager.c +++ b/src/userdb/userdbd-manager.c @@ -4,6 +4,7 @@ #include "sd-daemon.h" +#include "build-path.h" #include "common-signal.h" #include "env-util.h" #include "fd-util.h" @@ -14,6 +15,7 @@ #include "signal-util.h" #include "socket-util.h" #include "stdio-util.h" +#include "strv.h" #include "umask-util.h" #include "userdbd-manager.h" @@ -185,17 +187,19 @@ static int start_one_worker(Manager *m) { _exit(EXIT_FAILURE); } - if (setenv("USERDB_FIXED_WORKER", one_zero(fixed), 1) < 0) { log_error_errno(errno, "Failed to set $USERDB_FIXED_WORKER: %m"); _exit(EXIT_FAILURE); } - /* execl("/home/lennart/projects/systemd/build/systemd-userwork", "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /\* With some extra space rename_process() can make use of *\/ */ - /* execl("/usr/bin/valgrind", "valgrind", "/home/lennart/projects/systemd/build/systemd-userwork", "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /\* With some extra space rename_process() can make use of *\/ */ + r = setenv_systemd_log_level(); + if (r < 0) { + log_error_errno(r, "Failed to set $SYSTEMD_LOG_LEVEL: %m"); + _exit(EXIT_FAILURE); + } - execl(SYSTEMD_USERWORK_PATH, "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /* With some extra space rename_process() can make use of */ - log_error_errno(errno, "Failed start worker process: %m"); + r = invoke_callout_binary(SYSTEMD_USERWORK_PATH, STRV_MAKE(SYSTEMD_USERWORK_PATH, "xxxxxxxxxxxxxxxx")); /* With some extra space rename_process() can make use of */ + log_error_errno(r, "Failed start worker process: %m"); _exit(EXIT_FAILURE); } @@ -265,57 +269,85 @@ static int start_workers(Manager *m, bool explicit_request) { return 0; } -int manager_startup(Manager *m) { - int n, r; +static int manager_make_listen_socket(Manager *m) { + static const union sockaddr_union sockaddr = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/userdb/io.systemd.Multiplexer", + }; + int r; assert(m); - assert(m->listen_fd < 0); - n = sd_listen_fds(false); + if (m->listen_fd >= 0) + return 0; + + r = mkdir_p("/run/systemd/userdb", 0755); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/userdb: %m"); + + m->listen_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (m->listen_fd < 0) + return log_error_errno(errno, "Failed to bind on socket: %m"); + + (void) sockaddr_un_unlink(&sockaddr.un); + + WITH_UMASK(0000) + if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) + return log_error_errno(errno, "Failed to bind socket: %m"); + + FOREACH_STRING(alias, + "/run/systemd/userdb/io.systemd.NameServiceSwitch", + "/run/systemd/userdb/io.systemd.DropIn") { + + r = symlink_idempotent("io.systemd.Multiplexer", alias, /* make_relative= */ false); + if (r < 0) + return log_error_errno(r, "Failed to symlink '%s': %m", alias); + } + + if (listen(m->listen_fd, SOMAXCONN_DELUXE) < 0) + return log_error_errno(errno, "Failed to listen on socket: %m"); + + return 1; +} + +static int manager_scan_listen_fds(Manager *m) { + int n; + + assert(m); + + n = sd_listen_fds(/* unset_environment= */ true); if (n < 0) return log_error_errno(n, "Failed to determine number of passed file descriptors: %m"); if (n > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected one listening fd, got %i.", n); if (n == 1) m->listen_fd = SD_LISTEN_FDS_START; - else { - static const union sockaddr_union sockaddr = { - .un.sun_family = AF_UNIX, - .un.sun_path = "/run/systemd/userdb/io.systemd.Multiplexer", - }; - - r = mkdir_p("/run/systemd/userdb", 0755); - if (r < 0) - return log_error_errno(r, "Failed to create /run/systemd/userdb: %m"); - - m->listen_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (m->listen_fd < 0) - return log_error_errno(errno, "Failed to bind on socket: %m"); - (void) sockaddr_un_unlink(&sockaddr.un); + return 0; +} - WITH_UMASK(0000) - if (bind(m->listen_fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) - return log_error_errno(errno, "Failed to bind socket: %m"); +int manager_startup(Manager *m) { + int r; - r = symlink_idempotent("io.systemd.Multiplexer", - "/run/systemd/userdb/io.systemd.NameServiceSwitch", false); - if (r < 0) - return log_error_errno(r, "Failed to bind io.systemd.Multiplexer: %m"); + assert(m); + assert(m->listen_fd < 0); - r = symlink_idempotent("io.systemd.Multiplexer", - "/run/systemd/userdb/io.systemd.DropIn", false); - if (r < 0) - return log_error_errno(r, "Failed to bind io.systemd.Multiplexer: %m"); + r = manager_scan_listen_fds(m); + if (r < 0) + return r; - if (listen(m->listen_fd, SOMAXCONN_DELUXE) < 0) - return log_error_errno(errno, "Failed to listen on socket: %m"); - } + r = manager_make_listen_socket(m); + if (r < 0) + return r; /* Let's make sure every accept() call on this socket times out after 25s. This allows workers to be * GC'ed on idle */ if (setsockopt(m->listen_fd, SOL_SOCKET, SO_RCVTIMEO, TIMEVAL_STORE(LISTEN_TIMEOUT_USEC), sizeof(struct timeval)) < 0) return log_error_errno(errno, "Failed to se SO_RCVTIMEO: %m"); - return start_workers(m, /* explicit_request= */ false); + r = start_workers(m, /* explicit_request= */ false); + if (r < 0) + return r; + + return 0; } diff --git a/src/userdb/userdbd.c b/src/userdb/userdbd.c index 89ac9c7..cbe4c8e 100644 --- a/src/userdb/userdbd.c +++ b/src/userdb/userdbd.c @@ -37,7 +37,7 @@ static int run(int argc, char *argv[]) { if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.NameServiceSwitch:io.systemd.Multiplexer:io.systemd.DropIn", 1) < 0) return log_error_errno(errno, "Failed to set $SYSTEMD_BYPASS_USERDB: %m"); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0); r = manager_new(&m); if (r < 0) diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index b49dbbd..729a9a1 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -353,9 +353,9 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { static const JsonDispatch dispatch_table[] = { - { "userName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, user_name), 0 }, + { "userName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, user_name), 0 }, { "groupName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, group_name), 0 }, - { "service", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, + { "service", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, {} }; @@ -425,16 +425,16 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); } -static int process_connection(VarlinkServer *server, int fd) { +static int process_connection(VarlinkServer *server, int _fd) { + _cleanup_close_ int fd = TAKE_FD(_fd); /* always take possession */ _cleanup_(varlink_close_unrefp) Varlink *vl = NULL; int r; r = varlink_server_add_connection(server, fd, &vl); - if (r < 0) { - fd = safe_close(fd); + if (r < 0) return log_error_errno(r, "Failed to add connection: %m"); - } + TAKE_FD(fd); vl = varlink_ref(vl); for (;;) { @@ -461,6 +461,7 @@ static int process_connection(VarlinkServer *server, int fd) { static int run(int argc, char *argv[]) { usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY; _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL; + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; unsigned n_iterations = 0; int m, listen_fd, r; @@ -505,6 +506,12 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m"); + r = pidref_set_parent(&parent); + if (r < 0) + return log_error_errno(r, "Failed to acquire pidfd of parent process: %m"); + if (parent.pid == 1) /* We got reparented away from userdbd? */ + return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Parent already died, exiting."); + start_time = now(CLOCK_MONOTONIC); for (;;) { @@ -554,14 +561,11 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to test for POLLIN on listening socket: %m"); if (FLAGS_SET(r, POLLIN)) { - pid_t parent; - - parent = getppid(); - if (parent <= 1) - return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Parent already died?"); - - if (kill(parent, SIGUSR2) < 0) - return log_error_errno(errno, "Failed to kill our own parent: %m"); + r = pidref_kill(&parent, SIGUSR2); + if (r == -ESRCH) + return log_error_errno(r, "Parent already died?"); + if (r < 0) + return log_error_errno(r, "Failed to send SIGUSR2 signal to parent: %m"); } } -- cgit v1.2.3