]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/home/homed-home-bus.c
Merge pull request #31899 from yuwata/sd-journal-add-match
[thirdparty/systemd.git] / src / home / homed-home-bus.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
70a5db58
LP
2
3#include <linux/capability.h>
4
5#include "bus-common-errors.h"
6#include "bus-polkit.h"
7#include "fd-util.h"
058a84d1 8#include "format-util.h"
d94c7eef 9#include "home-util.h"
70a5db58
LP
10#include "homed-bus.h"
11#include "homed-home-bus.h"
12#include "homed-home.h"
13#include "strv.h"
14#include "user-record-util.h"
15#include "user-util.h"
16
17static int property_get_unix_record(
18 sd_bus *bus,
19 const char *path,
20 const char *interface,
21 const char *property,
22 sd_bus_message *reply,
23 void *userdata,
24 sd_bus_error *error) {
25
99534007 26 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
27
28 assert(bus);
29 assert(reply);
70a5db58
LP
30
31 return sd_bus_message_append(
32 reply, "(suusss)",
33 h->user_name,
34 (uint32_t) h->uid,
35 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
36 h->record ? user_record_real_name(h->record) : NULL,
37 h->record ? user_record_home_directory(h->record) : NULL,
38 h->record ? user_record_shell(h->record) : NULL);
39}
40
41static int property_get_state(
42 sd_bus *bus,
43 const char *path,
44 const char *interface,
45 const char *property,
46 sd_bus_message *reply,
47 void *userdata,
48 sd_bus_error *error) {
49
99534007 50 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
51
52 assert(bus);
53 assert(reply);
70a5db58
LP
54
55 return sd_bus_message_append(reply, "s", home_state_to_string(home_get_state(h)));
56}
57
58int bus_home_client_is_trusted(Home *h, sd_bus_message *message) {
59 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
60 uid_t euid;
61 int r;
62
63 assert(h);
64
65 if (!message)
66 return -EINVAL;
67
68 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
69 if (r < 0)
70 return r;
71
72 r = sd_bus_creds_get_euid(creds, &euid);
73 if (r < 0)
74 return r;
75
76 return euid == 0 || h->uid == euid;
77}
78
058a84d1
AV
79static int home_verify_polkit_async(
80 Home *h,
81 sd_bus_message *message,
82 const char *action,
83 uid_t good_uid,
84 sd_bus_error *error) {
85
86 assert(h);
87 assert(message);
88 assert(action);
89 assert(error);
90
91 const char *details[] = {
92 "uid", FORMAT_UID(h->uid),
93 "username", h->user_name,
94 NULL
95 };
96
97 return bus_verify_polkit_async_full(
98 message,
99 action,
100 details,
058a84d1 101 good_uid,
29556b75 102 /* flags= */ 0,
058a84d1
AV
103 &h->manager->polkit_registry,
104 error);
105}
106
70a5db58
LP
107int bus_home_get_record_json(
108 Home *h,
109 sd_bus_message *message,
110 char **ret,
111 bool *ret_incomplete) {
112
113 _cleanup_(user_record_unrefp) UserRecord *augmented = NULL;
114 UserRecordLoadFlags flags;
115 int r, trusted;
116
117 assert(h);
118 assert(ret);
119
120 trusted = bus_home_client_is_trusted(h, message);
121 if (trusted < 0) {
122 log_warning_errno(trusted, "Failed to determine whether client is trusted, assuming untrusted.");
123 trusted = false;
124 }
125
bfc0cc1a 126 flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
70a5db58
LP
127 if (trusted)
128 flags |= USER_RECORD_ALLOW_PRIVILEGED;
129 else
130 flags |= USER_RECORD_STRIP_PRIVILEGED;
131
132 r = home_augment_status(h, flags, &augmented);
133 if (r < 0)
134 return r;
135
136 r = json_variant_format(augmented->json, 0, ret);
137 if (r < 0)
138 return r;
139
140 if (ret_incomplete)
141 *ret_incomplete = augmented->incomplete;
142
143 return 0;
144}
145
146static int property_get_user_record(
147 sd_bus *bus,
148 const char *path,
149 const char *interface,
150 const char *property,
151 sd_bus_message *reply,
152 void *userdata,
153 sd_bus_error *error) {
154
155 _cleanup_free_ char *json = NULL;
99534007 156 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
157 bool incomplete;
158 int r;
159
160 assert(bus);
161 assert(reply);
70a5db58
LP
162
163 r = bus_home_get_record_json(h, sd_bus_get_current_message(bus), &json, &incomplete);
164 if (r < 0)
165 return r;
166
167 return sd_bus_message_append(reply, "(sb)", json, incomplete);
168}
169
170int bus_home_method_activate(
171 sd_bus_message *message,
172 void *userdata,
173 sd_bus_error *error) {
174
175 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 176 Home *h = ASSERT_PTR(userdata);
336b1f19 177 bool if_referenced;
70a5db58
LP
178 int r;
179
180 assert(message);
70a5db58 181
336b1f19
LP
182 if_referenced = endswith(sd_bus_message_get_member(message), "IfReferenced");
183
184 r = bus_verify_polkit_async_full(
185 message,
186 "org.freedesktop.home1.activate-home",
187 /* details= */ NULL,
336b1f19 188 h->uid,
29556b75 189 /* flags= */ 0,
336b1f19
LP
190 &h->manager->polkit_registry,
191 error);
192 if (r < 0)
193 return r;
194 if (r == 0)
195 return 1; /* Will call us back */
196
70a5db58
LP
197 r = bus_message_read_secret(message, &secret, error);
198 if (r < 0)
199 return r;
200
336b1f19 201 r = home_activate(h, if_referenced, secret, error);
70a5db58
LP
202 if (r < 0)
203 return r;
204
205 assert(r == 0);
206 assert(!h->current_operation);
207
208 /* The operation is now in process, keep track of this message so that we can later reply to it. */
209 r = home_set_current_message(h, message);
210 if (r < 0)
211 return r;
212
213 return 1;
214}
215
216int bus_home_method_deactivate(
217 sd_bus_message *message,
218 void *userdata,
219 sd_bus_error *error) {
220
99534007 221 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
222 int r;
223
224 assert(message);
70a5db58
LP
225
226 r = home_deactivate(h, false, error);
227 if (r < 0)
228 return r;
229
230 assert(r == 0);
231 assert(!h->current_operation);
232
233 r = home_set_current_message(h, message);
234 if (r < 0)
235 return r;
236
237 return 1;
238}
239
240int bus_home_method_unregister(
241 sd_bus_message *message,
242 void *userdata,
243 sd_bus_error *error) {
244
99534007 245 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
246 int r;
247
248 assert(message);
70a5db58 249
058a84d1
AV
250 r = home_verify_polkit_async(
251 h,
70a5db58 252 message,
70a5db58 253 "org.freedesktop.home1.remove-home",
058a84d1 254 UID_INVALID,
70a5db58
LP
255 error);
256 if (r < 0)
257 return r;
258 if (r == 0)
259 return 1; /* Will call us back */
260
261 r = home_unregister(h, error);
262 if (r < 0)
263 return r;
264
265 assert(r > 0);
266
267 /* Note that home_unregister() destroyed 'h' here, so no more accesses */
268
269 return sd_bus_reply_method_return(message, NULL);
270}
271
272int bus_home_method_realize(
273 sd_bus_message *message,
274 void *userdata,
275 sd_bus_error *error) {
276
277 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 278 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
279 int r;
280
281 assert(message);
70a5db58
LP
282
283 r = bus_message_read_secret(message, &secret, error);
284 if (r < 0)
285 return r;
286
058a84d1
AV
287 r = home_verify_polkit_async(
288 h,
70a5db58 289 message,
70a5db58 290 "org.freedesktop.home1.create-home",
058a84d1 291 UID_INVALID,
70a5db58
LP
292 error);
293 if (r < 0)
294 return r;
295 if (r == 0)
296 return 1; /* Will call us back */
297
a4d72746 298 r = home_create(h, secret, NULL, 0, error);
70a5db58
LP
299 if (r < 0)
300 return r;
301
302 assert(r == 0);
303 assert(!h->current_operation);
304
305 h->unregister_on_failure = false;
306
307 r = home_set_current_message(h, message);
308 if (r < 0)
309 return r;
310
311 return 1;
312}
313
314int bus_home_method_remove(
315 sd_bus_message *message,
316 void *userdata,
317 sd_bus_error *error) {
318
99534007 319 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
320 int r;
321
322 assert(message);
70a5db58 323
058a84d1
AV
324 r = home_verify_polkit_async(
325 h,
70a5db58 326 message,
70a5db58 327 "org.freedesktop.home1.remove-home",
058a84d1 328 UID_INVALID,
70a5db58
LP
329 error);
330 if (r < 0)
331 return r;
332 if (r == 0)
333 return 1; /* Will call us back */
334
335 r = home_remove(h, error);
336 if (r < 0)
337 return r;
338 if (r > 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */
339 return sd_bus_reply_method_return(message, NULL);
340
341 assert(!h->current_operation);
342
343 r = home_set_current_message(h, message);
344 if (r < 0)
345 return r;
346
347 return 1;
348}
349
350int bus_home_method_fixate(
351 sd_bus_message *message,
352 void *userdata,
353 sd_bus_error *error) {
354
355 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 356 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
357 int r;
358
359 assert(message);
70a5db58
LP
360
361 r = bus_message_read_secret(message, &secret, error);
362 if (r < 0)
363 return r;
364
365 r = home_fixate(h, secret, error);
366 if (r < 0)
367 return r;
368
369 assert(r == 0);
370 assert(!h->current_operation);
371
372 r = home_set_current_message(h, message);
373 if (r < 0)
374 return r;
375
376 return 1;
377}
378
379int bus_home_method_authenticate(
380 sd_bus_message *message,
381 void *userdata,
382 sd_bus_error *error) {
383
384 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 385 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
386 int r;
387
388 assert(message);
70a5db58
LP
389
390 r = bus_message_read_secret(message, &secret, error);
391 if (r < 0)
392 return r;
393
058a84d1
AV
394 r = home_verify_polkit_async(
395 h,
70a5db58 396 message,
70a5db58 397 "org.freedesktop.home1.authenticate-home",
70a5db58 398 h->uid,
70a5db58
LP
399 error);
400 if (r < 0)
401 return r;
402 if (r == 0)
403 return 1; /* Will call us back */
404
405 r = home_authenticate(h, secret, error);
406 if (r < 0)
407 return r;
408
409 assert(r == 0);
410 assert(!h->current_operation);
411
412 r = home_set_current_message(h, message);
413 if (r < 0)
414 return r;
415
416 return 1;
417}
418
7555fc91 419int bus_home_update_record(
a4d72746
AV
420 Home *h,
421 sd_bus_message *message,
422 UserRecord *hr,
423 Hashmap *blobs,
424 uint64_t flags,
425 sd_bus_error *error) {
70a5db58
LP
426 int r;
427
428 assert(h);
429 assert(message);
430 assert(hr);
431
432 r = user_record_is_supported(hr, error);
433 if (r < 0)
434 return r;
435
d94c7eef
AV
436 if ((flags & ~SD_HOMED_UPDATE_FLAGS_ALL) != 0)
437 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
a4d72746 438
058a84d1
AV
439 r = home_verify_polkit_async(
440 h,
70a5db58 441 message,
70a5db58 442 "org.freedesktop.home1.update-home",
058a84d1 443 UID_INVALID,
70a5db58
LP
444 error);
445 if (r < 0)
446 return r;
447 if (r == 0)
448 return 1; /* Will call us back */
449
a4d72746 450 r = home_update(h, hr, blobs, flags, error);
70a5db58
LP
451 if (r < 0)
452 return r;
453
454 assert(r == 0);
455 assert(!h->current_operation);
456
457 r = home_set_current_message(h, message);
458 if (r < 0)
459 return r;
460
d94c7eef
AV
461 h->current_operation->call_flags = flags;
462
70a5db58
LP
463 return 1;
464}
465
466int bus_home_method_update(
467 sd_bus_message *message,
468 void *userdata,
469 sd_bus_error *error) {
470
471 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
a4d72746
AV
472 _cleanup_hashmap_free_ Hashmap *blobs = NULL;
473 uint64_t flags = 0;
99534007 474 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
475 int r;
476
477 assert(message);
70a5db58 478
5ec87d57 479 r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
70a5db58
LP
480 if (r < 0)
481 return r;
482
a4d72746
AV
483 if (endswith(sd_bus_message_get_member(message), "Ex")) {
484 r = bus_message_read_blobs(message, &blobs, error);
485 if (r < 0)
486 return r;
487
488 r = sd_bus_message_read(message, "t", &flags);
489 if (r < 0)
490 return r;
491 }
492
7555fc91 493 return bus_home_update_record(h, message, hr, blobs, flags, error);
70a5db58
LP
494}
495
496int bus_home_method_resize(
497 sd_bus_message *message,
498 void *userdata,
499 sd_bus_error *error) {
500
501 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 502 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
503 uint64_t sz;
504 int r;
505
506 assert(message);
70a5db58
LP
507
508 r = sd_bus_message_read(message, "t", &sz);
509 if (r < 0)
510 return r;
511
512 r = bus_message_read_secret(message, &secret, error);
513 if (r < 0)
514 return r;
515
058a84d1
AV
516 r = home_verify_polkit_async(
517 h,
70a5db58 518 message,
70a5db58 519 "org.freedesktop.home1.resize-home",
058a84d1 520 UID_INVALID,
70a5db58
LP
521 error);
522 if (r < 0)
523 return r;
524 if (r == 0)
525 return 1; /* Will call us back */
526
5ec87d57 527 r = home_resize(h, sz, secret, error);
70a5db58
LP
528 if (r < 0)
529 return r;
530
531 assert(r == 0);
532 assert(!h->current_operation);
533
534 r = home_set_current_message(h, message);
535 if (r < 0)
536 return r;
537
538 return 1;
539}
540
541int bus_home_method_change_password(
542 sd_bus_message *message,
543 void *userdata,
544 sd_bus_error *error) {
545
546 _cleanup_(user_record_unrefp) UserRecord *new_secret = NULL, *old_secret = NULL;
99534007 547 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
548 int r;
549
550 assert(message);
70a5db58
LP
551
552 r = bus_message_read_secret(message, &new_secret, error);
553 if (r < 0)
554 return r;
555
556 r = bus_message_read_secret(message, &old_secret, error);
557 if (r < 0)
558 return r;
559
058a84d1
AV
560 r = home_verify_polkit_async(
561 h,
70a5db58 562 message,
70a5db58 563 "org.freedesktop.home1.passwd-home",
70a5db58 564 h->uid,
70a5db58
LP
565 error);
566 if (r < 0)
567 return r;
568 if (r == 0)
569 return 1; /* Will call us back */
570
571 r = home_passwd(h, new_secret, old_secret, error);
572 if (r < 0)
573 return r;
574
575 assert(r == 0);
576 assert(!h->current_operation);
577
578 r = home_set_current_message(h, message);
579 if (r < 0)
580 return r;
581
582 return 1;
583}
584
585int bus_home_method_lock(
586 sd_bus_message *message,
587 void *userdata,
588 sd_bus_error *error) {
589
99534007 590 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
591 int r;
592
593 assert(message);
70a5db58
LP
594
595 r = home_lock(h, error);
596 if (r < 0)
597 return r;
598 if (r > 0) /* Done */
599 return sd_bus_reply_method_return(message, NULL);
600
601 /* The operation is now in process, keep track of this message so that we can later reply to it. */
602 assert(!h->current_operation);
603
604 r = home_set_current_message(h, message);
605 if (r < 0)
606 return r;
607
608 return 1;
609}
610
611int bus_home_method_unlock(
612 sd_bus_message *message,
613 void *userdata,
614 sd_bus_error *error) {
615
616 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
99534007 617 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
618 int r;
619
620 assert(message);
70a5db58
LP
621
622 r = bus_message_read_secret(message, &secret, error);
623 if (r < 0)
624 return r;
625
626 r = home_unlock(h, secret, error);
627 if (r < 0)
628 return r;
629
630 assert(r == 0);
631 assert(!h->current_operation);
632
633 /* The operation is now in process, keep track of this message so that we can later reply to it. */
634 r = home_set_current_message(h, message);
635 if (r < 0)
636 return r;
637
638 return 1;
639}
640
641int bus_home_method_acquire(
642 sd_bus_message *message,
643 void *userdata,
644 sd_bus_error *error) {
645
646 _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
647 _cleanup_(operation_unrefp) Operation *o = NULL;
254d1313 648 _cleanup_close_ int fd = -EBADF;
70a5db58 649 int r, please_suspend;
99534007 650 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
651
652 assert(message);
70a5db58
LP
653
654 r = bus_message_read_secret(message, &secret, error);
655 if (r < 0)
656 return r;
657
658 r = sd_bus_message_read(message, "b", &please_suspend);
659 if (r < 0)
660 return r;
661
662 /* This operation might not be something we can executed immediately, hence queue it */
5d490208 663 fd = home_create_fifo(h, please_suspend);
70a5db58 664 if (fd < 0)
80ace4f2 665 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
70a5db58
LP
666
667 o = operation_new(OPERATION_ACQUIRE, message);
668 if (!o)
669 return -ENOMEM;
670
671 o->secret = TAKE_PTR(secret);
672 o->send_fd = TAKE_FD(fd);
673
674 r = home_schedule_operation(h, o, error);
675 if (r < 0)
676 return r;
677
678 return 1;
679}
680
681int bus_home_method_ref(
682 sd_bus_message *message,
683 void *userdata,
684 sd_bus_error *error) {
685
254d1313 686 _cleanup_close_ int fd = -EBADF;
99534007 687 Home *h = ASSERT_PTR(userdata);
70a5db58 688 int please_suspend, r;
508d344e 689 bool unrestricted;
70a5db58
LP
690
691 assert(message);
70a5db58 692
508d344e
LP
693 /* In unrestricted mode we'll add a reference to the home even if it's not active */
694 unrestricted = strstr(sd_bus_message_get_member(message), "Unrestricted");
695
70a5db58
LP
696 r = sd_bus_message_read(message, "b", &please_suspend);
697 if (r < 0)
698 return r;
699
508d344e
LP
700 if (!unrestricted) {
701 HomeState state;
70a5db58 702
508d344e
LP
703 state = home_get_state(h);
704
705 switch (state) {
706 case HOME_ABSENT:
707 return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
708 case HOME_UNFIXATED:
709 case HOME_INACTIVE:
710 case HOME_DIRTY:
711 return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
712 case HOME_LOCKED:
713 return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
714 default:
715 if (HOME_STATE_IS_ACTIVE(state))
716 break;
717
718 return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
719 }
70a5db58
LP
720 }
721
5d490208 722 fd = home_create_fifo(h, please_suspend);
70a5db58 723 if (fd < 0)
80ace4f2 724 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
70a5db58
LP
725
726 return sd_bus_reply_method_return(message, "h", fd);
727}
728
729int bus_home_method_release(
730 sd_bus_message *message,
731 void *userdata,
732 sd_bus_error *error) {
733
734 _cleanup_(operation_unrefp) Operation *o = NULL;
99534007 735 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
736 int r;
737
738 assert(message);
70a5db58
LP
739
740 o = operation_new(OPERATION_RELEASE, message);
741 if (!o)
742 return -ENOMEM;
743
744 r = home_schedule_operation(h, o, error);
745 if (r < 0)
746 return r;
747
748 return 1;
749}
750
751/* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
752assert_cc(sizeof(uid_t) == sizeof(uint32_t));
753
70a5db58
LP
754int bus_home_path(Home *h, char **ret) {
755 assert(ret);
756
757 return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret);
758}
759
cfd508a9 760static int bus_home_object_find(
70a5db58
LP
761 sd_bus *bus,
762 const char *path,
763 const char *interface,
764 void *userdata,
765 void **found,
766 sd_bus_error *error) {
767
768 _cleanup_free_ char *e = NULL;
769 Manager *m = userdata;
770 uid_t uid;
771 Home *h;
772 int r;
773
774 r = sd_bus_path_decode(path, "/org/freedesktop/home1/home", &e);
775 if (r <= 0)
776 return 0;
777
778 if (parse_uid(e, &uid) >= 0)
779 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
780 else
781 h = hashmap_get(m->homes_by_name, e);
782 if (!h)
783 return 0;
784
785 *found = h;
786 return 1;
787}
788
cfd508a9 789static int bus_home_node_enumerator(
70a5db58
LP
790 sd_bus *bus,
791 const char *path,
792 void *userdata,
793 char ***nodes,
794 sd_bus_error *error) {
795
796 _cleanup_strv_free_ char **l = NULL;
797 Manager *m = userdata;
798 size_t k = 0;
70a5db58
LP
799 Home *h;
800 int r;
801
802 assert(nodes);
803
804 l = new0(char*, hashmap_size(m->homes_by_uid) + 1);
805 if (!l)
806 return -ENOMEM;
807
90e74a66 808 HASHMAP_FOREACH(h, m->homes_by_uid) {
70a5db58
LP
809 r = bus_home_path(h, l + k);
810 if (r < 0)
811 return r;
52023622
YW
812
813 k++;
70a5db58
LP
814 }
815
816 *nodes = TAKE_PTR(l);
817 return 1;
818}
819
cfd508a9
ZJS
820const sd_bus_vtable home_vtable[] = {
821 SD_BUS_VTABLE_START(0),
822
823 SD_BUS_PROPERTY("UserName", "s",
824 NULL, offsetof(Home, user_name),
825 SD_BUS_VTABLE_PROPERTY_CONST),
826 SD_BUS_PROPERTY("UID", "u",
827 NULL, offsetof(Home, uid),
828 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
829 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
830 property_get_unix_record, 0,
831 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
832 SD_BUS_PROPERTY("State", "s",
833 property_get_state, 0,
834 0),
835 SD_BUS_PROPERTY("UserRecord", "(sb)",
836 property_get_user_record, 0,
837 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
838
9a814166
NK
839 SD_BUS_METHOD_WITH_ARGS("Activate",
840 SD_BUS_ARGS("s", secret),
841 SD_BUS_NO_RESULT,
842 bus_home_method_activate,
336b1f19
LP
843 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
844 SD_BUS_METHOD_WITH_ARGS("ActivateIfReferenced",
845 SD_BUS_ARGS("s", secret),
846 SD_BUS_NO_RESULT,
847 bus_home_method_activate,
848 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
cfd508a9
ZJS
849 SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
850 SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
9a814166
NK
851 SD_BUS_METHOD_WITH_ARGS("Realize",
852 SD_BUS_ARGS("s", secret),
853 SD_BUS_NO_RESULT,
854 bus_home_method_realize,
855 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
cfd508a9
ZJS
856
857 SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
9a814166
NK
858 SD_BUS_METHOD_WITH_ARGS("Fixate",
859 SD_BUS_ARGS("s", secret),
860 SD_BUS_NO_RESULT,
861 bus_home_method_fixate,
862 SD_BUS_VTABLE_SENSITIVE),
863 SD_BUS_METHOD_WITH_ARGS("Authenticate",
864 SD_BUS_ARGS("s", secret),
865 SD_BUS_NO_RESULT,
866 bus_home_method_authenticate,
867 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
868 SD_BUS_METHOD_WITH_ARGS("Update",
869 SD_BUS_ARGS("s", user_record),
870 SD_BUS_NO_RESULT,
871 bus_home_method_update,
872 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
a4d72746
AV
873 SD_BUS_METHOD_WITH_ARGS("UpdateEx",
874 SD_BUS_ARGS("s", user_record, "a{sh}", blobs, "t", flags),
875 SD_BUS_NO_RESULT,
876 bus_home_method_update,
877 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
9a814166
NK
878 SD_BUS_METHOD_WITH_ARGS("Resize",
879 SD_BUS_ARGS("t", size, "s", secret),
880 SD_BUS_NO_RESULT,
881 bus_home_method_resize,
882 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
883 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
884 SD_BUS_ARGS("s", new_secret, "s", old_secret),
885 SD_BUS_NO_RESULT,
886 bus_home_method_change_password,
887 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
cfd508a9 888 SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
9a814166
NK
889 SD_BUS_METHOD_WITH_ARGS("Unlock",
890 SD_BUS_ARGS("s", secret),
891 SD_BUS_NO_RESULT,
892 bus_home_method_unlock,
893 SD_BUS_VTABLE_SENSITIVE),
894 SD_BUS_METHOD_WITH_ARGS("Acquire",
895 SD_BUS_ARGS("s", secret, "b", please_suspend),
896 SD_BUS_RESULT("h", send_fd),
897 bus_home_method_acquire,
898 SD_BUS_VTABLE_SENSITIVE),
899 SD_BUS_METHOD_WITH_ARGS("Ref",
900 SD_BUS_ARGS("b", please_suspend),
901 SD_BUS_RESULT("h", send_fd),
508d344e
LP
902 bus_home_method_ref,
903 0),
904 SD_BUS_METHOD_WITH_ARGS("RefUnrestricted",
905 SD_BUS_ARGS("b", please_suspend),
906 SD_BUS_RESULT("h", send_fd),
9a814166
NK
907 bus_home_method_ref,
908 0),
cfd508a9
ZJS
909 SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
910 SD_BUS_VTABLE_END
911};
912
913const BusObjectImplementation home_object = {
914 "/org/freedesktop/home1/home",
915 "org.freedesktop.home1.Home",
916 .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
917 .node_enumerator = bus_home_node_enumerator,
918 .manager = true,
919};
920
70a5db58
LP
921static int on_deferred_change(sd_event_source *s, void *userdata) {
922 _cleanup_free_ char *path = NULL;
99534007 923 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
924 int r;
925
cf536638 926 h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source);
70a5db58
LP
927
928 r = bus_home_path(h, &path);
929 if (r < 0) {
930 log_warning_errno(r, "Failed to generate home bus path, ignoring: %m");
931 return 0;
932 }
933
934 if (h->announced)
935 r = sd_bus_emit_properties_changed_strv(h->manager->bus, path, "org.freedesktop.home1.Home", NULL);
936 else
937 r = sd_bus_emit_object_added(h->manager->bus, path);
938 if (r < 0)
939 log_warning_errno(r, "Failed to send home change event, ignoring: %m");
940 else
941 h->announced = true;
942
943 return 0;
944}
945
946int bus_home_emit_change(Home *h) {
947 int r;
948
949 assert(h);
950
951 if (h->deferred_change_event_source)
952 return 1;
953
954 if (!h->manager->event)
955 return 0;
956
957 if (IN_SET(sd_event_get_state(h->manager->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
958 return 0;
959
960 r = sd_event_add_defer(h->manager->event, &h->deferred_change_event_source, on_deferred_change, h);
961 if (r < 0)
962 return log_error_errno(r, "Failed to allocate deferred change event source: %m");
963
964 r = sd_event_source_set_priority(h->deferred_change_event_source, SD_EVENT_PRIORITY_IDLE+5);
965 if (r < 0)
966 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
967
968 (void) sd_event_source_set_description(h->deferred_change_event_source, "deferred-change-event");
969 return 1;
970}
971
972int bus_home_emit_remove(Home *h) {
973 _cleanup_free_ char *path = NULL;
974 int r;
975
976 assert(h);
977
978 if (!h->announced)
979 return 0;
980
2ff45772
YW
981 if (!h->manager)
982 return 0;
983
984 if (!h->manager->bus)
985 return 0;
986
70a5db58
LP
987 r = bus_home_path(h, &path);
988 if (r < 0)
989 return r;
990
991 r = sd_bus_emit_object_removed(h->manager->bus, path);
992 if (r < 0)
993 return r;
994
995 h->announced = false;
996 return 1;
997}