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 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
229 Session *s = userdata;
237 r = sd_bus_message_read(message, "b", &b);
241 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
245 r = sd_bus_creds_get_uid(creds, &uid);
249 if (uid != 0 && uid != s->user->uid)
250 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session my set idle hint");
252 session_set_idle_hint(s, b);
254 return sd_bus_reply_method_return(message, NULL);
257 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
258 Session *s = userdata;
268 r = sd_bus_message_read(message, "si", &swho, &signo);
275 who = kill_who_from_string(swho);
277 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
280 if (signo <= 0 || signo >= _NSIG)
281 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
283 r = session_kill(s, who, signo);
287 return sd_bus_reply_method_return(message, NULL);
290 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
291 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
292 Session *s = userdata;
300 r = sd_bus_message_read(message, "b", &force);
304 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
308 r = sd_bus_creds_get_uid(creds, &uid);
312 if (uid != 0 && (force || uid != s->user->uid))
313 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
315 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
319 return sd_bus_reply_method_return(message, NULL);
322 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
323 Session *s = userdata;
329 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
330 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
332 session_drop_controller(s);
334 return sd_bus_reply_method_return(message, NULL);
337 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
338 Session *s = userdata;
339 uint32_t major, minor;
348 r = sd_bus_message_read(message, "uu", &major, &minor);
352 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
353 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
355 dev = makedev(major, minor);
356 sd = hashmap_get(s->devices, &dev);
358 /* We don't allow retrieving a device multiple times.
359 * The related ReleaseDevice call is not ref-counted.
360 * The caller should use dup() if it requires more
361 * than one fd (it would be functionally
363 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
365 r = session_device_new(s, dev, &sd);
369 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
371 session_device_free(sd);
376 static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
377 Session *s = userdata;
378 uint32_t major, minor;
387 r = sd_bus_message_read(message, "uu", &major, &minor);
391 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
392 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
394 dev = makedev(major, minor);
395 sd = hashmap_get(s->devices, &dev);
397 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
399 session_device_free(sd);
400 return sd_bus_reply_method_return(message, NULL);
403 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
404 Session *s = userdata;
405 uint32_t major, minor;
414 r = sd_bus_message_read(message, "uu", &major, &minor);
418 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
419 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
421 dev = makedev(major, minor);
422 sd = hashmap_get(s->devices, &dev);
424 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
426 session_device_complete_pause(sd);
428 return sd_bus_reply_method_return(message, NULL);
431 const sd_bus_vtable session_vtable[] = {
432 SD_BUS_VTABLE_START(0),
434 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), 0),
435 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, 0),
436 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, 0),
437 SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(Session, timestamp.realtime), 0),
438 SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(Session, timestamp.monotonic), 0),
439 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), 0),
440 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, 0),
441 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), 0),
442 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), 0),
443 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), 0),
444 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), 0),
445 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), 0),
446 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), 0),
447 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), 0),
448 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), 0),
449 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), 0),
450 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), 0),
451 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), 0),
452 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
453 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
454 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
455 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
456 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
458 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
459 SD_BUS_METHOD("Activate", NULL, NULL, method_activate, 0),
460 SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
461 SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
462 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, 0),
463 SD_BUS_METHOD("Kill", "si", NULL, method_kill, 0),
464 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, 0),
465 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, 0),
466 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, 0),
467 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, 0),
468 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, 0),
470 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
471 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
472 SD_BUS_SIGNAL("Lock", NULL, 0),
473 SD_BUS_SIGNAL("Unlock", NULL, 0),
478 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
479 Manager *m = userdata;
489 if (streq(path, "/org/freedesktop/login1/session/self")) {
490 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
491 sd_bus_message *message;
494 message = sd_bus_get_current(bus);
498 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
502 r = sd_bus_creds_get_pid(creds, &pid);
506 r = manager_get_session_by_pid(m, pid, &session);
510 _cleanup_free_ char *e = NULL;
513 p = startswith(path, "/org/freedesktop/login1/session/");
517 e = sd_bus_label_unescape(p);
521 session = hashmap_get(m->sessions, e);
530 char *session_bus_path(Session *s) {
531 _cleanup_free_ char *t = NULL;
535 t = sd_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 Manager *m = userdata;
553 HASHMAP_FOREACH(session, m->sessions, i) {
556 p = session_bus_path(session);
560 r = strv_push(&l, p);
573 int session_send_signal(Session *s, bool new_session) {
574 _cleanup_free_ char *p = NULL;
578 p = session_bus_path(s);
582 return sd_bus_emit_signal(
584 "/org/freedesktop/login1",
585 "org.freedesktop.login1.Manager",
586 new_session ? "SessionNew" : "SessionRemoved",
590 int session_send_changed(Session *s, const char *properties, ...) {
591 _cleanup_free_ char *p = NULL;
599 p = session_bus_path(s);
603 l = strv_from_stdarg_alloca(properties);
605 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
608 int session_send_lock(Session *s, bool lock) {
609 _cleanup_free_ char *p = NULL;
613 p = session_bus_path(s);
617 return sd_bus_emit_signal(
620 "org.freedesktop.login1.Session",
621 lock ? "Lock" : "Unlock",
625 int session_send_lock_all(Manager *m, bool lock) {
632 HASHMAP_FOREACH(session, m->sessions, i) {
635 k = session_send_lock(session, lock);
643 int session_send_create_reply(Session *s, sd_bus_error *error) {
644 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
645 _cleanup_close_ int fifo_fd = -1;
646 _cleanup_free_ char *p = NULL;
650 /* This is called after the session scope was successfully
651 * created, and finishes where bus_manager_create_session()
654 if (!s->create_message)
657 c = s->create_message;
658 s->create_message = NULL;
661 return sd_bus_reply_method_error(c, error);
663 fifo_fd = session_create_fifo(s);
667 /* Update the session state file before we notify the client
668 * about the result. */
671 p = session_bus_path(s);
675 log_debug("Sending reply about created session: "
676 "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u",
679 s->user->runtime_path,
681 s->seat ? s->seat->id : "",
684 return sd_bus_reply_method_return(
688 s->user->runtime_path,
690 (uint32_t) s->user->uid,
691 s->seat ? s->seat->id : "",