]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/login/logind-session-dbus.c
tree-wide: Add more socket units (#37991)
[thirdparty/systemd.git] / src / login / logind-session-dbus.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <sys/eventfd.h>
4
5#include "sd-bus.h"
6#include "sd-device.h"
7
8#include "alloc-util.h"
9#include "bus-common-errors.h"
10#include "bus-get-properties.h"
11#include "bus-label.h"
12#include "bus-object.h"
13#include "bus-polkit.h"
14#include "device-util.h"
15#include "devnum-util.h"
16#include "errno-util.h"
17#include "fd-util.h"
18#include "format-util.h"
19#include "hashmap.h"
20#include "log.h"
21#include "logind.h"
22#include "logind-brightness.h"
23#include "logind-dbus.h"
24#include "logind-polkit.h"
25#include "logind-seat.h"
26#include "logind-seat-dbus.h"
27#include "logind-session.h"
28#include "logind-session-dbus.h"
29#include "logind-session-device.h"
30#include "logind-user.h"
31#include "logind-user-dbus.h"
32#include "path-util.h"
33#include "signal-util.h"
34#include "string-util.h"
35#include "strv.h"
36#include "terminal-util.h"
37#include "user-record.h"
38#include "user-util.h"
39
40static int property_get_user(
41 sd_bus *bus,
42 const char *path,
43 const char *interface,
44 const char *property,
45 sd_bus_message *reply,
46 void *userdata,
47 sd_bus_error *error) {
48
49 _cleanup_free_ char *p = NULL;
50 Session *s = ASSERT_PTR(userdata);
51
52 assert(bus);
53 assert(reply);
54
55 p = user_bus_path(s->user);
56 if (!p)
57 return -ENOMEM;
58
59 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->user_record->uid, p);
60}
61
62static int property_get_name(
63 sd_bus *bus,
64 const char *path,
65 const char *interface,
66 const char *property,
67 sd_bus_message *reply,
68 void *userdata,
69 sd_bus_error *error) {
70
71 Session *s = ASSERT_PTR(userdata);
72
73 assert(bus);
74 assert(reply);
75
76 return sd_bus_message_append(reply, "s", s->user->user_record->user_name);
77}
78
79static int property_get_seat(
80 sd_bus *bus,
81 const char *path,
82 const char *interface,
83 const char *property,
84 sd_bus_message *reply,
85 void *userdata,
86 sd_bus_error *error) {
87
88 _cleanup_free_ char *p = NULL;
89 Session *s = ASSERT_PTR(userdata);
90
91 assert(bus);
92 assert(reply);
93
94 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
95 if (!p)
96 return -ENOMEM;
97
98 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
99}
100
101static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
102static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
103static BUS_DEFINE_PROPERTY_GET(property_get_active, "b", Session, session_is_active);
104static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Session, session_get_state, session_state_to_string);
105
106static int property_get_idle_hint(
107 sd_bus *bus,
108 const char *path,
109 const char *interface,
110 const char *property,
111 sd_bus_message *reply,
112 void *userdata,
113 sd_bus_error *error) {
114
115 Session *s = ASSERT_PTR(userdata);
116
117 assert(bus);
118 assert(reply);
119
120 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
121}
122
123static int property_get_can_idle(
124 sd_bus *bus,
125 const char *path,
126 const char *interface,
127 const char *property,
128 sd_bus_message *reply,
129 void *userdata,
130 sd_bus_error *error) {
131
132 Session *s = ASSERT_PTR(userdata);
133
134 assert(bus);
135 assert(reply);
136
137 return sd_bus_message_append(reply, "b", SESSION_CLASS_CAN_IDLE(s->class));
138}
139
140static int property_get_can_lock(
141 sd_bus *bus,
142 const char *path,
143 const char *interface,
144 const char *property,
145 sd_bus_message *reply,
146 void *userdata,
147 sd_bus_error *error) {
148
149 Session *s = ASSERT_PTR(userdata);
150
151 assert(bus);
152 assert(reply);
153
154 return sd_bus_message_append(reply, "b", SESSION_CLASS_CAN_LOCK(s->class));
155}
156
157static int property_get_idle_since_hint(
158 sd_bus *bus,
159 const char *path,
160 const char *interface,
161 const char *property,
162 sd_bus_message *reply,
163 void *userdata,
164 sd_bus_error *error) {
165
166 Session *s = ASSERT_PTR(userdata);
167 dual_timestamp t = DUAL_TIMESTAMP_NULL;
168 uint64_t u;
169 int r;
170
171 assert(bus);
172 assert(reply);
173
174 r = session_get_idle_hint(s, &t);
175 if (r < 0)
176 return r;
177
178 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
179
180 return sd_bus_message_append(reply, "t", u);
181}
182
183static int property_get_locked_hint(
184 sd_bus *bus,
185 const char *path,
186 const char *interface,
187 const char *property,
188 sd_bus_message *reply,
189 void *userdata,
190 sd_bus_error *error) {
191
192 Session *s = ASSERT_PTR(userdata);
193
194 assert(bus);
195 assert(reply);
196
197 return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0);
198}
199
200int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
201 Session *s = ASSERT_PTR(userdata);
202 int r;
203
204 assert(message);
205
206 r = bus_verify_polkit_async_full(
207 message,
208 "org.freedesktop.login1.manage",
209 /* details= */ NULL,
210 s->user->user_record->uid,
211 /* flags= */ 0,
212 &s->manager->polkit_registry,
213 error);
214 if (r < 0)
215 return r;
216 if (r == 0)
217 return 1; /* Will call us back */
218
219 r = session_stop(s, /* force = */ true);
220 if (r < 0)
221 return r;
222
223 return sd_bus_reply_method_return(message, NULL);
224}
225
226int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
227 Session *s = ASSERT_PTR(userdata);
228 int r;
229
230 assert(message);
231
232 r = check_polkit_chvt(message, s->manager, error);
233 if (r < 0)
234 return r;
235 if (r == 0)
236 return 1; /* Will call us back */
237
238 r = session_activate(s);
239 if (r < 0)
240 return r;
241
242 return sd_bus_reply_method_return(message, NULL);
243}
244
245int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
246 Session *s = ASSERT_PTR(userdata);
247 int r;
248
249 assert(message);
250
251 r = bus_verify_polkit_async_full(
252 message,
253 "org.freedesktop.login1.lock-sessions",
254 /* details= */ NULL,
255 s->user->user_record->uid,
256 /* flags= */ 0,
257 &s->manager->polkit_registry,
258 error);
259 if (r < 0)
260 return r;
261 if (r == 0)
262 return 1; /* Will call us back */
263
264 r = session_send_lock(s, /* lock= */ strstr(sd_bus_message_get_member(message), "Lock"));
265 if (r == -ENOTTY)
266 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Session does not support lock screen.");
267 if (r < 0)
268 return r;
269
270 return sd_bus_reply_method_return(message, NULL);
271}
272
273static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
274 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
275 Session *s = ASSERT_PTR(userdata);
276 uid_t uid;
277 int r, b;
278
279 assert(message);
280
281 r = sd_bus_message_read(message, "b", &b);
282 if (r < 0)
283 return r;
284
285 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
286 if (r < 0)
287 return r;
288
289 r = sd_bus_creds_get_euid(creds, &uid);
290 if (r < 0)
291 return r;
292
293 if (uid != 0 && uid != s->user->user_record->uid)
294 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
295
296 r = session_set_idle_hint(s, b);
297 if (r == -ENOTTY)
298 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Idle hint control is not supported on non-graphical and non-user sessions.");
299 if (r < 0)
300 return r;
301
302 return sd_bus_reply_method_return(message, NULL);
303}
304
305static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
306 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
307 Session *s = ASSERT_PTR(userdata);
308 uid_t uid;
309 int r, b;
310
311 assert(message);
312
313 r = sd_bus_message_read(message, "b", &b);
314 if (r < 0)
315 return r;
316
317 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
318 if (r < 0)
319 return r;
320
321 r = sd_bus_creds_get_euid(creds, &uid);
322 if (r < 0)
323 return r;
324
325 if (uid != 0 && uid != s->user->user_record->uid)
326 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
327
328 r = session_set_locked_hint(s, b);
329 if (r == -ENOTTY)
330 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Session does not support lock screen.");
331 if (r < 0)
332 return r;
333
334 return sd_bus_reply_method_return(message, NULL);
335}
336
337int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
338 Session *s = ASSERT_PTR(userdata);
339 const char *swhom;
340 int32_t signo;
341 KillWhom whom;
342 int r;
343
344 assert(message);
345
346 r = sd_bus_message_read(message, "si", &swhom, &signo);
347 if (r < 0)
348 return r;
349
350 if (isempty(swhom))
351 whom = KILL_ALL;
352 else {
353 whom = kill_whom_from_string(swhom);
354 if (whom < 0)
355 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swhom);
356 }
357
358 if (!SIGNAL_VALID(signo))
359 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
360
361 r = bus_verify_polkit_async_full(
362 message,
363 "org.freedesktop.login1.manage",
364 /* details= */ NULL,
365 s->user->user_record->uid,
366 /* flags= */ 0,
367 &s->manager->polkit_registry,
368 error);
369 if (r < 0)
370 return r;
371 if (r == 0)
372 return 1; /* Will call us back */
373
374 r = session_kill(s, whom, signo, error);
375 if (r < 0)
376 return r;
377
378 return sd_bus_reply_method_return(message, NULL);
379}
380
381static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
382 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
383 Session *s = ASSERT_PTR(userdata);
384 int r, force;
385 uid_t uid;
386
387 assert(message);
388
389 r = sd_bus_message_read(message, "b", &force);
390 if (r < 0)
391 return r;
392
393 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
394 if (r < 0)
395 return r;
396
397 r = sd_bus_creds_get_euid(creds, &uid);
398 if (r < 0)
399 return r;
400
401 if (uid != 0 && (force || uid != s->user->user_record->uid))
402 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
403
404 r = session_set_controller(s, sd_bus_message_get_sender(message), force, true);
405 if (r < 0)
406 return r;
407
408 return sd_bus_reply_method_return(message, NULL);
409}
410
411static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
412 Session *s = ASSERT_PTR(userdata);
413
414 assert(message);
415
416 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
417 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
418
419 session_drop_controller(s);
420
421 return sd_bus_reply_method_return(message, NULL);
422}
423
424static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error *error) {
425 Session *s = ASSERT_PTR(userdata);
426 const char *t;
427 SessionType type;
428 int r;
429
430 assert(message);
431
432 r = sd_bus_message_read(message, "s", &t);
433 if (r < 0)
434 return r;
435
436 type = session_type_from_string(t);
437 if (type < 0)
438 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
439 "Invalid session type '%s'", t);
440
441 if (!SESSION_CLASS_CAN_CHANGE_TYPE(s->class))
442 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Session class doesn't support changing type.");
443
444 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
445 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
446
447 session_set_type(s, type);
448
449 return sd_bus_reply_method_return(message, NULL);
450}
451
452static int method_set_class(sd_bus_message *message, void *userdata, sd_bus_error *error) {
453 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
454 Session *s = ASSERT_PTR(userdata);
455 SessionClass class;
456 const char *c;
457 uid_t uid;
458 int r;
459
460 assert(message);
461
462 r = sd_bus_message_read(message, "s", &c);
463 if (r < 0)
464 return r;
465
466 class = session_class_from_string(c);
467 if (class < 0)
468 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
469 "Invalid session class '%s'", c);
470
471 /* For now, we'll allow only upgrades user-incomplete → user */
472 if (class != SESSION_USER)
473 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
474 "Class may only be set to 'user'");
475
476 if (s->class == SESSION_USER) /* No change, shortcut */
477 return sd_bus_reply_method_return(message, NULL);
478 if (s->class != SESSION_USER_INCOMPLETE)
479 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
480 "Only sessions with class 'user-incomplete' may change class");
481
482 if (s->upgrade_message)
483 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
484 "Set session class operation already in progress");
485
486 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
487 if (r < 0)
488 return r;
489
490 r = sd_bus_creds_get_euid(creds, &uid);
491 if (r < 0)
492 return r;
493
494 if (uid != 0 && uid != s->user->user_record->uid)
495 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change its class");
496
497 session_set_class(s, class);
498
499 s->upgrade_message = sd_bus_message_ref(message);
500
501 r = session_send_upgrade_reply(s, /* error= */ NULL);
502 if (r < 0)
503 return r;
504
505 return 1;
506}
507
508static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_error *error) {
509 Session *s = ASSERT_PTR(userdata);
510 const char *display;
511 int r;
512
513 assert(message);
514
515 r = sd_bus_message_read(message, "s", &display);
516 if (r < 0)
517 return r;
518
519 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
520 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set display");
521
522 if (!SESSION_TYPE_IS_GRAPHICAL(s->type))
523 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Setting display is only supported for graphical sessions");
524
525 r = session_set_display(s, display);
526 if (r < 0)
527 return r;
528
529 return sd_bus_reply_method_return(message, NULL);
530}
531
532static int method_set_tty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
533 Session *s = ASSERT_PTR(userdata);
534 int fd, r, flags;
535 _cleanup_free_ char *q = NULL;
536
537 assert(message);
538
539 r = sd_bus_message_read(message, "h", &fd);
540 if (r < 0)
541 return r;
542
543 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
544 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set tty");
545
546 assert(fd >= 0);
547
548 flags = fcntl(fd, F_GETFL, 0);
549 if (flags < 0)
550 return -errno;
551 if ((flags & O_ACCMODE_STRICT) != O_RDWR)
552 return -EACCES;
553 if (FLAGS_SET(flags, O_PATH))
554 return -ENOTTY;
555
556 r = getttyname_malloc(fd, &q);
557 if (r < 0)
558 return r;
559
560 r = session_set_tty(s, q);
561 if (r < 0)
562 return r;
563
564 return sd_bus_reply_method_return(message, NULL);
565}
566
567static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
568 Session *s = ASSERT_PTR(userdata);
569 uint32_t major, minor;
570 _cleanup_(session_device_freep) SessionDevice *sd = NULL;
571 dev_t dev;
572 int r;
573
574 assert(message);
575
576 r = sd_bus_message_read(message, "uu", &major, &minor);
577 if (r < 0)
578 return r;
579
580 if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
581 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
582
583 if (!SESSION_CLASS_CAN_TAKE_DEVICE(s->class))
584 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Session class doesn't support taking device control.");
585
586 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
587 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
588
589 dev = makedev(major, minor);
590 sd = hashmap_get(s->devices, &dev);
591 if (sd)
592 /* We don't allow retrieving a device multiple times.
593 * The related ReleaseDevice call is not ref-counted.
594 * The caller should use dup() if it requires more
595 * than one fd (it would be functionally
596 * equivalent). */
597 return sd_bus_error_set(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
598
599 r = session_device_new(s, dev, true, &sd);
600 if (r < 0)
601 return r;
602
603 r = session_device_save(sd);
604 if (r < 0)
605 return r;
606
607 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
608 if (r < 0)
609 return r;
610
611 session_save(s);
612 TAKE_PTR(sd);
613
614 return 1;
615}
616
617static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
618 Session *s = ASSERT_PTR(userdata);
619 uint32_t major, minor;
620 SessionDevice *sd;
621 dev_t dev;
622 int r;
623
624 assert(message);
625
626 r = sd_bus_message_read(message, "uu", &major, &minor);
627 if (r < 0)
628 return r;
629
630 if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
631 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
632
633 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
634 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
635
636 dev = makedev(major, minor);
637 sd = hashmap_get(s->devices, &dev);
638 if (!sd)
639 return sd_bus_error_set(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
640
641 session_device_free(sd);
642 session_save(s);
643
644 return sd_bus_reply_method_return(message, NULL);
645}
646
647static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
648 Session *s = ASSERT_PTR(userdata);
649 uint32_t major, minor;
650 SessionDevice *sd;
651 dev_t dev;
652 int r;
653
654 assert(message);
655
656 r = sd_bus_message_read(message, "uu", &major, &minor);
657 if (r < 0)
658 return r;
659
660 if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
661 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
662
663 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
664 return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
665
666 dev = makedev(major, minor);
667 sd = hashmap_get(s->devices, &dev);
668 if (!sd)
669 return sd_bus_error_set(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
670
671 session_device_complete_pause(sd);
672
673 return sd_bus_reply_method_return(message, NULL);
674}
675
676static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus_error *error) {
677 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
678 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
679 const char *subsystem, *name, *seat;
680 Session *s = ASSERT_PTR(userdata);
681 uint32_t brightness;
682 uid_t uid;
683 int r;
684
685 assert(message);
686
687 r = sd_bus_message_read(message, "ssu", &subsystem, &name, &brightness);
688 if (r < 0)
689 return r;
690
691 if (!STR_IN_SET(subsystem, "backlight", "leds"))
692 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Subsystem type %s not supported, must be one of 'backlight' or 'leds'.", subsystem);
693 if (!filename_is_valid(name))
694 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not a valid device name %s, refusing.", name);
695
696 if (!s->seat)
697 return sd_bus_error_set(error, BUS_ERROR_NOT_YOUR_DEVICE, "Your session has no seat, refusing.");
698 if (s->seat->active != s)
699 return sd_bus_error_set(error, BUS_ERROR_NOT_YOUR_DEVICE, "Session is not in foreground, refusing.");
700
701 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
702 if (r < 0)
703 return r;
704
705 r = sd_bus_creds_get_euid(creds, &uid);
706 if (r < 0)
707 return r;
708
709 if (uid != 0 && uid != s->user->user_record->uid)
710 return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change brightness.");
711
712 r = sd_device_new_from_subsystem_sysname(&d, subsystem, name);
713 if (r < 0)
714 return sd_bus_error_set_errnof(error, r, "Failed to open device %s:%s: %m", subsystem, name);
715
716 r = device_get_seat(d, &seat);
717 if (r < 0)
718 return sd_bus_error_set_errnof(error, r, "Failed to get seat of %s:%s: %m", subsystem, name);
719 if (!streq(seat, s->seat->id))
720 return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Device %s:%s does not belong to your seat %s, refusing.", subsystem, name, s->seat->id);
721
722 r = manager_write_brightness(s->manager, d, brightness, message);
723 if (r < 0)
724 return r;
725
726 return 1;
727}
728
729static int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
730 _cleanup_free_ char *e = NULL;
731 sd_bus_message *message;
732 Manager *m = ASSERT_PTR(userdata);
733 Session *session;
734 const char *p;
735 int r;
736
737 assert(bus);
738 assert(path);
739 assert(interface);
740 assert(found);
741
742 p = startswith(path, "/org/freedesktop/login1/session/");
743 if (!p)
744 return 0;
745
746 e = bus_label_unescape(p);
747 if (!e)
748 return -ENOMEM;
749
750 message = sd_bus_get_current_message(bus);
751
752 r = manager_get_session_from_creds(m, message, e, error, &session);
753 if (r == -ENXIO) {
754 sd_bus_error_free(error);
755 return 0;
756 }
757 if (r < 0)
758 return r;
759
760 *found = session;
761 return 1;
762}
763
764char* session_bus_path(Session *s) {
765 _cleanup_free_ char *t = NULL;
766
767 assert(s);
768
769 t = bus_label_escape(s->id);
770 if (!t)
771 return NULL;
772
773 return strjoin("/org/freedesktop/login1/session/", t);
774}
775
776static int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
777 _cleanup_strv_free_ char **l = NULL;
778 sd_bus_message *message;
779 Manager *m = userdata;
780 Session *session;
781 int r;
782
783 assert(bus);
784 assert(path);
785 assert(nodes);
786
787 HASHMAP_FOREACH(session, m->sessions) {
788 char *p;
789
790 p = session_bus_path(session);
791 if (!p)
792 return -ENOMEM;
793
794 r = strv_consume(&l, p);
795 if (r < 0)
796 return r;
797 }
798
799 message = sd_bus_get_current_message(bus);
800 if (message) {
801 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
802
803 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
804 if (r >= 0) {
805 bool may_auto = false;
806 const char *name;
807
808 r = sd_bus_creds_get_session(creds, &name);
809 if (r >= 0) {
810 session = hashmap_get(m->sessions, name);
811 if (session) {
812 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
813 if (r < 0)
814 return r;
815
816 may_auto = true;
817 }
818 }
819
820 if (!may_auto) {
821 uid_t uid;
822
823 r = sd_bus_creds_get_owner_uid(creds, &uid);
824 if (r >= 0) {
825 User *user;
826
827 user = hashmap_get(m->users, UID_TO_PTR(uid));
828 may_auto = user && user->display;
829 }
830 }
831
832 if (may_auto) {
833 r = strv_extend(&l, "/org/freedesktop/login1/session/auto");
834 if (r < 0)
835 return r;
836 }
837 }
838 }
839
840 *nodes = TAKE_PTR(l);
841 return 1;
842}
843
844int session_send_signal(Session *s, bool new_session) {
845 _cleanup_free_ char *p = NULL;
846
847 assert(s);
848
849 p = session_bus_path(s);
850 if (!p)
851 return -ENOMEM;
852
853 return sd_bus_emit_signal(
854 s->manager->bus,
855 "/org/freedesktop/login1",
856 "org.freedesktop.login1.Manager",
857 new_session ? "SessionNew" : "SessionRemoved",
858 "so", s->id, p);
859}
860
861int session_send_changed_strv(Session *s, char **properties) {
862 _cleanup_free_ char *p = NULL;
863
864 assert(s);
865
866 if (!s->started)
867 return 0;
868
869 p = session_bus_path(s);
870 if (!p)
871 return -ENOMEM;
872
873 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", properties);
874}
875
876int session_send_lock(Session *s, bool lock) {
877 _cleanup_free_ char *p = NULL;
878
879 assert(s);
880
881 if (!SESSION_CLASS_CAN_LOCK(s->class))
882 return -ENOTTY;
883
884 p = session_bus_path(s);
885 if (!p)
886 return -ENOMEM;
887
888 return sd_bus_emit_signal(
889 s->manager->bus,
890 p,
891 "org.freedesktop.login1.Session",
892 lock ? "Lock" : "Unlock",
893 NULL);
894}
895
896int session_send_lock_all(Manager *m, bool lock) {
897 Session *session;
898 int r = 0;
899
900 assert(m);
901
902 HASHMAP_FOREACH(session, m->sessions) {
903
904 if (!SESSION_CLASS_CAN_LOCK(session->class))
905 continue;
906
907 RET_GATHER(r, session_send_lock(session, lock));
908 }
909
910 return r;
911}
912
913int session_send_create_reply_bus(Session *s, const sd_bus_error *error) {
914 assert(s);
915
916 /* This is called after the session scope and the user service were successfully created, and
917 * finishes where manager_create_session() left off. */
918
919 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = TAKE_PTR(s->create_message);
920 if (!c)
921 return 0;
922
923 if (sd_bus_error_is_set(error))
924 return sd_bus_reply_method_error(c, error);
925
926 /* Prior to v258, logind tracked sessions by installing a fifo in client and subscribe to its EOF.
927 * Now we can fully rely on pidfd for this, but still need to return *something* to the client.
928 * Allocate something lightweight and isolated as placeholder. */
929 _cleanup_close_ int fd = eventfd(0, EFD_CLOEXEC);
930 if (fd < 0)
931 return -errno;
932
933 _cleanup_free_ char *p = session_bus_path(s);
934 if (!p)
935 return -ENOMEM;
936
937 log_debug("Sending D-Bus reply about created session: "
938 "id=%s object_path=%s uid=" UID_FMT " runtime_path=%s seat=%s vtnr=%u",
939 s->id,
940 p,
941 s->user->user_record->uid,
942 s->user->runtime_path,
943 s->seat ? s->seat->id : "",
944 s->vtnr);
945
946 return sd_bus_reply_method_return(
947 c, "soshusub",
948 s->id,
949 p,
950 s->user->runtime_path,
951 fd, /* not really used - see comments above */
952 (uint32_t) s->user->user_record->uid,
953 s->seat ? s->seat->id : "",
954 (uint32_t) s->vtnr,
955 false);
956}
957
958int session_send_upgrade_reply(Session *s, const sd_bus_error *error) {
959 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
960 assert(s);
961
962 if (!s->upgrade_message)
963 return 0;
964
965 /* See comments in session_send_create_reply */
966 if (!sd_bus_error_is_set(error) && session_job_pending(s))
967 return 0;
968
969 c = TAKE_PTR(s->upgrade_message);
970 if (error)
971 return sd_bus_reply_method_error(c, error);
972
973 session_save(s);
974
975 return sd_bus_reply_method_return(c, NULL);
976}
977
978static const sd_bus_vtable session_vtable[] = {
979 SD_BUS_VTABLE_START(0),
980
981 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
982 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
983 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
984 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
985 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
986 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
987 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
988 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
989 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
990 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
991 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
992 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
993 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
994 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
995 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
996 SD_BUS_PROPERTY("LeaderPIDFDId", "t", bus_property_get_pidfdid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
997 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
998 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
999 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1000 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1001 SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1002 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1003 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1004 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1005 SD_BUS_PROPERTY("CanIdle", "b", property_get_can_idle, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1006 SD_BUS_PROPERTY("CanLock", "b", property_get_can_lock, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1007 SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1008
1009 SD_BUS_METHOD("Terminate",
1010 NULL,
1011 NULL,
1012 bus_session_method_terminate,
1013 SD_BUS_VTABLE_UNPRIVILEGED),
1014 SD_BUS_METHOD("Activate",
1015 NULL,
1016 NULL,
1017 bus_session_method_activate,
1018 SD_BUS_VTABLE_UNPRIVILEGED),
1019 SD_BUS_METHOD("Lock",
1020 NULL,
1021 NULL,
1022 bus_session_method_lock,
1023 SD_BUS_VTABLE_UNPRIVILEGED),
1024 SD_BUS_METHOD("Unlock",
1025 NULL,
1026 NULL,
1027 bus_session_method_lock,
1028 SD_BUS_VTABLE_UNPRIVILEGED),
1029 SD_BUS_METHOD_WITH_ARGS("SetIdleHint",
1030 SD_BUS_ARGS("b", idle),
1031 SD_BUS_NO_RESULT,
1032 method_set_idle_hint,
1033 SD_BUS_VTABLE_UNPRIVILEGED),
1034 SD_BUS_METHOD_WITH_ARGS("SetLockedHint",
1035 SD_BUS_ARGS("b", locked),
1036 SD_BUS_NO_RESULT,
1037 method_set_locked_hint,
1038 SD_BUS_VTABLE_UNPRIVILEGED),
1039 SD_BUS_METHOD_WITH_ARGS("Kill",
1040 SD_BUS_ARGS("s", whom, "i", signal_number),
1041 SD_BUS_NO_RESULT,
1042 bus_session_method_kill,
1043 SD_BUS_VTABLE_UNPRIVILEGED),
1044 SD_BUS_METHOD_WITH_ARGS("TakeControl",
1045 SD_BUS_ARGS("b", force),
1046 SD_BUS_NO_RESULT,
1047 method_take_control,
1048 SD_BUS_VTABLE_UNPRIVILEGED),
1049 SD_BUS_METHOD("ReleaseControl",
1050 NULL,
1051 NULL,
1052 method_release_control,
1053 SD_BUS_VTABLE_UNPRIVILEGED),
1054 SD_BUS_METHOD_WITH_ARGS("SetType",
1055 SD_BUS_ARGS("s", type),
1056 SD_BUS_NO_RESULT,
1057 method_set_type,
1058 SD_BUS_VTABLE_UNPRIVILEGED),
1059 SD_BUS_METHOD_WITH_ARGS("SetClass",
1060 SD_BUS_ARGS("s", class),
1061 SD_BUS_NO_RESULT,
1062 method_set_class,
1063 SD_BUS_VTABLE_UNPRIVILEGED),
1064 SD_BUS_METHOD_WITH_ARGS("SetDisplay",
1065 SD_BUS_ARGS("s", display),
1066 SD_BUS_NO_RESULT,
1067 method_set_display,
1068 SD_BUS_VTABLE_UNPRIVILEGED),
1069 SD_BUS_METHOD_WITH_ARGS("SetTTY",
1070 SD_BUS_ARGS("h", tty_fd),
1071 SD_BUS_NO_RESULT,
1072 method_set_tty,
1073 SD_BUS_VTABLE_UNPRIVILEGED),
1074 SD_BUS_METHOD_WITH_ARGS("TakeDevice",
1075 SD_BUS_ARGS("u", major, "u", minor),
1076 SD_BUS_RESULT("h", fd, "b", inactive),
1077 method_take_device,
1078 SD_BUS_VTABLE_UNPRIVILEGED),
1079 SD_BUS_METHOD_WITH_ARGS("ReleaseDevice",
1080 SD_BUS_ARGS("u", major, "u", minor),
1081 SD_BUS_NO_RESULT,
1082 method_release_device,
1083 SD_BUS_VTABLE_UNPRIVILEGED),
1084 SD_BUS_METHOD_WITH_ARGS("PauseDeviceComplete",
1085 SD_BUS_ARGS("u", major, "u", minor),
1086 SD_BUS_NO_RESULT,
1087 method_pause_device_complete,
1088 SD_BUS_VTABLE_UNPRIVILEGED),
1089 SD_BUS_METHOD_WITH_ARGS("SetBrightness",
1090 SD_BUS_ARGS("s", subsystem, "s", name, "u", brightness),
1091 SD_BUS_NO_RESULT,
1092 method_set_brightness,
1093 SD_BUS_VTABLE_UNPRIVILEGED),
1094
1095 SD_BUS_SIGNAL_WITH_ARGS("PauseDevice",
1096 SD_BUS_ARGS("u", major, "u", minor, "s", type),
1097 0),
1098 SD_BUS_SIGNAL_WITH_ARGS("ResumeDevice",
1099 SD_BUS_ARGS("u", major, "u", minor, "h", fd),
1100 0),
1101 SD_BUS_SIGNAL("Lock", NULL, 0),
1102 SD_BUS_SIGNAL("Unlock", NULL, 0),
1103
1104 SD_BUS_VTABLE_END
1105};
1106
1107const BusObjectImplementation session_object = {
1108 "/org/freedesktop/login1/session",
1109 "org.freedesktop.login1.Session",
1110 .fallback_vtables = BUS_FALLBACK_VTABLES({session_vtable, session_object_find}),
1111 .node_enumerator = session_node_enumerator,
1112};