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
property_get_unix_record(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)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
property_get_state(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)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
bus_home_client_is_trusted(Home * h,sd_bus_message * message)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
bus_home_get_record_json(Home * h,sd_bus_message * message,char ** ret,bool * ret_incomplete)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|USER_RECORD_PERMISSIVE;
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
property_get_user_record(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)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
bus_home_method_activate(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_deactivate(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_unregister(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_realize(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_remove(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_fixate(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_authenticate(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_update_record(Home * h,sd_bus_message * message,UserRecord * hr,sd_bus_error * error)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
bus_home_method_update(sd_bus_message * message,void * userdata,sd_bus_error * error)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|USER_RECORD_PERMISSIVE, &hr, error);
447 if (r < 0)
448 return r;
449
450 return bus_home_method_update_record(h, message, hr, error);
451 }
452
bus_home_method_resize(sd_bus_message * message,void * userdata,sd_bus_error * error)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, /* automatic= */ false, 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
bus_home_method_change_password(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_lock(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_unlock(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_acquire(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_ref(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_method_release(sd_bus_message * message,void * userdata,sd_bus_error * error)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
bus_home_path(Home * h,char ** ret)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
bus_home_object_find(sd_bus * bus,const char * path,const char * interface,void * userdata,void ** found,sd_bus_error * error)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
bus_home_node_enumerator(sd_bus * bus,const char * path,void * userdata,char *** nodes,sd_bus_error * error)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 Home *h;
762 int r;
763
764 assert(nodes);
765
766 l = new0(char*, hashmap_size(m->homes_by_uid) + 1);
767 if (!l)
768 return -ENOMEM;
769
770 HASHMAP_FOREACH(h, m->homes_by_uid) {
771 r = bus_home_path(h, l + k);
772 if (r < 0)
773 return r;
774 }
775
776 *nodes = TAKE_PTR(l);
777 return 1;
778 }
779
780 const sd_bus_vtable home_vtable[] = {
781 SD_BUS_VTABLE_START(0),
782
783 SD_BUS_PROPERTY("UserName", "s",
784 NULL, offsetof(Home, user_name),
785 SD_BUS_VTABLE_PROPERTY_CONST),
786 SD_BUS_PROPERTY("UID", "u",
787 NULL, offsetof(Home, uid),
788 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
789 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
790 property_get_unix_record, 0,
791 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
792 SD_BUS_PROPERTY("State", "s",
793 property_get_state, 0,
794 0),
795 SD_BUS_PROPERTY("UserRecord", "(sb)",
796 property_get_user_record, 0,
797 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
798
799 SD_BUS_METHOD_WITH_ARGS("Activate",
800 SD_BUS_ARGS("s", secret),
801 SD_BUS_NO_RESULT,
802 bus_home_method_activate,
803 SD_BUS_VTABLE_SENSITIVE),
804 SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
805 SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
806 SD_BUS_METHOD_WITH_ARGS("Realize",
807 SD_BUS_ARGS("s", secret),
808 SD_BUS_NO_RESULT,
809 bus_home_method_realize,
810 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
811
812 SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
813 SD_BUS_METHOD_WITH_ARGS("Fixate",
814 SD_BUS_ARGS("s", secret),
815 SD_BUS_NO_RESULT,
816 bus_home_method_fixate,
817 SD_BUS_VTABLE_SENSITIVE),
818 SD_BUS_METHOD_WITH_ARGS("Authenticate",
819 SD_BUS_ARGS("s", secret),
820 SD_BUS_NO_RESULT,
821 bus_home_method_authenticate,
822 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
823 SD_BUS_METHOD_WITH_ARGS("Update",
824 SD_BUS_ARGS("s", user_record),
825 SD_BUS_NO_RESULT,
826 bus_home_method_update,
827 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
828 SD_BUS_METHOD_WITH_ARGS("Resize",
829 SD_BUS_ARGS("t", size, "s", secret),
830 SD_BUS_NO_RESULT,
831 bus_home_method_resize,
832 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
833 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
834 SD_BUS_ARGS("s", new_secret, "s", old_secret),
835 SD_BUS_NO_RESULT,
836 bus_home_method_change_password,
837 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
838 SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
839 SD_BUS_METHOD_WITH_ARGS("Unlock",
840 SD_BUS_ARGS("s", secret),
841 SD_BUS_NO_RESULT,
842 bus_home_method_unlock,
843 SD_BUS_VTABLE_SENSITIVE),
844 SD_BUS_METHOD_WITH_ARGS("Acquire",
845 SD_BUS_ARGS("s", secret, "b", please_suspend),
846 SD_BUS_RESULT("h", send_fd),
847 bus_home_method_acquire,
848 SD_BUS_VTABLE_SENSITIVE),
849 SD_BUS_METHOD_WITH_ARGS("Ref",
850 SD_BUS_ARGS("b", please_suspend),
851 SD_BUS_RESULT("h", send_fd),
852 bus_home_method_ref,
853 0),
854 SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
855 SD_BUS_VTABLE_END
856 };
857
858 const BusObjectImplementation home_object = {
859 "/org/freedesktop/home1/home",
860 "org.freedesktop.home1.Home",
861 .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
862 .node_enumerator = bus_home_node_enumerator,
863 .manager = true,
864 };
865
on_deferred_change(sd_event_source * s,void * userdata)866 static int on_deferred_change(sd_event_source *s, void *userdata) {
867 _cleanup_free_ char *path = NULL;
868 Home *h = userdata;
869 int r;
870
871 assert(h);
872
873 h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source);
874
875 r = bus_home_path(h, &path);
876 if (r < 0) {
877 log_warning_errno(r, "Failed to generate home bus path, ignoring: %m");
878 return 0;
879 }
880
881 if (h->announced)
882 r = sd_bus_emit_properties_changed_strv(h->manager->bus, path, "org.freedesktop.home1.Home", NULL);
883 else
884 r = sd_bus_emit_object_added(h->manager->bus, path);
885 if (r < 0)
886 log_warning_errno(r, "Failed to send home change event, ignoring: %m");
887 else
888 h->announced = true;
889
890 return 0;
891 }
892
bus_home_emit_change(Home * h)893 int bus_home_emit_change(Home *h) {
894 int r;
895
896 assert(h);
897
898 if (h->deferred_change_event_source)
899 return 1;
900
901 if (!h->manager->event)
902 return 0;
903
904 if (IN_SET(sd_event_get_state(h->manager->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
905 return 0;
906
907 r = sd_event_add_defer(h->manager->event, &h->deferred_change_event_source, on_deferred_change, h);
908 if (r < 0)
909 return log_error_errno(r, "Failed to allocate deferred change event source: %m");
910
911 r = sd_event_source_set_priority(h->deferred_change_event_source, SD_EVENT_PRIORITY_IDLE+5);
912 if (r < 0)
913 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
914
915 (void) sd_event_source_set_description(h->deferred_change_event_source, "deferred-change-event");
916 return 1;
917 }
918
bus_home_emit_remove(Home * h)919 int bus_home_emit_remove(Home *h) {
920 _cleanup_free_ char *path = NULL;
921 int r;
922
923 assert(h);
924
925 if (!h->announced)
926 return 0;
927
928 if (!h->manager)
929 return 0;
930
931 if (!h->manager->bus)
932 return 0;
933
934 r = bus_home_path(h, &path);
935 if (r < 0)
936 return r;
937
938 r = sd_bus_emit_object_removed(h->manager->bus, path);
939 if (r < 0)
940 return r;
941
942 h->announced = false;
943 return 1;
944 }
945