diff --git a/man/loginctl.xml b/man/loginctl.xml index 534a0d961e..617852dfa7 100644 --- a/man/loginctl.xml +++ b/man/loginctl.xml @@ -280,11 +280,10 @@ one or more logged in users, followed by the most recent log data from the journal. Takes one or more user names or numeric user IDs as parameters. If no parameters are passed, the status - of the caller's user is shown. This function is intended to - generate human-readable output. If you are looking for - computer-parsable output, use show-user - instead. Users may be specified by their usernames or numeric - user IDs. + is shown for the user of the session of the caller. This + function is intended to generate human-readable output. If you + are looking for computer-parsable output, use + show-user instead. diff --git a/man/rules/meson.build b/man/rules/meson.build index ae0556058e..f74dbf9c77 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -441,7 +441,7 @@ manpages = [ '3', ['sd_notifyf', 'sd_pid_notify', 'sd_pid_notify_with_fds', 'sd_pid_notifyf'], ''], - ['sd_pid_get_session', + ['sd_pid_get_owner_uid', '3', ['sd_peer_get_cgroup', 'sd_peer_get_machine_name', @@ -453,7 +453,7 @@ manpages = [ 'sd_peer_get_user_unit', 'sd_pid_get_cgroup', 'sd_pid_get_machine_name', - 'sd_pid_get_owner_uid', + 'sd_pid_get_session', 'sd_pid_get_slice', 'sd_pid_get_unit', 'sd_pid_get_user_slice', diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml index 9e68d5e8c7..56e62863f2 100644 --- a/man/sd_bus_creds_get_pid.xml +++ b/man/sd_bus_creds_get_pid.xml @@ -394,16 +394,19 @@ sd_bus_creds_get_session() will retrieve the identifier of the login session that the process is - a part of. See - systemd-logind.service8. For - processes that are not part of a session, returns -ENXIO. - + a part of. Please note the login session may be limited to a stub + process or two. User processes may instead be started from their + systemd user manager, e.g. GUI applications started using DBus + activation, as well as service processes which are shared between + multiple logins of the same user. For processes that are not part + of a session, returns -ENXIO. sd_bus_creds_get_owner_uid() will retrieve the numeric UID (user identifier) of the user who owns - the login session that the process is a part of. See + the user unit or login session that the process is a part of. See systemd-logind.service8. - For processes that are not part of a session, returns -ENXIO. + For processes that are not part of a user unit or session, returns + -ENXIO. sd_bus_creds_has_effective_cap() will check whether the capability specified by @@ -500,15 +503,16 @@ The given field is not specified for the described process or peer. This will be returned by - sd_bus_get_unit(), - sd_bus_get_slice(), - sd_bus_get_user_unit(), - sd_bus_get_user_slice(), - sd_bus_get_session(), and - sd_bus_get_owner_uid() if the process is + sd_bus_creds_get_unit(), + sd_bus_creds_get_slice(), + sd_bus_creds_get_user_unit(), + sd_bus_creds_get_user_slice(), and + sd_bus_creds_get_session() if the process is not part of a systemd system unit, systemd user unit, systemd - slice, or logind session. It will also be returned by - sd_bus_creds_get_exe() and + slice, or logind session. It will be returned by + sd_bus_creds_get_owner_uid() if the process is + not part of a systemd user unit or logind session. It will also be + returned by sd_bus_creds_get_exe() and sd_bus_creds_get_cmdline() for kernel threads (since these are not started from an executable binary, nor have a command line), and by diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_owner_uid.xml similarity index 85% rename from man/sd_pid_get_session.xml rename to man/sd_pid_get_owner_uid.xml index 14ebd53e36..5a2a07d096 100644 --- a/man/sd_pid_get_session.xml +++ b/man/sd_pid_get_owner_uid.xml @@ -21,10 +21,10 @@ along with systemd; If not, see . --> - + - sd_pid_get_session + sd_pid_get_owner_uid systemd @@ -38,30 +38,30 @@ - sd_pid_get_session + sd_pid_get_owner_uid 3 - sd_pid_get_session - sd_pid_get_unit - sd_pid_get_user_unit sd_pid_get_owner_uid + sd_pid_get_session + sd_pid_get_user_unit + sd_pid_get_unit sd_pid_get_machine_name sd_pid_get_slice sd_pid_get_user_slice sd_pid_get_cgroup - sd_peer_get_session - sd_peer_get_unit - sd_peer_get_user_unit sd_peer_get_owner_uid + sd_peer_get_session + sd_peer_get_user_unit + sd_peer_get_unit sd_peer_get_machine_name sd_peer_get_slice sd_peer_get_user_slice sd_peer_get_cgroup - Determine session, unit, owner of a session, - container/VM or slice of a specific PID or socket - peer + Determine the owner uid of the user unit or session, + or the session, user unit, system unit, container/VM or slice that + a specific PID or socket peer belongs to. @@ -69,15 +69,15 @@ #include <systemd/sd-login.h> - int sd_pid_get_session + int sd_pid_get_owner_uid pid_t pid - char **session + uid_t *uid - int sd_pid_get_unit + int sd_pid_get_session pid_t pid - char **unit + char **session @@ -87,9 +87,9 @@ - int sd_pid_get_owner_uid + int sd_pid_get_unit pid_t pid - uid_t *uid + char **unit @@ -117,15 +117,15 @@ - int sd_peer_get_session + int sd_peer_get_owner_uid int fd - char **session + uid_t *uid - int sd_peer_get_unit + int sd_peer_get_session int fd - char **unit + char **session @@ -135,9 +135,9 @@ - int sd_peer_get_owner_uid + int sd_peer_get_unit int fd - uid_t *uid + char **unit @@ -169,16 +169,34 @@ Description + sd_pid_get_owner_uid() may be used to + determine the Unix UID (user identifier) which owns the login + session or systemd user unit of a process identified by the + specified PID. For processes which are not part of a login session + and not managed by a user manager, this function will fail with + -ENODATA. + sd_pid_get_session() may be used to determine the login session identifier of a process identified by the specified process identifier. The session identifier is a - short string, suitable for usage in file system paths. Note that - not all processes are part of a login session (e.g. system service - processes, user processes that are shared between multiple - sessions of the same user, or kernel threads). For processes not - being part of a login session, this function will fail with - -ENODATA. The returned string needs to be freed with the libc - -ENODATA. + The returned string needs to be freed with the libc free3 + call after use. + + sd_pid_get_user_unit() may be used to + determine the systemd user unit (i.e. user service or scope unit) + identifier of a process identified by the specified PID. The + unit name is a short string, suitable for usage in file system + paths. For processes which are not managed by a user manager, this + function will fail with -ENODATA. The + returned string needs to be freed with the libc free3 call after use. @@ -186,37 +204,21 @@ determine the systemd system unit (i.e. system service or scope unit) identifier of a process identified by the specified PID. The unit name is a short string, suitable for usage in file system - paths. Note that not all processes are part of a system - unit/service (e.g. user processes, or kernel threads). For - processes not being part of a systemd system unit, this function - will fail with -ENODATA. (More specifically, this call will not - work for kernel threads.) The returned string needs to be freed - with the libc -ENODATA. + (More specifically, this call will not work for kernel threads.) + The returned string needs to be freed with the libc free3 call after use. - sd_pid_get_user_unit() may be used to - determine the systemd user unit (i.e. user service or scope unit) - identifier of a process identified by the specified PID. This is - similar to sd_pid_get_unit(), but applies to - user units instead of system units. - - sd_pid_get_owner_uid() may be used to - determine the Unix UID (user identifier) of the owner of the - session of a process identified the specified PID. Note that this - function will succeed for user processes which are shared between - multiple login sessions of the same user, whereas - sd_pid_get_session() will fail. For processes - not being part of a login session and not being a shared process - of a user, this function will fail with -ENODATA. - sd_pid_get_machine_name() may be used to determine the name of the VM or container is a member of. The machine name is a short string, suitable for usage in file system paths. The returned string needs to be freed with the libc free3 - call after use. For processes not part of a VM or containers, this + call after use. For processes not part of a VM or container, this function fails with -ENODATA. sd_pid_get_slice() may be used to @@ -246,10 +248,10 @@ functions is passed as 0, the operation is executed for the calling process. - The sd_peer_get_session(), - sd_peer_get_unit(), + The sd_peer_get_owner_uid(), + sd_peer_get_session(), sd_peer_get_user_unit(), - sd_peer_get_owner_uid(), + sd_peer_get_unit(), sd_peer_get_machine_name(), sd_peer_get_slice(), sd_peer_get_user_slice() and diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml index e488affe3e..cab356c5e7 100644 --- a/man/systemd.journal-fields.xml +++ b/man/systemd.journal-fields.xml @@ -193,18 +193,19 @@ _SYSTEMD_CGROUP= - _SYSTEMD_SESSION= + _SYSTEMD_SLICE= _SYSTEMD_UNIT= _SYSTEMD_USER_UNIT= + _SYSTEMD_SESSION= _SYSTEMD_OWNER_UID= - _SYSTEMD_SLICE= The control group path in the systemd hierarchy, the - systemd session ID (if any), the systemd unit name (if any), - the systemd user session unit name (if any), the owner UID - of the systemd session (if any) and the systemd slice unit - of the process the journal entry originates from. + the systemd slice unit name, the systemd unit name, the + unit name in the systemd user manager (if any), the systemd + session ID (if any), and the owner UID of the systemd user + unit or systemd session (if any) of the process the journal + entry originates from. diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 49624ba7d0..f2ed0ab02c 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1151,11 +1151,11 @@ static int enable_linger(int argc, char *argv[], void *userdata) { b = streq(argv[0], "enable-linger"); if (argc < 2) { - /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty - * session name, in which case logind will try to guess our session. */ + /* No argument? Let's use an empty user name, + * then logind will use our user. */ short_argv[0] = argv[0]; - short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) ""; + short_argv[1] = (char*) ""; short_argv[2] = NULL; argv = short_argv; argc = 2; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index f62a02c4d1..016274fb7a 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -50,27 +50,47 @@ #include "user-util.h" #include "utmp-wtmp.h" -int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { +static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + const char *name; Session *session; int r; + /* Get client login session. This is not what you are looking for these days, + * as apps may instead belong to a user service unit. This includes terminal + * emulators and hence command-line apps. */ + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_session(creds, &name); + if (r == -ENXIO) + goto err_no_session; + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + goto err_no_session; + + *ret = session; + return 0; + +err_no_session: + return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, + "Caller does not belong to any known session"); +} + +int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { + Session *session; + assert(m); assert(message); assert(ret); - if (isempty(name)) { - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); - if (r < 0) - return r; - - r = sd_bus_creds_get_session(creds, &name); - if (r == -ENXIO) - return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, - "Caller does not belong to any known session"); - if (r < 0) - return r; - } + if (isempty(name)) + return get_sender_session(m, message, error, ret); session = hashmap_get(m->sessions, name); if (!session) @@ -80,30 +100,48 @@ int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const ch return 0; } -int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) { +static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) { + + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + uid_t uid; User *user; int r; + /* Note that we get the owner UID of the session, not the actual client UID here! */ + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_owner_uid(creds, &uid); + if (r == -ENXIO) + goto err_no_user; + if (r < 0) + return r; + + user = hashmap_get(m->users, UID_TO_PTR(uid)); + if (!user) + goto err_no_user; + + *ret = user; + return 0; + +err_no_user: + return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "Caller does not belong to any logged in user or lingering user"); +} + +int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) { + User *user; + assert(m); assert(message); assert(ret); - if (!uid_is_valid(uid)) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - - /* Note that we get the owner UID of the session, not the actual client UID here! */ - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); - if (r < 0) - return r; - - r = sd_bus_creds_get_owner_uid(creds, &uid); - if (r < 0) - return r; - } + if (!uid_is_valid(uid)) + return get_sender_user(m, message, error, ret); user = hashmap_get(m->users, UID_TO_PTR(uid)); if (!user) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "User ID "UID_FMT" is not logged in or lingering", uid); *ret = user; return 0; @@ -329,6 +367,9 @@ static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_er return sd_bus_reply_method_return(message, "o", p); } +/* Get login session of a process. This is not what you are looking for these days, + * as apps may instead belong to a user service unit. This includes terminal + * emulators and hence command-line apps. */ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *p = NULL; Session *session = NULL; @@ -419,7 +460,9 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; if (!user) - return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "PID "PID_FMT" does not belong to any known or logged in user", pid); + return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, + "PID "PID_FMT" does not belong to any logged in user or lingering user", + pid); } p = user_bus_path(user); @@ -1117,13 +1160,13 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus } static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; _cleanup_free_ char *cc = NULL; Manager *m = userdata; int r, b, interactive; struct passwd *pw; const char *path; - uint32_t uid; - bool self = false; + uint32_t uid, auth_uid; assert(message); assert(m); @@ -1132,22 +1175,23 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID | + SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); + if (r < 0) + return r; + if (!uid_is_valid(uid)) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - - /* Note that we get the owner UID of the session, not the actual client UID here! */ - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); - if (r < 0) - return r; - + /* Note that we get the owner UID of the session or user unit, + * not the actual client UID here! */ r = sd_bus_creds_get_owner_uid(creds, &uid); if (r < 0) return r; + } - self = true; - - } else if (!uid_is_valid(uid)) - return -EINVAL; + /* owner_uid is racy, so for authorization we must use euid */ + r = sd_bus_creds_get_euid(creds, &auth_uid); + if (r < 0) + return r; errno = 0; pw = getpwuid(uid); @@ -1157,7 +1201,8 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, - self ? "org.freedesktop.login1.set-self-linger" : "org.freedesktop.login1.set-user-linger", + uid == auth_uid ? "org.freedesktop.login1.set-self-linger" : + "org.freedesktop.login1.set-user-linger", NULL, interactive, UID_INVALID, diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index c1a319b87d..f97e237019 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -357,6 +357,8 @@ static int pid_is_active(Manager *m, pid_t pid) { Session *s; int r; + /* Get client session. This is not what you are looking for these days. + * FIXME #6852 */ r = manager_get_session_by_pid(m, pid, &s); if (r < 0) return r; diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index f934a5326a..2154b878dd 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -332,28 +332,15 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void assert(m); if (streq(path, "/org/freedesktop/login1/seat/self")) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; - Session *session; - const char *name; message = sd_bus_get_current_message(bus); if (!message) return 0; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + r = manager_get_seat_from_creds(m, message, NULL, error, &seat); if (r < 0) return r; - - r = sd_bus_creds_get_session(creds, &name); - if (r < 0) - return r; - - session = hashmap_get(m->sessions, name); - if (!session) - return 0; - - seat = session->seat; } else { _cleanup_free_ char *e = NULL; const char *p; @@ -367,11 +354,10 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void return -ENOMEM; seat = hashmap_get(m->seats, e); + if (!seat) + return 0; } - if (!seat) - return 0; - *found = seat; return 1; } diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 649f3c155e..09ecb49d33 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -580,23 +580,15 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo assert(m); if (streq(path, "/org/freedesktop/login1/session/self")) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; - const char *name; message = sd_bus_get_current_message(bus); if (!message) return 0; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); + r = manager_get_session_from_creds(m, message, NULL, error, &session); if (r < 0) return r; - - r = sd_bus_creds_get_session(creds, &name); - if (r < 0) - return r; - - session = hashmap_get(m->sessions, name); } else { _cleanup_free_ char *e = NULL; const char *p; @@ -610,11 +602,10 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo return -ENOMEM; session = hashmap_get(m->sessions, e); + if (!session) + return 0; } - if (!session) - return 0; - *found = session; return 1; } diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 987c63014f..921f1e0f91 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -270,18 +270,15 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void assert(m); if (streq(path, "/org/freedesktop/login1/user/self")) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; message = sd_bus_get_current_message(bus); if (!message) return 0; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); + r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user); if (r < 0) return r; - - r = sd_bus_creds_get_owner_uid(creds, &uid); } else { const char *p; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index cbe98a3ff8..de72c37452 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1120,6 +1120,8 @@ static int parse_argv(int argc, char *argv[]) { arg_userns_chown = true; if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL) >= 0) { + /* Save the user from accidentally registering either user-$SESSION.scope or user@.service. + * The latter is not technically a user session, but we don't need to labour the point. */ log_error("--keep-unit --register=yes may not be used when invoked from a user session."); return -EINVAL; }