From 89f134406af6a4b4c7493f624a89dcd654b48e81 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 11 Feb 2012 00:13:10 +0100 Subject: [PATCH] logind: introduce CanReboot/CanPowerOff bus calls --- src/hostname/hostnamed.c | 6 +- src/locale/localed.c | 6 +- src/login/logind-dbus.c | 113 ++++++++++++++++++++------ src/login/org.freedesktop.login1.conf | 8 ++ src/polkit.c | 19 ++++- src/polkit.h | 1 + src/timedate/timedated.c | 8 +- 7 files changed, 125 insertions(+), 36 deletions(-) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 1340c29dd..ad7244084 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -332,7 +332,7 @@ static DBusHandlerResult hostname_message_handler( if (!streq_ptr(name, data[PROP_HOSTNAME])) { char *h; - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -376,7 +376,7 @@ static DBusHandlerResult hostname_message_handler( if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) { - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -441,7 +441,7 @@ static DBusHandlerResult hostname_message_handler( r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : - "org.freedesktop.hostname1.set-machine-info", interactive, &error); + "org.freedesktop.hostname1.set-machine-info", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); diff --git a/src/locale/localed.c b/src/locale/localed.c index d46d91e03..e9f9f8687 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1100,7 +1100,7 @@ static DBusHandlerResult locale_message_handler( if (modified) { - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, NULL, &error); if (r < 0) { strv_free(l); return bus_send_error_reply(connection, message, &error, r); @@ -1181,7 +1181,7 @@ static DBusHandlerResult locale_message_handler( if (!streq_ptr(keymap, state.vc_keymap) || !streq_ptr(keymap_toggle, state.vc_keymap_toggle)) { - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1251,7 +1251,7 @@ static DBusHandlerResult locale_message_handler( !streq_ptr(variant, state.x11_variant) || !streq_ptr(options, state.x11_options)) { - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a50db630a..7794ab917 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -129,6 +129,12 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -714,6 +720,37 @@ static int flush_devices(Manager *m) { return trigger_device(m, NULL); } +static int have_multiple_sessions( + DBusConnection *connection, + Manager *m, + DBusMessage *message, + DBusError *error) { + + Session *s; + + assert(m); + + if (hashmap_size(m->sessions) > 1) + return true; + + /* Hmm, there's only one session, but let's make sure it + * actually belongs to the user who is asking. If not, better + * be safe than sorry. */ + + s = hashmap_first(m->sessions); + if (s) { + unsigned long ul; + + ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); + if (ul == (unsigned long) -1) + return -EIO; + + return s->user->uid != ul; + } + + return false; +} + static const BusProperty bus_login_manager_properties[] = { { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true }, { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true }, @@ -1261,7 +1298,7 @@ static DBusHandlerResult manager_message_handler( if (!pw) return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL); - r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1321,7 +1358,7 @@ static DBusHandlerResult manager_message_handler( if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat)) return bus_send_error_reply(connection, message, NULL, -EINVAL); - r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1344,7 +1381,7 @@ static DBusHandlerResult manager_message_handler( DBUS_TYPE_INVALID)) return bus_send_error_reply(connection, message, &error, -EINVAL); - r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1372,27 +1409,11 @@ static DBusHandlerResult manager_message_handler( DBUS_TYPE_INVALID)) return bus_send_error_reply(connection, message, &error, -EINVAL); - multiple_sessions = hashmap_size(m->sessions) > 1; - - if (!multiple_sessions) { - Session *s; - - /* Hmm, there's only one session, but let's - * make sure it actually belongs to the user - * who is asking. If not, better be safe than - * sorry. */ - - s = hashmap_first(m->sessions); - if (s) { - unsigned long ul; - - ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error); - if (ul == (unsigned long) -1) - return bus_send_error_reply(connection, message, &error, -EIO); + r = have_multiple_sessions(connection, m, message, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); - multiple_sessions = s->user->uid != ul; - } - } + multiple_sessions = r > 0; if (streq(dbus_message_get_member(message), "PowerOff")) { if (multiple_sessions) @@ -1410,7 +1431,7 @@ static DBusHandlerResult manager_message_handler( name = SPECIAL_REBOOT_TARGET; } - r = verify_polkit(connection, message, action, interactive, &error); + r = verify_polkit(connection, message, action, interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -1442,6 +1463,50 @@ static DBusHandlerResult manager_message_handler( if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") || + dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) { + + bool multiple_sessions, challenge, b; + const char *t, *action; + + r = have_multiple_sessions(connection, m, message, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + multiple_sessions = r > 0; + + if (streq(dbus_message_get_member(message), "CanPowerOff")) { + if (multiple_sessions) + action = "org.freedesktop.login1.power-off-multiple-sessions"; + else + action = "org.freedesktop.login1.power-off"; + + } else { + if (multiple_sessions) + action = "org.freedesktop.login1.reboot-multiple-sessions"; + else + action = "org.freedesktop.login1.reboot"; + } + + r = verify_polkit(connection, message, action, false, &challenge, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + t = r > 0 ? "yes" : + challenge ? "challenge" : + "no"; + + b = dbus_message_append_args( + reply, + DBUS_TYPE_STRING, &t, + DBUS_TYPE_INVALID); + if (!b) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { char *introspection = NULL; FILE *f; diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index 5ae143694..9ef852bb7 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -84,6 +84,14 @@ send_interface="org.freedesktop.login1.Manager" send_member="Reboot"/> + + + + diff --git a/src/polkit.c b/src/polkit.c index 5b67480fe..3acbdc613 100644 --- a/src/polkit.c +++ b/src/polkit.c @@ -82,6 +82,7 @@ int verify_polkit( DBusMessage *request, const char *action, bool interactive, + bool *_challenge, DBusError *error) { DBusMessage *m = NULL, *reply = NULL; @@ -94,7 +95,7 @@ int verify_polkit( uint64_t starttime_u64; DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant; int r; - dbus_bool_t authorized = FALSE; + dbus_bool_t authorized = FALSE, challenge = FALSE; assert(c); assert(request); @@ -176,7 +177,21 @@ int verify_polkit( dbus_message_iter_get_basic(&iter_struct, &authorized); - r = authorized ? 0 : -EPERM; + if (!dbus_message_iter_next(&iter_struct) || + dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) { + r = -EIO; + goto finish; + } + + dbus_message_iter_get_basic(&iter_struct, &challenge); + + if (authorized) + r = 1; + else if (_challenge) { + *_challenge = !!challenge; + r = 0; + } else + r = -EPERM; finish: diff --git a/src/polkit.h b/src/polkit.h index fc4e77118..0d08194b2 100644 --- a/src/polkit.h +++ b/src/polkit.h @@ -30,6 +30,7 @@ int verify_polkit( DBusMessage *request, const char *action, bool interactive, + bool *challenge, DBusError *error); #endif diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 97306e9a3..792c61a7d 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -553,7 +553,7 @@ static DBusHandlerResult timedate_message_handler( if (!streq_ptr(z, tz.zone)) { char *t; - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -611,7 +611,7 @@ static DBusHandlerResult timedate_message_handler( if (lrtc != tz.local_rtc) { struct timespec ts; - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -702,7 +702,7 @@ static DBusHandlerResult timedate_message_handler( struct timespec ts; struct tm* tm; - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); @@ -741,7 +741,7 @@ static DBusHandlerResult timedate_message_handler( if (ntp != !!tz.use_ntp) { - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, &error); + r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, NULL, &error); if (r < 0) return bus_send_error_reply(connection, message, &error, r); -- 2.30.2