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-errors.h"
31 #include "logind-session.h"
32 #include "logind-session-device.h"
34 static int property_get_user(
37 const char *interface,
39 sd_bus_message *reply,
41 sd_bus_error *error) {
43 _cleanup_free_ char *p = NULL;
44 Session *s = userdata;
50 p = user_bus_path(s->user);
54 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
57 static int property_get_name(
60 const char *interface,
62 sd_bus_message *reply,
64 sd_bus_error *error) {
66 Session *s = userdata;
72 return sd_bus_message_append(reply, "s", s->user->name);
75 static int property_get_seat(
78 const char *interface,
80 sd_bus_message *reply,
82 sd_bus_error *error) {
84 _cleanup_free_ char *p = NULL;
85 Session *s = userdata;
91 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
95 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
98 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
99 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
101 static int property_get_active(
104 const char *interface,
105 const char *property,
106 sd_bus_message *reply,
108 sd_bus_error *error) {
110 Session *s = userdata;
116 return sd_bus_message_append(reply, "b", session_is_active(s));
119 static int property_get_state(
122 const char *interface,
123 const char *property,
124 sd_bus_message *reply,
126 sd_bus_error *error) {
128 Session *s = userdata;
134 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
137 static int property_get_idle_hint(
140 const char *interface,
141 const char *property,
142 sd_bus_message *reply,
144 sd_bus_error *error) {
146 Session *s = userdata;
152 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
155 static int property_get_idle_since_hint(
158 const char *interface,
159 const char *property,
160 sd_bus_message *reply,
162 sd_bus_error *error) {
164 Session *s = userdata;
173 r = session_get_idle_hint(s, &t);
177 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
179 return sd_bus_message_append(reply, "t", u);
182 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
183 Session *s = userdata;
194 return sd_bus_reply_method_return(message, NULL);
197 static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
198 Session *s = userdata;
205 r = session_activate(s);
209 return sd_bus_reply_method_return(message, NULL);
212 static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
213 Session *s = userdata;
220 r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock"));
224 return sd_bus_reply_method_return(message, NULL);
227 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
228 Session *s = userdata;
236 r = sd_bus_message_read(message, "b", &b);
240 r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
244 if (uid != 0 && uid != s->user->uid)
245 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session my set idle hint");
247 session_set_idle_hint(s, b);
249 return sd_bus_reply_method_return(message, NULL);
252 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
253 Session *s = userdata;
263 r = sd_bus_message_read(message, "si", &swho, &signo);
270 who = kill_who_from_string(swho);
272 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
275 if (signo <= 0 || signo >= _NSIG)
276 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
278 r = session_kill(s, who, signo);
282 return sd_bus_reply_method_return(message, NULL);
285 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
286 Session *s = userdata;
294 r = sd_bus_message_read(message, "b", &force);
298 r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
302 if (uid != 0 && (force || uid != s->user->uid))
303 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
305 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
309 return sd_bus_reply_method_return(message, NULL);
312 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
313 Session *s = userdata;
319 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
320 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
322 session_drop_controller(s);
324 return sd_bus_reply_method_return(message, NULL);
327 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
328 Session *s = userdata;
329 uint32_t major, minor;
338 r = sd_bus_message_read(message, "uu", &major, &minor);
342 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
343 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
345 dev = makedev(major, minor);
346 sd = hashmap_get(s->devices, &dev);
348 /* We don't allow retrieving a device multiple times.
349 * The related ReleaseDevice call is not ref-counted.
350 * The caller should use dup() if it requires more
351 * than one fd (it would be functionally
353 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
355 r = session_device_new(s, dev, &sd);
359 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
361 session_device_free(sd);
366 static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
367 Session *s = userdata;
368 uint32_t major, minor;
377 r = sd_bus_message_read(message, "uu", &major, &minor);
381 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
382 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
384 dev = makedev(major, minor);
385 sd = hashmap_get(s->devices, &dev);
387 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
389 session_device_free(sd);
390 return sd_bus_reply_method_return(message, NULL);
393 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394 Session *s = userdata;
395 uint32_t major, minor;
404 r = sd_bus_message_read(message, "uu", &major, &minor);
408 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
409 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
411 dev = makedev(major, minor);
412 sd = hashmap_get(s->devices, &dev);
414 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
416 session_device_complete_pause(sd);
418 return sd_bus_reply_method_return(message, NULL);
421 const sd_bus_vtable session_vtable[] = {
422 SD_BUS_VTABLE_START(0),
424 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), 0),
425 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, 0),
426 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, 0),
427 SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(Session, timestamp.realtime), 0),
428 SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(Session, timestamp.monotonic), 0),
429 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), 0),
430 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, 0),
431 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), 0),
432 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), 0),
433 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), 0),
434 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), 0),
435 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), 0),
436 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), 0),
437 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), 0),
438 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), 0),
439 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), 0),
440 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), 0),
441 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), 0),
442 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
443 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
444 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
445 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
446 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
448 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
449 SD_BUS_METHOD("Activate", NULL, NULL, method_activate, 0),
450 SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
451 SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
452 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, 0),
453 SD_BUS_METHOD("Kill", "si", NULL, method_kill, 0),
454 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, 0),
455 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, 0),
456 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, 0),
457 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, 0),
458 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, 0),
460 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
461 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
462 SD_BUS_SIGNAL("Lock", NULL, 0),
463 SD_BUS_SIGNAL("Unlock", NULL, 0),
468 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
469 Manager *m = userdata;
479 if (streq(path, "/org/freedesktop/login1/session/self")) {
480 sd_bus_message *message;
483 message = sd_bus_get_current(bus);
487 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
491 r = manager_get_session_by_pid(m, pid, &session);
495 _cleanup_free_ char *e = NULL;
498 p = startswith(path, "/org/freedesktop/login1/session/");
502 e = sd_bus_label_unescape(p);
506 session = hashmap_get(m->sessions, e);
515 char *session_bus_path(Session *s) {
516 _cleanup_free_ char *t = NULL;
520 t = sd_bus_label_escape(s->id);
524 return strappend("/org/freedesktop/login1/session/", t);
527 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
528 _cleanup_strv_free_ char **l = NULL;
529 Manager *m = userdata;
538 HASHMAP_FOREACH(session, m->sessions, i) {
541 p = session_bus_path(session);
545 r = strv_push(&l, p);
558 int session_send_signal(Session *s, bool new_session) {
559 _cleanup_free_ char *p = NULL;
563 p = session_bus_path(s);
567 return sd_bus_emit_signal(
569 "/org/freedesktop/login1",
570 "org.freedesktop.login1.Manager",
571 new_session ? "SessionNew" : "SessionRemoved",
575 int session_send_changed(Session *s, const char *properties, ...) {
576 _cleanup_free_ char *p = NULL;
584 p = session_bus_path(s);
588 l = strv_from_stdarg_alloca(properties);
590 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
593 int session_send_lock(Session *s, bool lock) {
594 _cleanup_free_ char *p = NULL;
598 p = session_bus_path(s);
602 return sd_bus_emit_signal(
605 "org.freedesktop.login1.Session",
606 lock ? "Lock" : "Unlock",
610 int session_send_lock_all(Manager *m, bool lock) {
617 HASHMAP_FOREACH(session, m->sessions, i) {
620 k = session_send_lock(session, lock);
628 int session_send_create_reply(Session *s, sd_bus_error *error) {
629 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
630 _cleanup_close_ int fifo_fd = -1;
631 _cleanup_free_ char *p = NULL;
635 /* This is called after the session scope was successfully
636 * created, and finishes where bus_manager_create_session()
639 if (!s->create_message)
642 c = s->create_message;
643 s->create_message = NULL;
646 return sd_bus_reply_method_error(c, error);
648 fifo_fd = session_create_fifo(s);
652 /* Update the session state file before we notify the client
653 * about the result. */
656 p = session_bus_path(s);
660 log_debug("Sending reply about created session: "
661 "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u",
664 s->user->runtime_path,
666 s->seat ? s->seat->id : "",
669 return sd_bus_reply_method_return(
673 s->user->runtime_path,
675 (uint32_t) s->user->uid,
676 s->seat ? s->seat->id : "",