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