]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homed-home-bus.c
Merge pull request #16821 from cgzones/selinux_status
[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 case HOME_DIRTY:
673 return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
674 case HOME_LOCKED:
675 return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
676 default:
677 if (HOME_STATE_IS_ACTIVE(state))
678 break;
679
680 return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
681 }
682
683 fd = home_create_fifo(h, please_suspend);
684 if (fd < 0)
685 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
686
687 return sd_bus_reply_method_return(message, "h", fd);
688 }
689
690 int bus_home_method_release(
691 sd_bus_message *message,
692 void *userdata,
693 sd_bus_error *error) {
694
695 _cleanup_(operation_unrefp) Operation *o = NULL;
696 Home *h = userdata;
697 int r;
698
699 assert(message);
700 assert(h);
701
702 o = operation_new(OPERATION_RELEASE, message);
703 if (!o)
704 return -ENOMEM;
705
706 r = home_schedule_operation(h, o, error);
707 if (r < 0)
708 return r;
709
710 return 1;
711 }
712
713 /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
714 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
715
716 int bus_home_path(Home *h, char **ret) {
717 assert(ret);
718
719 return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret);
720 }
721
722 static int bus_home_object_find(
723 sd_bus *bus,
724 const char *path,
725 const char *interface,
726 void *userdata,
727 void **found,
728 sd_bus_error *error) {
729
730 _cleanup_free_ char *e = NULL;
731 Manager *m = userdata;
732 uid_t uid;
733 Home *h;
734 int r;
735
736 r = sd_bus_path_decode(path, "/org/freedesktop/home1/home", &e);
737 if (r <= 0)
738 return 0;
739
740 if (parse_uid(e, &uid) >= 0)
741 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
742 else
743 h = hashmap_get(m->homes_by_name, e);
744 if (!h)
745 return 0;
746
747 *found = h;
748 return 1;
749 }
750
751 static int bus_home_node_enumerator(
752 sd_bus *bus,
753 const char *path,
754 void *userdata,
755 char ***nodes,
756 sd_bus_error *error) {
757
758 _cleanup_strv_free_ char **l = NULL;
759 Manager *m = userdata;
760 size_t k = 0;
761 Iterator i;
762 Home *h;
763 int r;
764
765 assert(nodes);
766
767 l = new0(char*, hashmap_size(m->homes_by_uid) + 1);
768 if (!l)
769 return -ENOMEM;
770
771 HASHMAP_FOREACH(h, m->homes_by_uid, i) {
772 r = bus_home_path(h, l + k);
773 if (r < 0)
774 return r;
775 }
776
777 *nodes = TAKE_PTR(l);
778 return 1;
779 }
780
781 const sd_bus_vtable home_vtable[] = {
782 SD_BUS_VTABLE_START(0),
783
784 SD_BUS_PROPERTY("UserName", "s",
785 NULL, offsetof(Home, user_name),
786 SD_BUS_VTABLE_PROPERTY_CONST),
787 SD_BUS_PROPERTY("UID", "u",
788 NULL, offsetof(Home, uid),
789 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
790 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
791 property_get_unix_record, 0,
792 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
793 SD_BUS_PROPERTY("State", "s",
794 property_get_state, 0,
795 0),
796 SD_BUS_PROPERTY("UserRecord", "(sb)",
797 property_get_user_record, 0,
798 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
799
800 SD_BUS_METHOD_WITH_NAMES("Activate",
801 "s",
802 SD_BUS_PARAM(secret),
803 NULL,,
804 bus_home_method_activate,
805 SD_BUS_VTABLE_SENSITIVE),
806 SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
807 SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
808 SD_BUS_METHOD_WITH_NAMES("Realize",
809 "s",
810 SD_BUS_PARAM(secret),
811 NULL,,
812 bus_home_method_realize,
813 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
814
815 SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
816 SD_BUS_METHOD_WITH_NAMES("Fixate",
817 "s",
818 SD_BUS_PARAM(secret),
819 NULL,,
820 bus_home_method_fixate,
821 SD_BUS_VTABLE_SENSITIVE),
822 SD_BUS_METHOD_WITH_NAMES("Authenticate",
823 "s",
824 SD_BUS_PARAM(secret),
825 NULL,,
826 bus_home_method_authenticate,
827 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
828 SD_BUS_METHOD_WITH_NAMES("Update",
829 "s",
830 SD_BUS_PARAM(user_record),
831 NULL,,
832 bus_home_method_update,
833 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
834 SD_BUS_METHOD_WITH_NAMES("Resize",
835 "ts",
836 SD_BUS_PARAM(size)
837 SD_BUS_PARAM(secret),
838 NULL,,
839 bus_home_method_resize,
840 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
841 SD_BUS_METHOD_WITH_NAMES("ChangePassword",
842 "ss",
843 SD_BUS_PARAM(new_secret)
844 SD_BUS_PARAM(old_secret),
845 NULL,,
846 bus_home_method_change_password,
847 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
848 SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
849 SD_BUS_METHOD_WITH_NAMES("Unlock",
850 "s",
851 SD_BUS_PARAM(secret),
852 NULL,,
853 bus_home_method_unlock,
854 SD_BUS_VTABLE_SENSITIVE),
855 SD_BUS_METHOD_WITH_NAMES("Acquire",
856 "sb",
857 SD_BUS_PARAM(secret)
858 SD_BUS_PARAM(please_suspend),
859 "h",
860 SD_BUS_PARAM(send_fd),
861 bus_home_method_acquire,
862 SD_BUS_VTABLE_SENSITIVE),
863 SD_BUS_METHOD_WITH_NAMES("Ref",
864 "b",
865 SD_BUS_PARAM(please_suspend),
866 "h",
867 SD_BUS_PARAM(send_fd),
868 bus_home_method_ref,
869 0),
870 SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
871 SD_BUS_VTABLE_END
872 };
873
874 const BusObjectImplementation home_object = {
875 "/org/freedesktop/home1/home",
876 "org.freedesktop.home1.Home",
877 .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
878 .node_enumerator = bus_home_node_enumerator,
879 .manager = true,
880 };
881
882 static int on_deferred_change(sd_event_source *s, void *userdata) {
883 _cleanup_free_ char *path = NULL;
884 Home *h = userdata;
885 int r;
886
887 assert(h);
888
889 h->deferred_change_event_source = sd_event_source_unref(h->deferred_change_event_source);
890
891 r = bus_home_path(h, &path);
892 if (r < 0) {
893 log_warning_errno(r, "Failed to generate home bus path, ignoring: %m");
894 return 0;
895 }
896
897 if (h->announced)
898 r = sd_bus_emit_properties_changed_strv(h->manager->bus, path, "org.freedesktop.home1.Home", NULL);
899 else
900 r = sd_bus_emit_object_added(h->manager->bus, path);
901 if (r < 0)
902 log_warning_errno(r, "Failed to send home change event, ignoring: %m");
903 else
904 h->announced = true;
905
906 return 0;
907 }
908
909 int bus_home_emit_change(Home *h) {
910 int r;
911
912 assert(h);
913
914 if (h->deferred_change_event_source)
915 return 1;
916
917 if (!h->manager->event)
918 return 0;
919
920 if (IN_SET(sd_event_get_state(h->manager->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
921 return 0;
922
923 r = sd_event_add_defer(h->manager->event, &h->deferred_change_event_source, on_deferred_change, h);
924 if (r < 0)
925 return log_error_errno(r, "Failed to allocate deferred change event source: %m");
926
927 r = sd_event_source_set_priority(h->deferred_change_event_source, SD_EVENT_PRIORITY_IDLE+5);
928 if (r < 0)
929 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
930
931 (void) sd_event_source_set_description(h->deferred_change_event_source, "deferred-change-event");
932 return 1;
933 }
934
935 int bus_home_emit_remove(Home *h) {
936 _cleanup_free_ char *path = NULL;
937 int r;
938
939 assert(h);
940
941 if (!h->announced)
942 return 0;
943
944 r = bus_home_path(h, &path);
945 if (r < 0)
946 return r;
947
948 r = sd_bus_emit_object_removed(h->manager->bus, path);
949 if (r < 0)
950 return r;
951
952 h->announced = false;
953 return 1;
954 }