]> git.ipfire.org Git - thirdparty/systemd.git/blob - 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
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/capability.h>
4
5 #include "bus-common-errors.h"
6 #include "bus-polkit.h"
7 #include "fd-util.h"
8 #include "format-util.h"
9 #include "home-util.h"
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
17 static 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
26 Home *h = ASSERT_PTR(userdata);
27
28 assert(bus);
29 assert(reply);
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
41 static 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
50 Home *h = ASSERT_PTR(userdata);
51
52 assert(bus);
53 assert(reply);
54
55 return sd_bus_message_append(reply, "s", home_state_to_string(home_get_state(h)));
56 }
57
58 int 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
79 static 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,
101 good_uid,
102 /* flags= */ 0,
103 &h->manager->polkit_registry,
104 error);
105 }
106
107 int 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
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;
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
146 static 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;
156 Home *h = ASSERT_PTR(userdata);
157 bool incomplete;
158 int r;
159
160 assert(bus);
161 assert(reply);
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
170 int 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;
176 Home *h = ASSERT_PTR(userdata);
177 bool if_referenced;
178 int r;
179
180 assert(message);
181
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,
188 h->uid,
189 /* flags= */ 0,
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
197 r = bus_message_read_secret(message, &secret, error);
198 if (r < 0)
199 return r;
200
201 r = home_activate(h, if_referenced, secret, error);
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
216 int bus_home_method_deactivate(
217 sd_bus_message *message,
218 void *userdata,
219 sd_bus_error *error) {
220
221 Home *h = ASSERT_PTR(userdata);
222 int r;
223
224 assert(message);
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
240 int bus_home_method_unregister(
241 sd_bus_message *message,
242 void *userdata,
243 sd_bus_error *error) {
244
245 Home *h = ASSERT_PTR(userdata);
246 int r;
247
248 assert(message);
249
250 r = home_verify_polkit_async(
251 h,
252 message,
253 "org.freedesktop.home1.remove-home",
254 UID_INVALID,
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
272 int 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;
278 Home *h = ASSERT_PTR(userdata);
279 int r;
280
281 assert(message);
282
283 r = bus_message_read_secret(message, &secret, error);
284 if (r < 0)
285 return r;
286
287 r = home_verify_polkit_async(
288 h,
289 message,
290 "org.freedesktop.home1.create-home",
291 UID_INVALID,
292 error);
293 if (r < 0)
294 return r;
295 if (r == 0)
296 return 1; /* Will call us back */
297
298 r = home_create(h, secret, NULL, 0, error);
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
314 int bus_home_method_remove(
315 sd_bus_message *message,
316 void *userdata,
317 sd_bus_error *error) {
318
319 Home *h = ASSERT_PTR(userdata);
320 int r;
321
322 assert(message);
323
324 r = home_verify_polkit_async(
325 h,
326 message,
327 "org.freedesktop.home1.remove-home",
328 UID_INVALID,
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
350 int 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;
356 Home *h = ASSERT_PTR(userdata);
357 int r;
358
359 assert(message);
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
379 int 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;
385 Home *h = ASSERT_PTR(userdata);
386 int r;
387
388 assert(message);
389
390 r = bus_message_read_secret(message, &secret, error);
391 if (r < 0)
392 return r;
393
394 r = home_verify_polkit_async(
395 h,
396 message,
397 "org.freedesktop.home1.authenticate-home",
398 h->uid,
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
419 int bus_home_update_record(
420 Home *h,
421 sd_bus_message *message,
422 UserRecord *hr,
423 Hashmap *blobs,
424 uint64_t flags,
425 sd_bus_error *error) {
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
436 if ((flags & ~SD_HOMED_UPDATE_FLAGS_ALL) != 0)
437 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
438
439 r = home_verify_polkit_async(
440 h,
441 message,
442 "org.freedesktop.home1.update-home",
443 UID_INVALID,
444 error);
445 if (r < 0)
446 return r;
447 if (r == 0)
448 return 1; /* Will call us back */
449
450 r = home_update(h, hr, blobs, flags, error);
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
461 h->current_operation->call_flags = flags;
462
463 return 1;
464 }
465
466 int 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;
472 _cleanup_hashmap_free_ Hashmap *blobs = NULL;
473 uint64_t flags = 0;
474 Home *h = ASSERT_PTR(userdata);
475 int r;
476
477 assert(message);
478
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);
480 if (r < 0)
481 return r;
482
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
493 return bus_home_update_record(h, message, hr, blobs, flags, error);
494 }
495
496 int 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;
502 Home *h = ASSERT_PTR(userdata);
503 uint64_t sz;
504 int r;
505
506 assert(message);
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
516 r = home_verify_polkit_async(
517 h,
518 message,
519 "org.freedesktop.home1.resize-home",
520 UID_INVALID,
521 error);
522 if (r < 0)
523 return r;
524 if (r == 0)
525 return 1; /* Will call us back */
526
527 r = home_resize(h, sz, secret, error);
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
541 int 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;
547 Home *h = ASSERT_PTR(userdata);
548 int r;
549
550 assert(message);
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
560 r = home_verify_polkit_async(
561 h,
562 message,
563 "org.freedesktop.home1.passwd-home",
564 h->uid,
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
585 int bus_home_method_lock(
586 sd_bus_message *message,
587 void *userdata,
588 sd_bus_error *error) {
589
590 Home *h = ASSERT_PTR(userdata);
591 int r;
592
593 assert(message);
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
611 int 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;
617 Home *h = ASSERT_PTR(userdata);
618 int r;
619
620 assert(message);
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
641 int 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;
648 _cleanup_close_ int fd = -EBADF;
649 int r, please_suspend;
650 Home *h = ASSERT_PTR(userdata);
651
652 assert(message);
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 */
663 fd = home_create_fifo(h, please_suspend);
664 if (fd < 0)
665 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
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
681 int bus_home_method_ref(
682 sd_bus_message *message,
683 void *userdata,
684 sd_bus_error *error) {
685
686 _cleanup_close_ int fd = -EBADF;
687 Home *h = ASSERT_PTR(userdata);
688 int please_suspend, r;
689 bool unrestricted;
690
691 assert(message);
692
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
696 r = sd_bus_message_read(message, "b", &please_suspend);
697 if (r < 0)
698 return r;
699
700 if (!unrestricted) {
701 HomeState state;
702
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 }
720 }
721
722 fd = home_create_fifo(h, please_suspend);
723 if (fd < 0)
724 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
725
726 return sd_bus_reply_method_return(message, "h", fd);
727 }
728
729 int 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;
735 Home *h = ASSERT_PTR(userdata);
736 int r;
737
738 assert(message);
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. */
752 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
753
754 int 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
760 static int bus_home_object_find(
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
789 static int bus_home_node_enumerator(
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;
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
808 HASHMAP_FOREACH(h, m->homes_by_uid) {
809 r = bus_home_path(h, l + k);
810 if (r < 0)
811 return r;
812
813 k++;
814 }
815
816 *nodes = TAKE_PTR(l);
817 return 1;
818 }
819
820 const 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
839 SD_BUS_METHOD_WITH_ARGS("Activate",
840 SD_BUS_ARGS("s", secret),
841 SD_BUS_NO_RESULT,
842 bus_home_method_activate,
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),
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),
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),
856
857 SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
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),
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),
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),
888 SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
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),
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),
907 bus_home_method_ref,
908 0),
909 SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
910 SD_BUS_VTABLE_END
911 };
912
913 const 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
921 static int on_deferred_change(sd_event_source *s, void *userdata) {
922 _cleanup_free_ char *path = NULL;
923 Home *h = ASSERT_PTR(userdata);
924 int r;
925
926 h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source);
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
946 int 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
972 int 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
981 if (!h->manager)
982 return 0;
983
984 if (!h->manager->bus)
985 return 0;
986
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 }