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