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