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/>.
30 #include "logind-session.h"
31 #include "logind-session-device.h"
33 static int property_get_user(
36 const char *interface,
38 sd_bus_message *reply,
42 _cleanup_free_ char *p = NULL;
43 Session *s = userdata;
49 p = user_bus_path(s->user);
53 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
56 static int property_get_name(
59 const char *interface,
61 sd_bus_message *reply,
65 Session *s = userdata;
71 return sd_bus_message_append(reply, "s", s->user->name);
74 static int property_get_seat(
77 const char *interface,
79 sd_bus_message *reply,
83 _cleanup_free_ char *p = NULL;
84 Session *s = userdata;
90 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
94 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
97 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
98 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
100 static int property_get_active(
103 const char *interface,
104 const char *property,
105 sd_bus_message *reply,
109 Session *s = userdata;
115 return sd_bus_message_append(reply, "b", session_is_active(s));
118 static int property_get_state(
121 const char *interface,
122 const char *property,
123 sd_bus_message *reply,
127 Session *s = userdata;
133 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
136 static int property_get_idle_hint(
139 const char *interface,
140 const char *property,
141 sd_bus_message *reply,
145 Session *s = userdata;
151 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
154 static int property_get_idle_since_hint(
157 const char *interface,
158 const char *property,
159 sd_bus_message *reply,
163 Session *s = userdata;
172 r = session_get_idle_hint(s, &t);
176 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
178 return sd_bus_message_append(reply, "t", u);
181 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata) {
182 Session *s = userdata;
191 return sd_bus_reply_method_errno(bus, message, r, NULL);
193 return sd_bus_reply_method_return(bus, message, NULL);
196 static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata) {
197 Session *s = userdata;
204 r = session_activate(s);
206 return sd_bus_reply_method_errno(bus, message, r, NULL);
208 return sd_bus_reply_method_return(bus, message, NULL);
211 static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata) {
212 Session *s = userdata;
219 r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock"));
221 return sd_bus_reply_method_errno(bus, message, r, NULL);
223 return sd_bus_reply_method_return(bus, message, NULL);
226 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata) {
227 Session *s = userdata;
235 r = sd_bus_message_read(message, "b", &b);
237 return sd_bus_reply_method_errno(bus, message, r, NULL);
239 r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
241 return sd_bus_reply_method_errno(bus, message, r, NULL);
243 if (uid != 0 && uid != s->user->uid)
244 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session my set idle hint");
246 session_set_idle_hint(s, b);
248 return sd_bus_reply_method_return(bus, message, NULL);
251 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata) {
252 Session *s = userdata;
262 r = sd_bus_message_read(message, "si", &swho, &signo);
264 return sd_bus_reply_method_errno(bus, message, r, NULL);
269 who = kill_who_from_string(swho);
271 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
274 if (signo <= 0 || signo >= _NSIG)
275 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
277 r = session_kill(s, who, signo);
279 return sd_bus_reply_method_errno(bus, message, r, NULL);
281 return sd_bus_reply_method_return(bus, message, NULL);
284 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata) {
285 Session *s = userdata;
293 r = sd_bus_message_read(message, "b", &force);
295 return sd_bus_reply_method_errno(bus, message, r, NULL);
297 r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
299 return sd_bus_reply_method_errno(bus, message, r, NULL);
301 if (uid != 0 && (force || uid != s->user->uid))
302 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
304 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
306 return sd_bus_reply_method_errno(bus, message, r, NULL);
308 return sd_bus_reply_method_return(bus, message, NULL);
311 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata) {
312 Session *s = userdata;
318 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
319 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
321 session_drop_controller(s);
323 return sd_bus_reply_method_return(bus, message, NULL);
326 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata) {
327 Session *s = userdata;
328 uint32_t major, minor;
337 r = sd_bus_message_read(message, "uu", &major, &minor);
339 return sd_bus_reply_method_errno(bus, message, r, NULL);
341 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
342 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
344 dev = makedev(major, minor);
345 sd = hashmap_get(s->devices, &dev);
347 /* We don't allow retrieving a device multiple times.
348 * The related ReleaseDevice call is not ref-counted.
349 * The caller should use dup() if it requires more
350 * than one fd (it would be functionally
352 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
354 r = session_device_new(s, dev, &sd);
356 return sd_bus_reply_method_errno(bus, message, r, NULL);
358 r = sd_bus_reply_method_return(bus, message, "hb", sd->fd, !sd->active);
360 session_device_free(sd);
365 static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata) {
366 Session *s = userdata;
367 uint32_t major, minor;
376 r = sd_bus_message_read(message, "uu", &major, &minor);
378 return sd_bus_reply_method_errno(bus, message, r, NULL);
380 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
381 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
383 dev = makedev(major, minor);
384 sd = hashmap_get(s->devices, &dev);
386 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
388 session_device_free(sd);
389 return sd_bus_reply_method_return(bus, message, NULL);
392 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata) {
393 Session *s = userdata;
394 uint32_t major, minor;
403 r = sd_bus_message_read(message, "uu", &major, &minor);
405 return sd_bus_reply_method_errno(bus, message, r, NULL);
407 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
408 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
410 dev = makedev(major, minor);
411 sd = hashmap_get(s->devices, &dev);
413 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
415 session_device_complete_pause(sd);
417 return sd_bus_reply_method_return(bus, message, NULL);
420 const sd_bus_vtable session_vtable[] = {
421 SD_BUS_VTABLE_START(0),
423 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), 0),
424 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, 0),
425 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, 0),
426 SD_BUS_PROPERTY("Timestamp", "t", NULL, offsetof(Session, timestamp.realtime), 0),
427 SD_BUS_PROPERTY("TimestampMonotonic", "t", NULL, offsetof(Session, timestamp.monotonic), 0),
428 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), 0),
429 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, 0),
430 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), 0),
431 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), 0),
432 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), 0),
433 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), 0),
434 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), 0),
435 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), 0),
436 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), 0),
437 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), 0),
438 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), 0),
439 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), 0),
440 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), 0),
441 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
442 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
443 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
444 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
445 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
447 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
448 SD_BUS_METHOD("Activate", NULL, NULL, method_activate, 0),
449 SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
450 SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
451 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, 0),
452 SD_BUS_METHOD("Kill", "si", NULL, method_kill, 0),
453 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, 0),
454 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, 0),
455 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, 0),
456 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, 0),
457 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, 0),
459 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
460 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
461 SD_BUS_SIGNAL("Lock", NULL, 0),
462 SD_BUS_SIGNAL("Unlock", NULL, 0),
467 int session_object_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
468 _cleanup_free_ char *e = NULL;
469 Manager *m = userdata;
479 p = startswith(path, "/org/freedesktop/login1/session/");
483 e = bus_path_unescape(p);
487 session = hashmap_get(m->sessions, e);
495 char *session_bus_path(Session *s) {
496 _cleanup_free_ char *t = NULL;
500 t = bus_path_escape(s->id);
504 return strappend("/org/freedesktop/login1/session/", t);
507 int session_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
508 _cleanup_strv_free_ char **l = NULL;
509 Manager *m = userdata;
518 HASHMAP_FOREACH(session, m->sessions, i) {
521 p = session_bus_path(session);
525 r = strv_push(&l, p);
538 int session_send_signal(Session *s, bool new_session) {
539 _cleanup_free_ char *p = NULL;
543 p = session_bus_path(s);
547 return sd_bus_emit_signal(
549 "/org/freedesktop/login1",
550 "org.freedesktop.login1.Manager",
551 new_session ? "SessionNew" : "SessionRemoved",
555 int session_send_changed(Session *s, const char *properties, ...) {
556 _cleanup_free_ char *p = NULL;
564 p = session_bus_path(s);
568 l = strv_from_stdarg_alloca(properties);
570 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
573 int session_send_lock(Session *s, bool lock) {
574 _cleanup_free_ char *p = NULL;
578 p = session_bus_path(s);
582 return sd_bus_emit_signal(
585 "org.freedesktop.login1.Session",
586 lock ? "Lock" : "Unlock",
590 int session_send_lock_all(Manager *m, bool lock) {
597 HASHMAP_FOREACH(session, m->sessions, i) {
600 k = session_send_lock(session, lock);
608 int session_send_create_reply(Session *s, sd_bus_error *error) {
609 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
610 _cleanup_close_ int fifo_fd = -1;
611 _cleanup_free_ char *p = NULL;
615 /* This is called after the session scope was successfully
616 * created, and finishes where bus_manager_create_session()
619 if (!s->create_message)
622 c = s->create_message;
623 s->create_message = NULL;
626 return sd_bus_reply_method_error(s->manager->bus, c, error);
628 /* Update the session state file before we notify the client
629 * about the result. */
632 fifo_fd = session_create_fifo(s);
636 p = session_bus_path(s);
640 return sd_bus_reply_method_return(
645 s->user->runtime_path,
647 s->seat ? s->seat->id : "",