logind-dbus.c revision c2a23db0b91faca3795099fd4b41587bac170ff7
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2011 Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is free software; you can redistribute it and/or modify it
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen under the terms of the GNU Lesser General Public License as published by
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (at your option) any later version.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is distributed in the hope that it will be useful, but
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Lesser General Public License for more details.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen You should have received a copy of the GNU Lesser General Public License
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_creds_get_session(creds, &name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering session = hashmap_get(m->sessions, name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering /* Note that we get the owner UID of the session, not the actual client UID here! */
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering r = sd_bus_creds_get_owner_uid(creds, &uid);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering user = hashmap_get(m->users, UID_TO_PTR(uid));
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = manager_get_session_from_creds(m, message, NULL, error, &session);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (streq(property, "PreparingForShutdown"))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering b = !!(m->action_what & INHIBIT_SHUTDOWN);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_message_append(reply, "b", b);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int property_get_scheduled_shutdown(
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen r = sd_bus_message_open_container(reply, 'r', "st");
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read(message, "s", &name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert_cc(sizeof(pid_t) == sizeof(uint32_t));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt r = manager_get_session_from_creds(m, message, NULL, error, &session);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = manager_get_session_by_pid(m, pid, &session);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_read(message, "u", &uid);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = manager_get_user_from_creds(m, message, uid, error, &user);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poetteringstatic int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering assert_cc(sizeof(pid_t) == sizeof(uint32_t));
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_read(message, "u", &pid);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = manager_get_user_by_pid(m, pid, &user);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering 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);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_read(message, "s", &name);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = manager_get_seat_from_creds(m, message, name, error, &seat);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(susso)");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering HASHMAP_FOREACH(session, m->sessions, i) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_append(reply, "(susso)",
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_close_container(reply);
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poetteringstatic int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(uso)");
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = sd_bus_message_close_container(reply);
00fa60ae3b2823036cb3e7734f16bce30cb7441dLennart Poetteringstatic int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = sd_bus_message_new_method_return(message, &reply);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(so)");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_append(reply, "(so)", seat->id, p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_close_container(reply);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering strempty(inhibit_what_to_string(inhibitor->what)),
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering strempty(inhibit_mode_to_string(inhibitor->mode)),
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering r = sd_bus_message_close_container(reply);
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poetteringstatic int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
a38d99451f2bf8026ec51aee91662292e823c6a8Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = sd_bus_message_enter_container(message, 'a', "(sv)");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering manager_get_session_by_pid(m, leader, &session);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Session already exists, client is probably
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * something like "su" which changes uid but is still
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * the same session */
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering log_debug("Sending reply about an existing session: "
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering "id=%s object_path=%s uid=%u runtime_path=%s "
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering "session_fd=%d seat=%s vtnr=%u",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering audit_session_from_pid(leader, &audit_id);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Keep our session IDs and the audit session IDs in sync */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (asprintf(&id, "%"PRIu32, audit_id) < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Wut? There's already a session by this name and we
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * didn't find it above? Weird, then let's not trust
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the audit data and let's better register a new
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering session->remote_user = strdup(remote_user);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering session->remote_host = strdup(remote_host);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering session->create_message = sd_bus_message_ref(message);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Now, let's wait until the slice unit and stuff got
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * created. We send the reply back from
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * session_send_create_reply(). */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = sd_bus_message_read(message, "s", &name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return sd_bus_reply_method_return(message, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read(message, "s", &name);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return bus_session_method_activate(bus, message, session, error);
deb3f3d335d64601bb2d8a7520d8303f99d8a071Lennart Poetteringstatic int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering /* Same as ActivateSession() but refuses to work if
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering * the seat doesn't match */
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering r = manager_get_session_from_creds(m, message, session_name, error, &session);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering r = manager_get_seat_from_creds(m, message, seat_name, error, &seat);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return sd_bus_reply_method_return(message, NULL);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_bus_message_read(message, "s", &name);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return bus_session_method_lock(bus, message, session, error);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering "org.freedesktop.login1.lock-sessions",
556a22945fcc88ca27ae7ecc46c9bb2727e37895Lennart Poettering r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
556a22945fcc88ca27ae7ecc46c9bb2727e37895Lennart Poettering return sd_bus_reply_method_return(message, NULL);
556a22945fcc88ca27ae7ecc46c9bb2727e37895Lennart Poetteringstatic int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_read(message, "s", &name);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return bus_session_method_kill(bus, message, session, error);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringstatic int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_bus_message_read(message, "u", &uid);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = manager_get_user_from_creds(m, message, uid, error, &user);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return bus_user_method_kill(bus, message, user, error);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poetteringstatic int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering r = sd_bus_message_read(message, "s", &name);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering r = manager_get_session_from_creds(m, message, name, error, &session);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack return bus_session_method_terminate(bus, message, session, error);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poetteringstatic int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack r = manager_get_user_from_creds(m, message, uid, error, &user);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering return bus_user_method_terminate(bus, message, user, error);
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poetteringstatic int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_read(message, "s", &name);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = manager_get_seat_from_creds(m, message, name, error, &seat);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return bus_seat_method_terminate(bus, message, seat, error);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poetteringstatic int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering /* Note that we get the owner UID of the session, not the actual client UID here! */
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering r = sd_bus_creds_get_owner_uid(creds, &uid);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering "org.freedesktop.login1.set-user-linger",
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering path = strjoina("/var/lib/systemd/linger/", cc);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering if (manager_add_user_by_uid(m, uid, &u) >= 0)
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering u = hashmap_get(m->users, UID_TO_PTR(uid));
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering return sd_bus_reply_method_return(message, NULL);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poetteringstatic int trigger_device(Manager *m, struct udev_device *d) {
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
assert(m);
return -ENOMEM;
r = udev_enumerate_add_match_parent(e, d);
r = udev_enumerate_scan_devices(e);
return -ENOMEM;
const char *id_for_seat;
assert(m);
return -ENODEV;
return -ENODEV;
if (!id_for_seat)
return -ENODEV;
return -ENOMEM;
if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0)
return -ENOMEM;
return trigger_device(m, d);
assert(m);
static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
int interactive, r;
assert(m);
&m->polkit_registry,
error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
int interactive, r;
assert(m);
&m->polkit_registry,
error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = flush_devices(m);
static int have_multiple_sessions(
Manager *m,
Iterator i;
assert(m);
static int bus_manager_log_shutdown(
Manager *m,
InhibitWhat w,
const char *unit_name) {
assert(m);
if (w != INHIBIT_SHUTDOWN)
q = NULL;
NULL);
assert(e);
assert(m);
assert(m);
if (m->lid_switch_ignore_event_source) {
usec_t u;
if (until <= u)
r = sd_event_add_time(
m->event,
until, 0,
static int execute_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *unit_name,
assert(m);
assert(w >= 0);
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
c = strdup(p);
return -ENOMEM;
m->action_job = c;
m->action_what = w;
static int manager_inhibit_timeout_handler(
sd_event_source *s,
void *userdata) {
if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
log_notice("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
static int delay_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *unit_name) {
assert(m);
assert(w >= 0);
if (m->inhibit_timeout_source) {
m->action_what = w;
assert(m);
assert(w >= 0);
"/org/freedesktop/login1",
signal_name[w],
active);
Manager *m,
const char *unit_name,
InhibitWhat w,
bool delayed;
assert(m);
assert(w >= 0);
send_prepare_for(m, w, true);
delayed =
m->inhibit_delay_max > 0 &&
if (delayed)
static int verify_shutdown_creds(
Manager *m,
InhibitWhat w,
bool interactive,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
assert(m);
assert(w >= 0);
multiple_sessions = r > 0;
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, interactive, UID_INVALID, &m->polkit_registry, error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, interactive, UID_INVALID, &m->polkit_registry, error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, interactive, UID_INVALID, &m->polkit_registry, error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
static int method_do_shutdown_or_sleep(
Manager *m,
const char *unit_name,
InhibitWhat w,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
int interactive, r;
assert(m);
assert(w >= 0);
if (m->action_what)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
if (sleep_verb) {
static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
error);
static int nologin_timeout_handler(
sd_event_source *s,
void *userdata) {
m->unlink_nologin = true;
assert(m);
return log_oom();
fprintf(f,
(void) fflush_and_check(f);
r = -errno;
static int manager_scheduled_shutdown_handler(
sd_event_source *s,
void *userdata) {
const char *target;
assert(m);
static int method_schedule_shutdown(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
char *type;
assert(m);
if (m->scheduled_shutdown_timeout_source) {
return log_oom();
if (m->nologin_timeout_source) {
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
const char *tty;
return log_oom();
r = manager_setup_wall_message_timer(m);
r = update_schedule_file(m);
static int method_cancel_scheduled_shutdown(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
bool cancelled;
assert(m);
m->scheduled_shutdown_timeout = 0;
if (cancelled) {
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_can_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
assert(m);
assert(w >= 0);
if (sleep_verb) {
multiple_sessions = r > 0;
if (multiple_sessions) {
r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, UID_INVALID, &challenge, error);
else if (challenge)
if (blocked) {
if (r > 0 && !result)
else if (challenge)
static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
error);
static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int property_get_reboot_to_firmware_setup(
const char *path,
const char *interface,
const char *property,
void *userdata,
r = efi_get_reboot_to_firmware();
if (r < 0 && r != -EOPNOTSUPP)
static int method_set_reboot_to_firmware_setup(
void *userdata,
assert(m);
"org.freedesktop.login1.set-reboot-to-firmware-setup",
&m->polkit_registry,
error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = efi_set_reboot_to_firmware(b);
static int method_can_reboot_to_firmware_setup(
void *userdata,
bool challenge;
const char *result;
assert(m);
if (r == -EOPNOTSUPP)
"org.freedesktop.login1.set-reboot-to-firmware-setup",
error);
else if (challenge)
static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
InhibitWhat w;
assert(m);
if (mm < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
if (m->action_what & w)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
&m->polkit_registry,
error);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
return -ENOMEM;
i->what = w;
r = -ENOMEM;
goto fail;
if (fifo_fd < 0) {
r = fifo_fd;
goto fail;
inhibitor_start(i);
fail:
inhibitor_free(i);
SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
assert(s);
if (!s->started)
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
r = session_send_create_reply(s, &e);
assert(m);
m->action_what = 0;
if (session) {
if (user) {
assert(m);
if (session)
if (user)
int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path;
assert(m);
if (!path)
if (session)
if (user)
Iterator i;
int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Iterator i;
char *key;
if (!key)
"/org/freedesktop/login1",
int manager_start_scope(
const char *scope,
const char *slice,
const char *description,
char **job) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
r = sd_bus_message_close_container(m);
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
if (job)
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
if (!path)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Scope",
NULL,
NULL);
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
return sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
NULL,
const char *state;
if (!path)
return -ENOMEM;
r = sd_bus_get_property(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Unit",
&error,
&reply,
return -EINVAL;
r = sd_bus_get_property(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Job",
&error,
&reply,