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_message *message, void *userdata, sd_bus_error *error) {
184 Session *s = userdata;
190 r = bus_verify_polkit_async(
193 "org.freedesktop.login1.manage",
196 &s->manager->polkit_registry,
201 return 1; /* Will call us back */
203 r = session_stop(s, true);
207 return sd_bus_reply_method_return(message, NULL);
210 int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
211 Session *s = userdata;
217 r = session_activate(s);
221 return sd_bus_reply_method_return(message, NULL);
224 int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
225 Session *s = userdata;
231 r = bus_verify_polkit_async(
234 "org.freedesktop.login1.lock-sessions",
237 &s->manager->polkit_registry,
242 return 1; /* Will call us back */
244 r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
248 return sd_bus_reply_method_return(message, NULL);
251 static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
252 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
253 Session *s = userdata;
260 r = sd_bus_message_read(message, "b", &b);
264 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
268 r = sd_bus_creds_get_euid(creds, &uid);
272 if (uid != 0 && uid != s->user->uid)
273 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
275 session_set_idle_hint(s, b);
277 return sd_bus_reply_method_return(message, NULL);
280 int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
281 Session *s = userdata;
290 r = sd_bus_message_read(message, "si", &swho, &signo);
297 who = kill_who_from_string(swho);
299 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
302 if (signo <= 0 || signo >= _NSIG)
303 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
305 r = bus_verify_polkit_async(
308 "org.freedesktop.login1.manage",
311 &s->manager->polkit_registry,
316 return 1; /* Will call us back */
318 r = session_kill(s, who, signo);
322 return sd_bus_reply_method_return(message, NULL);
325 static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
326 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
327 Session *s = userdata;
334 r = sd_bus_message_read(message, "b", &force);
338 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
342 r = sd_bus_creds_get_euid(creds, &uid);
346 if (uid != 0 && (force || uid != s->user->uid))
347 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
349 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
353 return sd_bus_reply_method_return(message, NULL);
356 static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
357 Session *s = userdata;
362 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
363 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
365 session_drop_controller(s);
367 return sd_bus_reply_method_return(message, NULL);
370 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
371 Session *s = userdata;
372 uint32_t major, minor;
380 r = sd_bus_message_read(message, "uu", &major, &minor);
384 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
385 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
387 dev = makedev(major, minor);
388 sd = hashmap_get(s->devices, &dev);
390 /* We don't allow retrieving a device multiple times.
391 * The related ReleaseDevice call is not ref-counted.
392 * The caller should use dup() if it requires more
393 * than one fd (it would be functionally
395 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
397 r = session_device_new(s, dev, &sd);
401 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
403 session_device_free(sd);
408 static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
409 Session *s = userdata;
410 uint32_t major, minor;
418 r = sd_bus_message_read(message, "uu", &major, &minor);
422 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
423 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
425 dev = makedev(major, minor);
426 sd = hashmap_get(s->devices, &dev);
428 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
430 session_device_free(sd);
431 return sd_bus_reply_method_return(message, NULL);
434 static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
435 Session *s = userdata;
436 uint32_t major, minor;
444 r = sd_bus_message_read(message, "uu", &major, &minor);
448 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
449 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
451 dev = makedev(major, minor);
452 sd = hashmap_get(s->devices, &dev);
454 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
456 session_device_complete_pause(sd);
458 return sd_bus_reply_method_return(message, NULL);
461 const sd_bus_vtable session_vtable[] = {
462 SD_BUS_VTABLE_START(0),
464 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
465 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
466 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
467 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
468 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
469 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
470 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
471 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
472 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
473 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
474 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
475 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
476 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
477 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
478 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
479 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
480 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
481 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
482 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
483 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
484 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
485 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
486 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
488 SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
489 SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
490 SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
491 SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
492 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
493 SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
494 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
495 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
496 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
497 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
498 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
500 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
501 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
502 SD_BUS_SIGNAL("Lock", NULL, 0),
503 SD_BUS_SIGNAL("Unlock", NULL, 0),
508 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
509 Manager *m = userdata;
519 if (streq(path, "/org/freedesktop/login1/session/self")) {
520 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
521 sd_bus_message *message;
524 message = sd_bus_get_current_message(bus);
528 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
532 r = sd_bus_creds_get_session(creds, &name);
536 session = hashmap_get(m->sessions, name);
538 _cleanup_free_ char *e = NULL;
541 p = startswith(path, "/org/freedesktop/login1/session/");
545 e = bus_label_unescape(p);
549 session = hashmap_get(m->sessions, e);
559 char *session_bus_path(Session *s) {
560 _cleanup_free_ char *t = NULL;
564 t = bus_label_escape(s->id);
568 return strappend("/org/freedesktop/login1/session/", t);
571 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
572 _cleanup_strv_free_ char **l = NULL;
573 sd_bus_message *message;
574 Manager *m = userdata;
583 HASHMAP_FOREACH(session, m->sessions, i) {
586 p = session_bus_path(session);
590 r = strv_consume(&l, p);
595 message = sd_bus_get_current_message(bus);
597 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
600 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
602 r = sd_bus_creds_get_session(creds, &name);
604 session = hashmap_get(m->sessions, name);
606 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
620 int session_send_signal(Session *s, bool new_session) {
621 _cleanup_free_ char *p = NULL;
625 p = session_bus_path(s);
629 return sd_bus_emit_signal(
631 "/org/freedesktop/login1",
632 "org.freedesktop.login1.Manager",
633 new_session ? "SessionNew" : "SessionRemoved",
637 int session_send_changed(Session *s, const char *properties, ...) {
638 _cleanup_free_ char *p = NULL;
646 p = session_bus_path(s);
650 l = strv_from_stdarg_alloca(properties);
652 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
655 int session_send_lock(Session *s, bool lock) {
656 _cleanup_free_ char *p = NULL;
660 p = session_bus_path(s);
664 return sd_bus_emit_signal(
667 "org.freedesktop.login1.Session",
668 lock ? "Lock" : "Unlock",
672 int session_send_lock_all(Manager *m, bool lock) {
679 HASHMAP_FOREACH(session, m->sessions, i) {
682 k = session_send_lock(session, lock);
690 int session_send_create_reply(Session *s, sd_bus_error *error) {
691 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
692 _cleanup_close_ int fifo_fd = -1;
693 _cleanup_free_ char *p = NULL;
697 /* This is called after the session scope and the user service
698 * were successfully created, and finishes where
699 * bus_manager_create_session() left off. */
701 if (!s->create_message)
704 c = s->create_message;
705 s->create_message = NULL;
708 return sd_bus_reply_method_error(c, error);
710 fifo_fd = session_create_fifo(s);
714 /* Update the session and user state files before we notify
715 * the client about the result. */
719 p = session_bus_path(s);
723 log_debug("Sending reply about created session: "
724 "id=%s object_path=%s uid=%u runtime_path=%s "
725 "session_fd=%d seat=%s vtnr=%u",
728 (uint32_t) s->user->uid,
729 s->user->runtime_path,
731 s->seat ? s->seat->id : "",
734 return sd_bus_reply_method_return(
738 s->user->runtime_path,
740 (uint32_t) s->user->uid,
741 s->seat ? s->seat->id : "",