summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlan Jenkins <alan.christopher.jenkins@gmail.com>2017-09-15 17:35:02 +0100
committerSven Eden <yamakuzure@gmx.net>2017-09-15 17:35:02 +0100
commita7b9ac880b452f0acebd42f63aa9d3a70b3692df (patch)
tree964ec681c1641637141b9c43057d5b6d2d1b8eb0 /src
parent8f22b5738389cad3a9f3f054205ad0fedbda5b09 (diff)
logind: fix SetLinger to authorize by client's effective User ID
SetLinger is authorized by the PolicyKit action "set-self-linger", if it is not passed an explicit UID. According to comments we were determining the default UID from the client's session. However, user processes e.g. which are run from a terminal emulator do not necessarily belong to a session scope unit. They may equally be started from the elogind user manager [1][2]. Actually the comment was wrong, and it would also have worked for processes started from the elogind user manager. Nevertheless it seems to involve fetching "augmented credentials" i.e. it's using a racy method, so we shouldn't have been authenticating based on it. We could change the default UID, but that raises issues especially for consistency between the methods. Instead we can just use the clients effective UID for authorization. This commit also fixes `loginctl enable-linger $USER` to match the docs that say it was equivalent to `loginctl enable-linger` (given that $USER matches the callers user and owner_uid). Previously, the former would not have suceeded for unpriviliged users in the default configuration. [1] It seems the main meaning of per-session scopes is tracking the PAM login process. Killing that provokes logind to revoke device access. Less circularly, killing it provokes getty to hangup the TTY. [2] User units may be started with an environment which includes XDG_SESSION_ID (presuambly GNOME does this?). Or not.
Diffstat (limited to 'src')
-rw-r--r--src/login/logind-dbus.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 6e42b2b07..2badab1d3 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1131,13 +1131,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);
@@ -1146,22 +1146,23 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
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;
+ 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)) {
+ /* 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);
@@ -1171,7 +1172,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,