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"
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
;
165 dual_timestamp t
= DUAL_TIMESTAMP_NULL
;
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 int bus_session_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
183 Session
*s
= userdata
;
189 r
= bus_verify_polkit_async(
192 "org.freedesktop.login1.manage",
196 &s
->manager
->polkit_registry
,
201 return 1; /* Will call us back */
203 r
= session_stop(s
, true);
207 return sd_bus_reply_method_return(message
, NULL
);
210 int bus_session_method_activate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
211 Session
*s
= userdata
;
217 r
= session_activate(s
);
221 return sd_bus_reply_method_return(message
, NULL
);
224 int bus_session_method_lock(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
225 Session
*s
= userdata
;
231 r
= bus_verify_polkit_async(
234 "org.freedesktop.login1.lock-sessions",
238 &s
->manager
->polkit_registry
,
243 return 1; /* Will call us back */
245 r
= session_send_lock(s
, strstr(sd_bus_message_get_member(message
), "Lock"));
249 return sd_bus_reply_method_return(message
, NULL
);
252 static int method_set_idle_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
253 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
254 Session
*s
= userdata
;
261 r
= sd_bus_message_read(message
, "b", &b
);
265 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
269 r
= sd_bus_creds_get_euid(creds
, &uid
);
273 if (uid
!= 0 && uid
!= s
->user
->uid
)
274 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set idle hint");
276 session_set_idle_hint(s
, b
);
278 return sd_bus_reply_method_return(message
, NULL
);
281 int bus_session_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
282 Session
*s
= userdata
;
291 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
298 who
= kill_who_from_string(swho
);
300 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
303 if (signo
<= 0 || signo
>= _NSIG
)
304 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
306 r
= bus_verify_polkit_async(
309 "org.freedesktop.login1.manage",
313 &s
->manager
->polkit_registry
,
318 return 1; /* Will call us back */
320 r
= session_kill(s
, who
, signo
);
324 return sd_bus_reply_method_return(message
, NULL
);
327 static int method_take_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
328 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
329 Session
*s
= userdata
;
336 r
= sd_bus_message_read(message
, "b", &force
);
340 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
344 r
= sd_bus_creds_get_euid(creds
, &uid
);
348 if (uid
!= 0 && (force
|| uid
!= s
->user
->uid
))
349 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may take control");
351 r
= session_set_controller(s
, sd_bus_message_get_sender(message
), force
);
355 return sd_bus_reply_method_return(message
, NULL
);
358 static int method_release_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
359 Session
*s
= userdata
;
364 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
365 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
367 session_drop_controller(s
);
369 return sd_bus_reply_method_return(message
, NULL
);
372 static int method_take_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
373 Session
*s
= userdata
;
374 uint32_t major
, minor
;
382 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
386 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
387 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
389 dev
= makedev(major
, minor
);
390 sd
= hashmap_get(s
->devices
, &dev
);
392 /* We don't allow retrieving a device multiple times.
393 * The related ReleaseDevice call is not ref-counted.
394 * The caller should use dup() if it requires more
395 * than one fd (it would be functionally
397 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_IS_TAKEN
, "Device already taken");
399 r
= session_device_new(s
, dev
, &sd
);
403 r
= sd_bus_reply_method_return(message
, "hb", sd
->fd
, !sd
->active
);
405 session_device_free(sd
);
410 static int method_release_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
411 Session
*s
= userdata
;
412 uint32_t major
, minor
;
420 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
424 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
425 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
427 dev
= makedev(major
, minor
);
428 sd
= hashmap_get(s
->devices
, &dev
);
430 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
432 session_device_free(sd
);
433 return sd_bus_reply_method_return(message
, NULL
);
436 static int method_pause_device_complete(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
437 Session
*s
= userdata
;
438 uint32_t major
, minor
;
446 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
450 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
451 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
453 dev
= makedev(major
, minor
);
454 sd
= hashmap_get(s
->devices
, &dev
);
456 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
458 session_device_complete_pause(sd
);
460 return sd_bus_reply_method_return(message
, NULL
);
463 const sd_bus_vtable session_vtable
[] = {
464 SD_BUS_VTABLE_START(0),
466 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Session
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
467 SD_BUS_PROPERTY("User", "(uo)", property_get_user
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
468 SD_BUS_PROPERTY("Name", "s", property_get_name
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
469 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
470 SD_BUS_PROPERTY("VTNr", "u", NULL
, offsetof(Session
, vtnr
), SD_BUS_VTABLE_PROPERTY_CONST
),
471 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
472 SD_BUS_PROPERTY("TTY", "s", NULL
, offsetof(Session
, tty
), SD_BUS_VTABLE_PROPERTY_CONST
),
473 SD_BUS_PROPERTY("Display", "s", NULL
, offsetof(Session
, display
), SD_BUS_VTABLE_PROPERTY_CONST
),
474 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool
, offsetof(Session
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
475 SD_BUS_PROPERTY("RemoteHost", "s", NULL
, offsetof(Session
, remote_host
), SD_BUS_VTABLE_PROPERTY_CONST
),
476 SD_BUS_PROPERTY("RemoteUser", "s", NULL
, offsetof(Session
, remote_user
), SD_BUS_VTABLE_PROPERTY_CONST
),
477 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Session
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
478 SD_BUS_PROPERTY("Desktop", "s", NULL
, offsetof(Session
, desktop
), SD_BUS_VTABLE_PROPERTY_CONST
),
479 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Session
, scope
), SD_BUS_VTABLE_PROPERTY_CONST
),
480 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid
, offsetof(Session
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
481 SD_BUS_PROPERTY("Audit", "u", NULL
, offsetof(Session
, audit_id
), SD_BUS_VTABLE_PROPERTY_CONST
),
482 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Session
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
483 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Session
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
484 SD_BUS_PROPERTY("Active", "b", property_get_active
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
485 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
486 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
487 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
488 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
490 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_session_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
491 SD_BUS_METHOD("Activate", NULL
, NULL
, bus_session_method_activate
, SD_BUS_VTABLE_UNPRIVILEGED
),
492 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
493 SD_BUS_METHOD("Unlock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
494 SD_BUS_METHOD("SetIdleHint", "b", NULL
, method_set_idle_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
495 SD_BUS_METHOD("Kill", "si", NULL
, bus_session_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
496 SD_BUS_METHOD("TakeControl", "b", NULL
, method_take_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
497 SD_BUS_METHOD("ReleaseControl", NULL
, NULL
, method_release_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
498 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
499 SD_BUS_METHOD("ReleaseDevice", "uu", NULL
, method_release_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
500 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL
, method_pause_device_complete
, SD_BUS_VTABLE_UNPRIVILEGED
),
502 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
503 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
504 SD_BUS_SIGNAL("Lock", NULL
, 0),
505 SD_BUS_SIGNAL("Unlock", NULL
, 0),
510 int session_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
511 Manager
*m
= userdata
;
521 if (streq(path
, "/org/freedesktop/login1/session/self")) {
522 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
523 sd_bus_message
*message
;
526 message
= sd_bus_get_current_message(bus
);
530 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
534 r
= sd_bus_creds_get_session(creds
, &name
);
538 session
= hashmap_get(m
->sessions
, name
);
540 _cleanup_free_
char *e
= NULL
;
543 p
= startswith(path
, "/org/freedesktop/login1/session/");
547 e
= bus_label_unescape(p
);
551 session
= hashmap_get(m
->sessions
, e
);
561 char *session_bus_path(Session
*s
) {
562 _cleanup_free_
char *t
= NULL
;
566 t
= bus_label_escape(s
->id
);
570 return strappend("/org/freedesktop/login1/session/", t
);
573 int session_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
574 _cleanup_strv_free_
char **l
= NULL
;
575 sd_bus_message
*message
;
576 Manager
*m
= userdata
;
585 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
588 p
= session_bus_path(session
);
592 r
= strv_consume(&l
, p
);
597 message
= sd_bus_get_current_message(bus
);
599 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
602 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
604 r
= sd_bus_creds_get_session(creds
, &name
);
606 session
= hashmap_get(m
->sessions
, name
);
608 r
= strv_extend(&l
, "/org/freedesktop/login1/session/self");
622 int session_send_signal(Session
*s
, bool new_session
) {
623 _cleanup_free_
char *p
= NULL
;
627 p
= session_bus_path(s
);
631 return sd_bus_emit_signal(
633 "/org/freedesktop/login1",
634 "org.freedesktop.login1.Manager",
635 new_session
? "SessionNew" : "SessionRemoved",
639 int session_send_changed(Session
*s
, const char *properties
, ...) {
640 _cleanup_free_
char *p
= NULL
;
648 p
= session_bus_path(s
);
652 l
= strv_from_stdarg_alloca(properties
);
654 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Session", l
);
657 int session_send_lock(Session
*s
, bool lock
) {
658 _cleanup_free_
char *p
= NULL
;
662 p
= session_bus_path(s
);
666 return sd_bus_emit_signal(
669 "org.freedesktop.login1.Session",
670 lock
? "Lock" : "Unlock",
674 int session_send_lock_all(Manager
*m
, bool lock
) {
681 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
684 k
= session_send_lock(session
, lock
);
692 int session_send_create_reply(Session
*s
, sd_bus_error
*error
) {
693 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
694 _cleanup_close_
int fifo_fd
= -1;
695 _cleanup_free_
char *p
= NULL
;
699 /* This is called after the session scope and the user service
700 * were successfully created, and finishes where
701 * bus_manager_create_session() left off. */
703 if (!s
->create_message
)
706 if (!sd_bus_error_is_set(error
) && (s
->scope_job
|| s
->user
->service_job
))
709 c
= s
->create_message
;
710 s
->create_message
= NULL
;
713 return sd_bus_reply_method_error(c
, error
);
715 fifo_fd
= session_create_fifo(s
);
719 /* Update the session state file before we notify the client
720 * about the result. */
723 p
= session_bus_path(s
);
727 log_debug("Sending reply about created session: "
728 "id=%s object_path=%s uid=%u runtime_path=%s "
729 "session_fd=%d seat=%s vtnr=%u",
732 (uint32_t) s
->user
->uid
,
733 s
->user
->runtime_path
,
735 s
->seat
? s
->seat
->id
: "",
738 return sd_bus_reply_method_return(
742 s
->user
->runtime_path
,
744 (uint32_t) s
->user
->uid
,
745 s
->seat
? s
->seat
->id
: "",