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