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 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
184 Session *s = userdata;
191 r = session_stop(s, true);
195 return sd_bus_reply_method_return(message, NULL);
198 static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
199 Session *s = userdata;
206 r = session_activate(s);
210 return sd_bus_reply_method_return(message, NULL);
213 static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
214 Session *s = userdata;
221 r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock"));
225 return sd_bus_reply_method_return(message, NULL);
228 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
229 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
230 Session *s = userdata;
238 r = sd_bus_message_read(message, "b", &b);
242 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
246 r = sd_bus_creds_get_euid(creds, &uid);
250 if (uid != 0 && uid != s->user->uid)
251 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
253 session_set_idle_hint(s, b);
255 return sd_bus_reply_method_return(message, NULL);
258 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
259 Session *s = userdata;
269 r = sd_bus_message_read(message, "si", &swho, &signo);
276 who = kill_who_from_string(swho);
278 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
281 if (signo <= 0 || signo >= _NSIG)
282 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
284 r = session_kill(s, who, signo);
288 return sd_bus_reply_method_return(message, NULL);
291 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
292 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
293 Session *s = userdata;
301 r = sd_bus_message_read(message, "b", &force);
305 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
309 r = sd_bus_creds_get_euid(creds, &uid);
313 if (uid != 0 && (force || uid != s->user->uid))
314 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
316 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
320 return sd_bus_reply_method_return(message, NULL);
323 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
324 Session *s = userdata;
330 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
331 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
333 session_drop_controller(s);
335 return sd_bus_reply_method_return(message, NULL);
338 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
339 Session *s = userdata;
340 uint32_t major, minor;
349 r = sd_bus_message_read(message, "uu", &major, &minor);
353 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
354 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
356 dev = makedev(major, minor);
357 sd = hashmap_get(s->devices, &dev);
359 /* We don't allow retrieving a device multiple times.
360 * The related ReleaseDevice call is not ref-counted.
361 * The caller should use dup() if it requires more
362 * than one fd (it would be functionally
364 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
366 r = session_device_new(s, dev, &sd);
370 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
372 session_device_free(sd);
377 static int method_release_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 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
400 session_device_free(sd);
401 return sd_bus_reply_method_return(message, NULL);
404 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
405 Session *s = userdata;
406 uint32_t major, minor;
415 r = sd_bus_message_read(message, "uu", &major, &minor);
419 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
420 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
422 dev = makedev(major, minor);
423 sd = hashmap_get(s->devices, &dev);
425 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
427 session_device_complete_pause(sd);
429 return sd_bus_reply_method_return(message, NULL);
432 const sd_bus_vtable session_vtable[] = {
433 SD_BUS_VTABLE_START(0),
435 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
436 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
437 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
438 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
439 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
440 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
441 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
442 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
443 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
444 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
445 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
446 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
447 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
448 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
449 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
450 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
451 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
452 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
453 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
454 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
455 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
456 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
457 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
459 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
460 SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
461 SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
462 SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
463 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
464 SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
465 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
466 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
467 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
468 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
469 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
471 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
472 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
473 SD_BUS_SIGNAL("Lock", NULL, 0),
474 SD_BUS_SIGNAL("Unlock", NULL, 0),
479 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
480 Manager *m = userdata;
490 if (streq(path, "/org/freedesktop/login1/session/self")) {
491 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
492 sd_bus_message *message;
495 message = sd_bus_get_current_message(bus);
499 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
503 r = sd_bus_creds_get_session(creds, &name);
507 session = hashmap_get(m->sessions, name);
509 _cleanup_free_ char *e = NULL;
512 p = startswith(path, "/org/freedesktop/login1/session/");
516 e = bus_label_unescape(p);
520 session = hashmap_get(m->sessions, e);
530 char *session_bus_path(Session *s) {
531 _cleanup_free_ char *t = NULL;
535 t = bus_label_escape(s->id);
539 return strappend("/org/freedesktop/login1/session/", t);
542 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
543 _cleanup_strv_free_ char **l = NULL;
544 sd_bus_message *message;
545 Manager *m = userdata;
554 HASHMAP_FOREACH(session, m->sessions, i) {
557 p = session_bus_path(session);
561 r = strv_consume(&l, p);
566 message = sd_bus_get_current_message(bus);
568 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
571 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
573 r = sd_bus_creds_get_session(creds, &name);
575 session = hashmap_get(m->sessions, name);
577 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
591 int session_send_signal(Session *s, bool new_session) {
592 _cleanup_free_ char *p = NULL;
596 p = session_bus_path(s);
600 return sd_bus_emit_signal(
602 "/org/freedesktop/login1",
603 "org.freedesktop.login1.Manager",
604 new_session ? "SessionNew" : "SessionRemoved",
608 int session_send_changed(Session *s, const char *properties, ...) {
609 _cleanup_free_ char *p = NULL;
617 p = session_bus_path(s);
621 l = strv_from_stdarg_alloca(properties);
623 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
626 int session_send_lock(Session *s, bool lock) {
627 _cleanup_free_ char *p = NULL;
631 p = session_bus_path(s);
635 return sd_bus_emit_signal(
638 "org.freedesktop.login1.Session",
639 lock ? "Lock" : "Unlock",
643 int session_send_lock_all(Manager *m, bool lock) {
650 HASHMAP_FOREACH(session, m->sessions, i) {
653 k = session_send_lock(session, lock);
661 int session_send_create_reply(Session *s, sd_bus_error *error) {
662 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
663 _cleanup_close_ int fifo_fd = -1;
664 _cleanup_free_ char *p = NULL;
668 /* This is called after the session scope and the user service
669 * were successfully created, and finishes where
670 * bus_manager_create_session() left off. */
672 if (!s->create_message)
675 if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
678 c = s->create_message;
679 s->create_message = NULL;
682 return sd_bus_reply_method_error(c, error);
684 fifo_fd = session_create_fifo(s);
688 /* Update the session state file before we notify the client
689 * about the result. */
692 p = session_bus_path(s);
696 log_debug("Sending reply about created session: "
697 "id=%s object_path=%s uid=%u runtime_path=%s "
698 "session_fd=%d seat=%s vtnr=%u",
701 (uint32_t) s->user->uid,
702 s->user->runtime_path,
704 s->seat ? s->seat->id : "",
707 return sd_bus_reply_method_return(
711 s->user->runtime_path,
713 (uint32_t) s->user->uid,
714 s->seat ? s->seat->id : "",