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/>.
24 #include <sys/capability.h>
29 #include "bus-common-errors.h"
30 #include "bus-label.h"
33 #include "logind-session.h"
34 #include "logind-session-device.h"
36 static int property_get_user(
39 const char *interface
,
41 sd_bus_message
*reply
,
43 sd_bus_error
*error
) {
45 _cleanup_free_
char *p
= NULL
;
46 Session
*s
= userdata
;
52 p
= user_bus_path(s
->user
);
56 return sd_bus_message_append(reply
, "(uo)", (uint32_t) s
->user
->uid
, p
);
59 static int property_get_name(
62 const char *interface
,
64 sd_bus_message
*reply
,
66 sd_bus_error
*error
) {
68 Session
*s
= userdata
;
74 return sd_bus_message_append(reply
, "s", s
->user
->name
);
77 static int property_get_seat(
80 const char *interface
,
82 sd_bus_message
*reply
,
84 sd_bus_error
*error
) {
86 _cleanup_free_
char *p
= NULL
;
87 Session
*s
= userdata
;
93 p
= s
->seat
? seat_bus_path(s
->seat
) : strdup("/");
97 return sd_bus_message_append(reply
, "(so)", s
->seat
? s
->seat
->id
: "", p
);
100 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, session_type
, SessionType
);
101 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class
, session_class
, SessionClass
);
103 static int property_get_active(
106 const char *interface
,
107 const char *property
,
108 sd_bus_message
*reply
,
110 sd_bus_error
*error
) {
112 Session
*s
= userdata
;
118 return sd_bus_message_append(reply
, "b", session_is_active(s
));
121 static int property_get_state(
124 const char *interface
,
125 const char *property
,
126 sd_bus_message
*reply
,
128 sd_bus_error
*error
) {
130 Session
*s
= userdata
;
136 return sd_bus_message_append(reply
, "s", session_state_to_string(session_get_state(s
)));
139 static int property_get_idle_hint(
142 const char *interface
,
143 const char *property
,
144 sd_bus_message
*reply
,
146 sd_bus_error
*error
) {
148 Session
*s
= userdata
;
154 return sd_bus_message_append(reply
, "b", session_get_idle_hint(s
, NULL
) > 0);
157 static int property_get_idle_since_hint(
160 const char *interface
,
161 const char *property
,
162 sd_bus_message
*reply
,
164 sd_bus_error
*error
) {
166 Session
*s
= userdata
;
175 r
= session_get_idle_hint(s
, &t
);
179 u
= streq(property
, "IdleSinceHint") ? t
.realtime
: t
.monotonic
;
181 return sd_bus_message_append(reply
, "t", u
);
184 static int method_terminate(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
185 Session
*s
= userdata
;
192 r
= session_stop(s
, true);
196 return sd_bus_reply_method_return(message
, NULL
);
199 static int method_activate(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
200 Session
*s
= userdata
;
207 r
= session_activate(s
);
211 return sd_bus_reply_method_return(message
, NULL
);
214 static int method_lock(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
215 Session
*s
= userdata
;
222 r
= session_send_lock(s
, streq(sd_bus_message_get_member(message
), "Lock"));
226 return sd_bus_reply_method_return(message
, NULL
);
229 static int method_set_idle_hint(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
230 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
231 Session
*s
= userdata
;
239 r
= sd_bus_message_read(message
, "b", &b
);
243 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_UID
, &creds
);
247 r
= sd_bus_creds_get_uid(creds
, &uid
);
251 if (uid
!= 0 && uid
!= s
->user
->uid
)
252 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set idle hint");
254 session_set_idle_hint(s
, b
);
256 return sd_bus_reply_method_return(message
, NULL
);
259 static int method_kill(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
260 Session
*s
= userdata
;
270 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
277 who
= kill_who_from_string(swho
);
279 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
282 if (signo
<= 0 || signo
>= _NSIG
)
283 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
285 r
= session_kill(s
, who
, signo
);
289 return sd_bus_reply_method_return(message
, NULL
);
292 static int method_take_control(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
293 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
294 Session
*s
= userdata
;
302 r
= sd_bus_message_read(message
, "b", &force
);
306 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_UID
, &creds
);
310 r
= sd_bus_creds_get_uid(creds
, &uid
);
314 if (uid
!= 0 && (force
|| uid
!= s
->user
->uid
))
315 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may take control");
317 r
= session_set_controller(s
, sd_bus_message_get_sender(message
), force
);
321 return sd_bus_reply_method_return(message
, NULL
);
324 static int method_release_control(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
325 Session
*s
= userdata
;
331 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
332 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
334 session_drop_controller(s
);
336 return sd_bus_reply_method_return(message
, NULL
);
339 static int method_take_device(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
340 Session
*s
= userdata
;
341 uint32_t major
, minor
;
350 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
354 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
355 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
357 dev
= makedev(major
, minor
);
358 sd
= hashmap_get(s
->devices
, &dev
);
360 /* We don't allow retrieving a device multiple times.
361 * The related ReleaseDevice call is not ref-counted.
362 * The caller should use dup() if it requires more
363 * than one fd (it would be functionally
365 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_IS_TAKEN
, "Device already taken");
367 r
= session_device_new(s
, dev
, &sd
);
371 r
= sd_bus_reply_method_return(message
, "hb", sd
->fd
, !sd
->active
);
373 session_device_free(sd
);
378 static int method_release_device(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
379 Session
*s
= userdata
;
380 uint32_t major
, minor
;
389 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
393 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
394 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
396 dev
= makedev(major
, minor
);
397 sd
= hashmap_get(s
->devices
, &dev
);
399 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
401 session_device_free(sd
);
402 return sd_bus_reply_method_return(message
, NULL
);
405 static int method_pause_device_complete(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
406 Session
*s
= userdata
;
407 uint32_t major
, minor
;
416 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
420 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
421 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
423 dev
= makedev(major
, minor
);
424 sd
= hashmap_get(s
->devices
, &dev
);
426 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
428 session_device_complete_pause(sd
);
430 return sd_bus_reply_method_return(message
, NULL
);
433 const sd_bus_vtable session_vtable
[] = {
434 SD_BUS_VTABLE_START(0),
436 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Session
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
437 SD_BUS_PROPERTY("User", "(uo)", property_get_user
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
438 SD_BUS_PROPERTY("Name", "s", property_get_name
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
439 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
440 SD_BUS_PROPERTY("VTNr", "u", NULL
, offsetof(Session
, vtnr
), SD_BUS_VTABLE_PROPERTY_CONST
),
441 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
442 SD_BUS_PROPERTY("TTY", "s", NULL
, offsetof(Session
, tty
), SD_BUS_VTABLE_PROPERTY_CONST
),
443 SD_BUS_PROPERTY("Display", "s", NULL
, offsetof(Session
, display
), SD_BUS_VTABLE_PROPERTY_CONST
),
444 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool
, offsetof(Session
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
445 SD_BUS_PROPERTY("RemoteHost", "s", NULL
, offsetof(Session
, remote_host
), SD_BUS_VTABLE_PROPERTY_CONST
),
446 SD_BUS_PROPERTY("RemoteUser", "s", NULL
, offsetof(Session
, remote_user
), SD_BUS_VTABLE_PROPERTY_CONST
),
447 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Session
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
448 SD_BUS_PROPERTY("Desktop", "s", NULL
, offsetof(Session
, desktop
), SD_BUS_VTABLE_PROPERTY_CONST
),
449 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Session
, scope
), SD_BUS_VTABLE_PROPERTY_CONST
),
450 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid
, offsetof(Session
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
451 SD_BUS_PROPERTY("Audit", "u", NULL
, offsetof(Session
, audit_id
), SD_BUS_VTABLE_PROPERTY_CONST
),
452 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Session
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
453 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Session
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
454 SD_BUS_PROPERTY("Active", "b", property_get_active
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
455 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
456 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
457 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
458 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
460 SD_BUS_METHOD("Terminate", NULL
, NULL
, method_terminate
, SD_BUS_VTABLE_CAPABILITY(CAP_KILL
)),
461 SD_BUS_METHOD("Activate", NULL
, NULL
, method_activate
, SD_BUS_VTABLE_UNPRIVILEGED
),
462 SD_BUS_METHOD("Lock", NULL
, NULL
, method_lock
, 0),
463 SD_BUS_METHOD("Unlock", NULL
, NULL
, method_lock
, 0),
464 SD_BUS_METHOD("SetIdleHint", "b", NULL
, method_set_idle_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
465 SD_BUS_METHOD("Kill", "si", NULL
, method_kill
, SD_BUS_VTABLE_CAPABILITY(CAP_KILL
)),
466 SD_BUS_METHOD("TakeControl", "b", NULL
, method_take_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
467 SD_BUS_METHOD("ReleaseControl", NULL
, NULL
, method_release_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
468 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
469 SD_BUS_METHOD("ReleaseDevice", "uu", NULL
, method_release_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
470 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL
, method_pause_device_complete
, SD_BUS_VTABLE_UNPRIVILEGED
),
472 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
473 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
474 SD_BUS_SIGNAL("Lock", NULL
, 0),
475 SD_BUS_SIGNAL("Unlock", NULL
, 0),
480 int session_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
481 Manager
*m
= userdata
;
491 if (streq(path
, "/org/freedesktop/login1/session/self")) {
492 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
493 sd_bus_message
*message
;
496 message
= sd_bus_get_current_message(bus
);
500 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
504 r
= sd_bus_creds_get_pid(creds
, &pid
);
508 r
= manager_get_session_by_pid(m
, pid
, &session
);
512 _cleanup_free_
char *e
= NULL
;
515 p
= startswith(path
, "/org/freedesktop/login1/session/");
519 e
= bus_label_unescape(p
);
523 session
= hashmap_get(m
->sessions
, e
);
532 char *session_bus_path(Session
*s
) {
533 _cleanup_free_
char *t
= NULL
;
537 t
= bus_label_escape(s
->id
);
541 return strappend("/org/freedesktop/login1/session/", t
);
544 int session_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
545 _cleanup_strv_free_
char **l
= NULL
;
546 Manager
*m
= userdata
;
555 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
558 p
= session_bus_path(session
);
562 r
= strv_consume(&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 and the user service
651 * were successfully created, and finishes where
652 * bus_manager_create_session() left off. */
654 if (!s
->create_message
)
657 if (!sd_bus_error_is_set(error
) && (s
->scope_job
|| s
->user
->service_job
))
660 c
= s
->create_message
;
661 s
->create_message
= NULL
;
664 return sd_bus_reply_method_error(c
, error
);
666 fifo_fd
= session_create_fifo(s
);
670 /* Update the session state file before we notify the client
671 * about the result. */
674 p
= session_bus_path(s
);
678 log_debug("Sending reply about created session: "
679 "id=%s object_path=%s uid=%u runtime_path=%s "
680 "session_fd=%d seat=%s vtnr=%u",
683 (uint32_t) s
->user
->uid
,
684 s
->user
->runtime_path
,
686 s
->seat
? s
->seat
->id
: "",
689 return sd_bus_reply_method_return(
693 s
->user
->runtime_path
,
695 (uint32_t) s
->user
->uid
,
696 s
->seat
? s
->seat
->id
: "",