2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "bus-common-errors.h"
25 #include "bus-label.h"
28 #include "logind-session-device.h"
29 #include "logind-session.h"
31 #include "signal-util.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
;
166 dual_timestamp t
= DUAL_TIMESTAMP_NULL
;
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 property_get_locked_hint(
186 const char *interface
,
187 const char *property
,
188 sd_bus_message
*reply
,
190 sd_bus_error
*error
) {
192 Session
*s
= userdata
;
198 return sd_bus_message_append(reply
, "b", session_get_locked_hint(s
) > 0);
201 int bus_session_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
202 Session
*s
= userdata
;
208 r
= bus_verify_polkit_async(
211 "org.freedesktop.login1.manage",
215 &s
->manager
->polkit_registry
,
220 return 1; /* Will call us back */
222 r
= session_stop(s
, true);
226 return sd_bus_reply_method_return(message
, NULL
);
229 int bus_session_method_activate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
230 Session
*s
= userdata
;
236 r
= session_activate(s
);
240 return sd_bus_reply_method_return(message
, NULL
);
243 int bus_session_method_lock(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
244 Session
*s
= userdata
;
250 r
= bus_verify_polkit_async(
253 "org.freedesktop.login1.lock-sessions",
257 &s
->manager
->polkit_registry
,
262 return 1; /* Will call us back */
264 r
= session_send_lock(s
, strstr(sd_bus_message_get_member(message
), "Lock"));
268 return sd_bus_reply_method_return(message
, NULL
);
271 static int method_set_idle_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
272 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
273 Session
*s
= userdata
;
280 r
= sd_bus_message_read(message
, "b", &b
);
284 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
288 r
= sd_bus_creds_get_euid(creds
, &uid
);
292 if (uid
!= 0 && uid
!= s
->user
->uid
)
293 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set idle hint");
295 session_set_idle_hint(s
, b
);
297 return sd_bus_reply_method_return(message
, NULL
);
300 static int method_set_locked_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
301 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
302 Session
*s
= userdata
;
309 r
= sd_bus_message_read(message
, "b", &b
);
313 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
317 r
= sd_bus_creds_get_euid(creds
, &uid
);
321 if (uid
!= 0 && uid
!= s
->user
->uid
)
322 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set locked hint");
324 session_set_locked_hint(s
, b
);
326 return sd_bus_reply_method_return(message
, NULL
);
329 int bus_session_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
330 Session
*s
= userdata
;
339 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
346 who
= kill_who_from_string(swho
);
348 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
351 if (!SIGNAL_VALID(signo
))
352 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
354 r
= bus_verify_polkit_async(
357 "org.freedesktop.login1.manage",
361 &s
->manager
->polkit_registry
,
366 return 1; /* Will call us back */
368 r
= session_kill(s
, who
, signo
);
372 return sd_bus_reply_method_return(message
, NULL
);
375 static int method_take_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
376 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
377 Session
*s
= userdata
;
384 r
= sd_bus_message_read(message
, "b", &force
);
388 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
392 r
= sd_bus_creds_get_euid(creds
, &uid
);
396 if (uid
!= 0 && (force
|| uid
!= s
->user
->uid
))
397 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may take control");
399 r
= session_set_controller(s
, sd_bus_message_get_sender(message
), force
);
403 return sd_bus_reply_method_return(message
, NULL
);
406 static int method_release_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
407 Session
*s
= userdata
;
412 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
413 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
415 session_drop_controller(s
);
417 return sd_bus_reply_method_return(message
, NULL
);
420 static int method_take_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
421 Session
*s
= userdata
;
422 uint32_t major
, minor
;
430 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
434 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
435 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
437 dev
= makedev(major
, minor
);
438 sd
= hashmap_get(s
->devices
, &dev
);
440 /* We don't allow retrieving a device multiple times.
441 * The related ReleaseDevice call is not ref-counted.
442 * The caller should use dup() if it requires more
443 * than one fd (it would be functionally
445 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_IS_TAKEN
, "Device already taken");
447 r
= session_device_new(s
, dev
, &sd
);
451 r
= sd_bus_reply_method_return(message
, "hb", sd
->fd
, !sd
->active
);
453 session_device_free(sd
);
458 static int method_release_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
459 Session
*s
= userdata
;
460 uint32_t major
, minor
;
468 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
472 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
473 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
475 dev
= makedev(major
, minor
);
476 sd
= hashmap_get(s
->devices
, &dev
);
478 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
480 session_device_free(sd
);
481 return sd_bus_reply_method_return(message
, NULL
);
484 static int method_pause_device_complete(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
485 Session
*s
= userdata
;
486 uint32_t major
, minor
;
494 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
498 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
499 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
501 dev
= makedev(major
, minor
);
502 sd
= hashmap_get(s
->devices
, &dev
);
504 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
506 session_device_complete_pause(sd
);
508 return sd_bus_reply_method_return(message
, NULL
);
511 const sd_bus_vtable session_vtable
[] = {
512 SD_BUS_VTABLE_START(0),
514 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Session
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
515 SD_BUS_PROPERTY("User", "(uo)", property_get_user
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
516 SD_BUS_PROPERTY("Name", "s", property_get_name
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
517 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
518 SD_BUS_PROPERTY("VTNr", "u", NULL
, offsetof(Session
, vtnr
), SD_BUS_VTABLE_PROPERTY_CONST
),
519 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
520 SD_BUS_PROPERTY("TTY", "s", NULL
, offsetof(Session
, tty
), SD_BUS_VTABLE_PROPERTY_CONST
),
521 SD_BUS_PROPERTY("Display", "s", NULL
, offsetof(Session
, display
), SD_BUS_VTABLE_PROPERTY_CONST
),
522 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool
, offsetof(Session
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
523 SD_BUS_PROPERTY("RemoteHost", "s", NULL
, offsetof(Session
, remote_host
), SD_BUS_VTABLE_PROPERTY_CONST
),
524 SD_BUS_PROPERTY("RemoteUser", "s", NULL
, offsetof(Session
, remote_user
), SD_BUS_VTABLE_PROPERTY_CONST
),
525 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Session
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
526 SD_BUS_PROPERTY("Desktop", "s", NULL
, offsetof(Session
, desktop
), SD_BUS_VTABLE_PROPERTY_CONST
),
527 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Session
, scope
), SD_BUS_VTABLE_PROPERTY_CONST
),
528 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid
, offsetof(Session
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
529 SD_BUS_PROPERTY("Audit", "u", NULL
, offsetof(Session
, audit_id
), SD_BUS_VTABLE_PROPERTY_CONST
),
530 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Session
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
531 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Session
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
532 SD_BUS_PROPERTY("Active", "b", property_get_active
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
533 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
534 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
535 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
536 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
537 SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
539 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_session_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
540 SD_BUS_METHOD("Activate", NULL
, NULL
, bus_session_method_activate
, SD_BUS_VTABLE_UNPRIVILEGED
),
541 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
542 SD_BUS_METHOD("Unlock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
543 SD_BUS_METHOD("SetIdleHint", "b", NULL
, method_set_idle_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
544 SD_BUS_METHOD("SetLockedHint", "b", NULL
, method_set_locked_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
545 SD_BUS_METHOD("Kill", "si", NULL
, bus_session_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
546 SD_BUS_METHOD("TakeControl", "b", NULL
, method_take_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
547 SD_BUS_METHOD("ReleaseControl", NULL
, NULL
, method_release_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
548 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
549 SD_BUS_METHOD("ReleaseDevice", "uu", NULL
, method_release_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
550 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL
, method_pause_device_complete
, SD_BUS_VTABLE_UNPRIVILEGED
),
552 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
553 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
554 SD_BUS_SIGNAL("Lock", NULL
, 0),
555 SD_BUS_SIGNAL("Unlock", NULL
, 0),
560 int session_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
561 Manager
*m
= userdata
;
571 if (streq(path
, "/org/freedesktop/login1/session/self")) {
572 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
573 sd_bus_message
*message
;
576 message
= sd_bus_get_current_message(bus
);
580 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
584 r
= sd_bus_creds_get_session(creds
, &name
);
588 session
= hashmap_get(m
->sessions
, name
);
590 _cleanup_free_
char *e
= NULL
;
593 p
= startswith(path
, "/org/freedesktop/login1/session/");
597 e
= bus_label_unescape(p
);
601 session
= hashmap_get(m
->sessions
, e
);
611 char *session_bus_path(Session
*s
) {
612 _cleanup_free_
char *t
= NULL
;
616 t
= bus_label_escape(s
->id
);
620 return strappend("/org/freedesktop/login1/session/", t
);
623 int session_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
624 _cleanup_strv_free_
char **l
= NULL
;
625 sd_bus_message
*message
;
626 Manager
*m
= userdata
;
635 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
638 p
= session_bus_path(session
);
642 r
= strv_consume(&l
, p
);
647 message
= sd_bus_get_current_message(bus
);
649 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
652 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
654 r
= sd_bus_creds_get_session(creds
, &name
);
656 session
= hashmap_get(m
->sessions
, name
);
658 r
= strv_extend(&l
, "/org/freedesktop/login1/session/self");
672 int session_send_signal(Session
*s
, bool new_session
) {
673 _cleanup_free_
char *p
= NULL
;
677 p
= session_bus_path(s
);
681 return sd_bus_emit_signal(
683 "/org/freedesktop/login1",
684 "org.freedesktop.login1.Manager",
685 new_session
? "SessionNew" : "SessionRemoved",
689 int session_send_changed(Session
*s
, const char *properties
, ...) {
690 _cleanup_free_
char *p
= NULL
;
698 p
= session_bus_path(s
);
702 l
= strv_from_stdarg_alloca(properties
);
704 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Session", l
);
707 int session_send_lock(Session
*s
, bool lock
) {
708 _cleanup_free_
char *p
= NULL
;
712 p
= session_bus_path(s
);
716 return sd_bus_emit_signal(
719 "org.freedesktop.login1.Session",
720 lock
? "Lock" : "Unlock",
724 int session_send_lock_all(Manager
*m
, bool lock
) {
731 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
734 k
= session_send_lock(session
, lock
);
742 int session_send_create_reply(Session
*s
, sd_bus_error
*error
) {
743 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
744 _cleanup_close_
int fifo_fd
= -1;
745 _cleanup_free_
char *p
= NULL
;
749 /* This is called after the session scope and the user service
750 * were successfully created, and finishes where
751 * bus_manager_create_session() left off. */
753 if (!s
->create_message
)
756 if (!sd_bus_error_is_set(error
) && (s
->scope_job
|| s
->user
->service_job
))
759 c
= s
->create_message
;
760 s
->create_message
= NULL
;
763 return sd_bus_reply_method_error(c
, error
);
765 fifo_fd
= session_create_fifo(s
);
769 /* Update the session state file before we notify the client
770 * about the result. */
773 p
= session_bus_path(s
);
777 log_debug("Sending reply about created session: "
778 "id=%s object_path=%s uid=%u runtime_path=%s "
779 "session_fd=%d seat=%s vtnr=%u",
782 (uint32_t) s
->user
->uid
,
783 s
->user
->runtime_path
,
785 s
->seat
? s
->seat
->id
: "",
788 return sd_bus_reply_method_return(
792 s
->user
->runtime_path
,
794 (uint32_t) s
->user
->uid
,
795 s
->seat
? s
->seat
->id
: "",