7e7c9f
From fb419649754767124f30dba36f8fdbd114b0e9d7 Mon Sep 17 00:00:00 2001
7e7c9f
From: Lennart Poettering <lennart@poettering.net>
7e7c9f
Date: Wed, 22 Jan 2020 12:04:38 +0100
7e7c9f
Subject: [PATCH] logind: check PolicyKit before allowing VT switch
7e7c9f
7e7c9f
Let's lock this down a bit. Effectively nothing much changes, since the
7e7c9f
default PK policy will allow users on the VT to change VT. Only users
7e7c9f
with no local VT session won't be able to switch VTs.
7e7c9f
7e7c9f
(cherry picked from commit 4acf0cfd2f92edb94ad48d04f1ce6c9ab4e19d55)
7e7c9f
7e7c9f
Resolves: #1797672
7e7c9f
---
7e7c9f
 src/login/logind-dbus.c                    | 18 ++++++--
7e7c9f
 src/login/logind-seat-dbus.c               | 50 +++++++++++++++++++++-
7e7c9f
 src/login/logind-session-dbus.c            | 16 ++++++-
7e7c9f
 src/login/logind-session.h                 |  2 +
7e7c9f
 src/login/org.freedesktop.login1.policy.in | 10 +++++
7e7c9f
 5 files changed, 89 insertions(+), 7 deletions(-)
7e7c9f
7e7c9f
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
7e7c9f
index 63b9a0df36..019aa193f5 100644
7e7c9f
--- a/src/login/logind-dbus.c
7e7c9f
+++ b/src/login/logind-dbus.c
7e7c9f
@@ -854,11 +854,9 @@ static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *u
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
 
7e7c9f
-        r = session_activate(session);
7e7c9f
-        if (r < 0)
7e7c9f
-                return r;
7e7c9f
+        /* PolicyKit is done by bus_session_method_activate() */
7e7c9f
 
7e7c9f
-        return sd_bus_reply_method_return(message, NULL);
7e7c9f
+        return bus_session_method_activate(bus, message, session, error);
7e7c9f
 }
7e7c9f
 
7e7c9f
 static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
7e7c9f
@@ -890,6 +888,18 @@ static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message,
7e7c9f
         if (session->seat != seat)
7e7c9f
                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
7e7c9f
 
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &m->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
+
7e7c9f
         r = session_activate(session);
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
7e7c9f
index 50b0b8842f..f49e416fce 100644
7e7c9f
--- a/src/login/logind-seat-dbus.c
7e7c9f
+++ b/src/login/logind-seat-dbus.c
7e7c9f
@@ -229,6 +229,18 @@ static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *u
7e7c9f
         if (session->seat != s)
7e7c9f
                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
7e7c9f
 
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &s->manager->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
+
7e7c9f
         r = session_activate(session);
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
@@ -250,7 +262,19 @@ static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata
7e7c9f
                 return r;
7e7c9f
 
7e7c9f
         if (to <= 0)
7e7c9f
-                return -EINVAL;
7e7c9f
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal");
7e7c9f
+
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &s->manager->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
 
7e7c9f
         r = seat_switch_to(s, to);
7e7c9f
         if (r < 0)
7e7c9f
@@ -267,6 +291,18 @@ static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *use
7e7c9f
         assert(message);
7e7c9f
         assert(s);
7e7c9f
 
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &s->manager->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
+
7e7c9f
         r = seat_switch_to_next(s);
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
@@ -282,6 +318,18 @@ static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void
7e7c9f
         assert(message);
7e7c9f
         assert(s);
7e7c9f
 
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &s->manager->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
+
7e7c9f
         r = seat_switch_to_previous(s);
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
7e7c9f
index 75b7186e8f..0ec4196257 100644
7e7c9f
--- a/src/login/logind-session-dbus.c
7e7c9f
+++ b/src/login/logind-session-dbus.c
7e7c9f
@@ -213,7 +213,7 @@ static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata
7e7c9f
         return sd_bus_reply_method_return(message, NULL);
7e7c9f
 }
7e7c9f
 
7e7c9f
-static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
7e7c9f
+int bus_session_method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
7e7c9f
         Session *s = userdata;
7e7c9f
         int r;
7e7c9f
 
7e7c9f
@@ -221,6 +221,18 @@ static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata,
7e7c9f
         assert(message);
7e7c9f
         assert(s);
7e7c9f
 
7e7c9f
+        r = bus_verify_polkit_async(
7e7c9f
+                        message,
7e7c9f
+                        CAP_SYS_ADMIN,
7e7c9f
+                        "org.freedesktop.login1.chvt",
7e7c9f
+                        false,
7e7c9f
+                        &s->manager->polkit_registry,
7e7c9f
+                        error);
7e7c9f
+        if (r < 0)
7e7c9f
+                return r;
7e7c9f
+        if (r == 0)
7e7c9f
+                return 1; /* Will call us back */
7e7c9f
+
7e7c9f
         r = session_activate(s);
7e7c9f
         if (r < 0)
7e7c9f
                 return r;
7e7c9f
@@ -506,7 +518,7 @@ const sd_bus_vtable session_vtable[] = {
7e7c9f
         SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
7e7c9f
 
7e7c9f
         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
7e7c9f
-        SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
7e7c9f
+        SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
7e7c9f
         SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
7e7c9f
         SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
7e7c9f
         SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
7e7c9f
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
7e7c9f
index d662082d85..b498f49592 100644
7e7c9f
--- a/src/login/logind-session.h
7e7c9f
+++ b/src/login/logind-session.h
7e7c9f
@@ -184,3 +184,5 @@ void session_leave_vt(Session *s);
7e7c9f
 bool session_is_controller(Session *s, const char *sender);
7e7c9f
 int session_set_controller(Session *s, const char *sender, bool force);
7e7c9f
 void session_drop_controller(Session *s);
7e7c9f
+
7e7c9f
+int bus_session_method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
7e7c9f
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
7e7c9f
index 49094eeddb..fa51ed8d74 100644
7e7c9f
--- a/src/login/org.freedesktop.login1.policy.in
7e7c9f
+++ b/src/login/org.freedesktop.login1.policy.in
7e7c9f
@@ -270,4 +270,14 @@
7e7c9f
                 <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.hibernate</annotate>
7e7c9f
         </action>
7e7c9f
 
7e7c9f
+        <action id="org.freedesktop.login1.chvt">
7e7c9f
+                <description gettext-domain="systemd">Change Session</description>
7e7c9f
+                <message gettext-domain="systemd">Authentication is required for changing the virtual terminal.</message>
7e7c9f
+                <defaults>
7e7c9f
+                        <allow_any>auth_admin_keep</allow_any>
7e7c9f
+                        <allow_inactive>auth_admin_keep</allow_inactive>
7e7c9f
+                        <allow_active>yes</allow_active>
7e7c9f
+                </defaults>
7e7c9f
+        </action>
7e7c9f
+
7e7c9f
 </policyconfig>