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