1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "bus-common-errors.h"
29 #include "bus-label.h"
32 #include "logind-session.h"
33 #include "logind-session-device.h"
35 static int property_get_user(
38 const char *interface,
40 sd_bus_message *reply,
42 sd_bus_error *error) {
44 _cleanup_free_ char *p = NULL;
45 Session *s = userdata;
51 p = user_bus_path(s->user);
55 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
58 static int property_get_name(
61 const char *interface,
63 sd_bus_message *reply,
65 sd_bus_error *error) {
67 Session *s = userdata;
73 return sd_bus_message_append(reply, "s", s->user->name);
76 static int property_get_seat(
79 const char *interface,
81 sd_bus_message *reply,
83 sd_bus_error *error) {
85 _cleanup_free_ char *p = NULL;
86 Session *s = userdata;
92 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
96 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
99 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
100 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
102 static int property_get_active(
105 const char *interface,
106 const char *property,
107 sd_bus_message *reply,
109 sd_bus_error *error) {
111 Session *s = userdata;
117 return sd_bus_message_append(reply, "b", session_is_active(s));
120 static int property_get_state(
123 const char *interface,
124 const char *property,
125 sd_bus_message *reply,
127 sd_bus_error *error) {
129 Session *s = userdata;
135 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
138 static int property_get_idle_hint(
141 const char *interface,
142 const char *property,
143 sd_bus_message *reply,
145 sd_bus_error *error) {
147 Session *s = userdata;
153 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
156 static int property_get_idle_since_hint(
159 const char *interface,
160 const char *property,
161 sd_bus_message *reply,
163 sd_bus_error *error) {
165 Session *s = userdata;
174 r = session_get_idle_hint(s, &t);
178 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
180 return sd_bus_message_append(reply, "t", u);
183 int bus_session_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
184 Session *s = userdata;
191 r = bus_verify_polkit_async(
194 "org.freedesktop.login1.manage",
197 &s->manager->polkit_registry,
202 return 1; /* Will call us back */
204 r = session_stop(s, true);
208 return sd_bus_reply_method_return(message, NULL);
211 int bus_session_method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
212 Session *s = userdata;
219 r = session_activate(s);
223 return sd_bus_reply_method_return(message, NULL);
226 int bus_session_method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
227 Session *s = userdata;
234 r = bus_verify_polkit_async(
237 "org.freedesktop.login1.lock-sessions",
240 &s->manager->polkit_registry,
245 return 1; /* Will call us back */
247 r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
251 return sd_bus_reply_method_return(message, NULL);
254 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
255 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
256 Session *s = userdata;
264 r = sd_bus_message_read(message, "b", &b);
268 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
272 r = sd_bus_creds_get_euid(creds, &uid);
276 if (uid != 0 && uid != s->user->uid)
277 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
279 session_set_idle_hint(s, b);
281 return sd_bus_reply_method_return(message, NULL);
284 int bus_session_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
285 Session *s = userdata;
295 r = sd_bus_message_read(message, "si", &swho, &signo);
302 who = kill_who_from_string(swho);
304 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
307 if (signo <= 0 || signo >= _NSIG)
308 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
310 r = bus_verify_polkit_async(
313 "org.freedesktop.login1.manage",
316 &s->manager->polkit_registry,
321 return 1; /* Will call us back */
323 r = session_kill(s, who, signo);
327 return sd_bus_reply_method_return(message, NULL);
330 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
331 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
332 Session *s = userdata;
340 r = sd_bus_message_read(message, "b", &force);
344 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
348 r = sd_bus_creds_get_euid(creds, &uid);
352 if (uid != 0 && (force || uid != s->user->uid))
353 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
355 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
359 return sd_bus_reply_method_return(message, NULL);
362 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
363 Session *s = userdata;
369 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
370 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
372 session_drop_controller(s);
374 return sd_bus_reply_method_return(message, NULL);
377 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
378 Session *s = userdata;
379 uint32_t major, minor;
388 r = sd_bus_message_read(message, "uu", &major, &minor);
392 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
393 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
395 dev = makedev(major, minor);
396 sd = hashmap_get(s->devices, &dev);
398 /* We don't allow retrieving a device multiple times.
399 * The related ReleaseDevice call is not ref-counted.
400 * The caller should use dup() if it requires more
401 * than one fd (it would be functionally
403 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
405 r = session_device_new(s, dev, &sd);
409 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
411 session_device_free(sd);
416 static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
417 Session *s = userdata;
418 uint32_t major, minor;
427 r = sd_bus_message_read(message, "uu", &major, &minor);
431 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
432 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
434 dev = makedev(major, minor);
435 sd = hashmap_get(s->devices, &dev);
437 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
439 session_device_free(sd);
440 return sd_bus_reply_method_return(message, NULL);
443 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
444 Session *s = userdata;
445 uint32_t major, minor;
454 r = sd_bus_message_read(message, "uu", &major, &minor);
458 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
459 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
461 dev = makedev(major, minor);
462 sd = hashmap_get(s->devices, &dev);
464 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
466 session_device_complete_pause(sd);
468 return sd_bus_reply_method_return(message, NULL);
471 const sd_bus_vtable session_vtable[] = {
472 SD_BUS_VTABLE_START(0),
474 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
475 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
476 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
477 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
478 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
479 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
480 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
481 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
482 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
483 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
484 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
485 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
486 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
487 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
488 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
489 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
490 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
491 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
492 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
493 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
494 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
495 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
496 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
498 SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
499 SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
500 SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
501 SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
502 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
503 SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
504 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
505 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
506 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
507 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
508 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
510 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
511 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
512 SD_BUS_SIGNAL("Lock", NULL, 0),
513 SD_BUS_SIGNAL("Unlock", NULL, 0),
518 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
519 Manager *m = userdata;
529 if (streq(path, "/org/freedesktop/login1/session/self")) {
530 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
531 sd_bus_message *message;
534 message = sd_bus_get_current_message(bus);
538 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
542 r = sd_bus_creds_get_session(creds, &name);
546 session = hashmap_get(m->sessions, name);
548 _cleanup_free_ char *e = NULL;
551 p = startswith(path, "/org/freedesktop/login1/session/");
555 e = bus_label_unescape(p);
559 session = hashmap_get(m->sessions, e);
569 char *session_bus_path(Session *s) {
570 _cleanup_free_ char *t = NULL;
574 t = bus_label_escape(s->id);
578 return strappend("/org/freedesktop/login1/session/", t);
581 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
582 _cleanup_strv_free_ char **l = NULL;
583 sd_bus_message *message;
584 Manager *m = userdata;
593 HASHMAP_FOREACH(session, m->sessions, i) {
596 p = session_bus_path(session);
600 r = strv_consume(&l, p);
605 message = sd_bus_get_current_message(bus);
607 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
610 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
612 r = sd_bus_creds_get_session(creds, &name);
614 session = hashmap_get(m->sessions, name);
616 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
630 int session_send_signal(Session *s, bool new_session) {
631 _cleanup_free_ char *p = NULL;
635 p = session_bus_path(s);
639 return sd_bus_emit_signal(
641 "/org/freedesktop/login1",
642 "org.freedesktop.login1.Manager",
643 new_session ? "SessionNew" : "SessionRemoved",
647 int session_send_changed(Session *s, const char *properties, ...) {
648 _cleanup_free_ char *p = NULL;
656 p = session_bus_path(s);
660 l = strv_from_stdarg_alloca(properties);
662 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
665 int session_send_lock(Session *s, bool lock) {
666 _cleanup_free_ char *p = NULL;
670 p = session_bus_path(s);
674 return sd_bus_emit_signal(
677 "org.freedesktop.login1.Session",
678 lock ? "Lock" : "Unlock",
682 int session_send_lock_all(Manager *m, bool lock) {
689 HASHMAP_FOREACH(session, m->sessions, i) {
692 k = session_send_lock(session, lock);
700 int session_send_create_reply(Session *s, sd_bus_error *error) {
701 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
702 _cleanup_close_ int fifo_fd = -1;
703 _cleanup_free_ char *p = NULL;
707 /* This is called after the session scope and the user service
708 * were successfully created, and finishes where
709 * bus_manager_create_session() left off. */
711 if (!s->create_message)
714 if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
717 c = s->create_message;
718 s->create_message = NULL;
721 return sd_bus_reply_method_error(c, error);
723 fifo_fd = session_create_fifo(s);
727 /* Update the session state file before we notify the client
728 * about the result. */
731 p = session_bus_path(s);
735 log_debug("Sending reply about created session: "
736 "id=%s object_path=%s uid=%u runtime_path=%s "
737 "session_fd=%d seat=%s vtnr=%u",
740 (uint32_t) s->user->uid,
741 s->user->runtime_path,
743 s->seat ? s->seat->id : "",
746 return sd_bus_reply_method_return(
750 s->user->runtime_path,
752 (uint32_t) s->user->uid,
753 s->seat ? s->seat->id : "",