summaryrefslogtreecommitdiffstats
path: root/src/userdb
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/userdb
parentAdding upstream version 255.5. (diff)
downloadsystemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz
systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/userdb')
-rw-r--r--src/userdb/20-systemd-userdb.conf.in6
-rw-r--r--src/userdb/meson.build17
-rw-r--r--src/userdb/userdbctl.c79
-rw-r--r--src/userdb/userdbd-manager.c108
-rw-r--r--src/userdb/userdbd.c2
-rw-r--r--src/userdb/userwork.c32
6 files changed, 150 insertions, 94 deletions
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");
}
}