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