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