]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/home/homed-home-bus.c
homed: add bus call that allows referencing a home without activating it
[thirdparty/systemd.git] / src / home / homed-home-bus.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
70a5db58
LP
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
15static 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
99534007 24 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
25
26 assert(bus);
27 assert(reply);
70a5db58
LP
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
39static 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
99534007 48 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
49
50 assert(bus);
51 assert(reply);
70a5db58
LP
52
53 return sd_bus_message_append(reply, "s", home_state_to_string(home_get_state(h)));
54}
55
56int 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
77int 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
bfc0cc1a 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;
70a5db58
LP
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
116static 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;
99534007 126 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
127 bool incomplete;
128 int r;
129
130 assert(bus);
131 assert(reply);
70a5db58
LP
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
140int 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;
99534007 146 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
147 int r;
148
149 assert(message);
70a5db58
LP
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
170int bus_home_method_deactivate(
171 sd_bus_message *message,
172 void *userdata,
173 sd_bus_error *error) {
174
99534007 175 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
176 int r;
177
178 assert(message);
70a5db58
LP
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
194int bus_home_method_unregister(
195 sd_bus_message *message,
196 void *userdata,
197 sd_bus_error *error) {
198
99534007 199 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
200 int r;
201
202 assert(message);
70a5db58
LP
203
204 r = bus_verify_polkit_async(
205 message,
70a5db58 206 "org.freedesktop.home1.remove-home",
7b36fb9f 207 /* details= */ NULL,
70a5db58
LP
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
226int 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;
99534007 232 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
233 int r;
234
235 assert(message);
70a5db58
LP
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,
70a5db58 243 "org.freedesktop.home1.create-home",
7b36fb9f 244 /* details= */ NULL,
70a5db58
LP
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
268int bus_home_method_remove(
269 sd_bus_message *message,
270 void *userdata,
271 sd_bus_error *error) {
272
99534007 273 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
274 int r;
275
276 assert(message);
70a5db58
LP
277
278 r = bus_verify_polkit_async(
279 message,
70a5db58 280 "org.freedesktop.home1.remove-home",
7b36fb9f 281 /* details= */ NULL,
70a5db58
LP
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
304int 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;
99534007 310 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
311 int r;
312
313 assert(message);
70a5db58
LP
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
333int 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;
99534007 339 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
340 int r;
341
342 assert(message);
70a5db58
LP
343
344 r = bus_message_read_secret(message, &secret, error);
345 if (r < 0)
346 return r;
347
7b36fb9f 348 r = bus_verify_polkit_async_full(
70a5db58 349 message,
70a5db58 350 "org.freedesktop.home1.authenticate-home",
7b36fb9f
LP
351 /* details= */ NULL,
352 /* interactive= */ false,
70a5db58
LP
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
375int 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,
70a5db58 388 "org.freedesktop.home1.update-home",
7b36fb9f 389 /* details= */ NULL,
70a5db58
LP
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
411int 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;
99534007 417 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
418 int r;
419
420 assert(message);
70a5db58 421
bfc0cc1a 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);
70a5db58
LP
423 if (r < 0)
424 return r;
425
426 return bus_home_method_update_record(h, message, hr, error);
427}
428
429int 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;
99534007 435 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
436 uint64_t sz;
437 int r;
438
439 assert(message);
70a5db58
LP
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,
70a5db58 451 "org.freedesktop.home1.resize-home",
7b36fb9f 452 /* details= */ NULL,
70a5db58
LP
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
d357b80d 460 r = home_resize(h, sz, secret, /* automatic= */ false, error);
70a5db58
LP
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
474int 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;
99534007 480 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
481 int r;
482
483 assert(message);
70a5db58
LP
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
7b36fb9f 493 r = bus_verify_polkit_async_full(
70a5db58 494 message,
70a5db58 495 "org.freedesktop.home1.passwd-home",
7b36fb9f
LP
496 /* details= */ NULL,
497 /* interactive= */ false,
70a5db58
LP
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
520int bus_home_method_lock(
521 sd_bus_message *message,
522 void *userdata,
523 sd_bus_error *error) {
524
99534007 525 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
526 int r;
527
528 assert(message);
70a5db58
LP
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
546int 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;
99534007 552 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
553 int r;
554
555 assert(message);
70a5db58
LP
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
576int 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;
254d1313 583 _cleanup_close_ int fd = -EBADF;
70a5db58 584 int r, please_suspend;
99534007 585 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
586
587 assert(message);
70a5db58
LP
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 */
691b9916 598 fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
70a5db58 599 if (fd < 0)
80ace4f2 600 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
70a5db58
LP
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
616int bus_home_method_ref(
617 sd_bus_message *message,
618 void *userdata,
619 sd_bus_error *error) {
620
254d1313 621 _cleanup_close_ int fd = -EBADF;
99534007 622 Home *h = ASSERT_PTR(userdata);
70a5db58 623 int please_suspend, r;
508d344e 624 bool unrestricted;
70a5db58
LP
625
626 assert(message);
70a5db58 627
508d344e
LP
628 /* In unrestricted mode we'll add a reference to the home even if it's not active */
629 unrestricted = strstr(sd_bus_message_get_member(message), "Unrestricted");
630
70a5db58
LP
631 r = sd_bus_message_read(message, "b", &please_suspend);
632 if (r < 0)
633 return r;
634
508d344e
LP
635 if (!unrestricted) {
636 HomeState state;
70a5db58 637
508d344e
LP
638 state = home_get_state(h);
639
640 switch (state) {
641 case HOME_ABSENT:
642 return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
643 case HOME_UNFIXATED:
644 case HOME_INACTIVE:
645 case HOME_DIRTY:
646 return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
647 case HOME_LOCKED:
648 return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
649 default:
650 if (HOME_STATE_IS_ACTIVE(state))
651 break;
652
653 return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
654 }
70a5db58
LP
655 }
656
691b9916 657 fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
70a5db58 658 if (fd < 0)
80ace4f2 659 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
70a5db58
LP
660
661 return sd_bus_reply_method_return(message, "h", fd);
662}
663
664int bus_home_method_release(
665 sd_bus_message *message,
666 void *userdata,
667 sd_bus_error *error) {
668
669 _cleanup_(operation_unrefp) Operation *o = NULL;
99534007 670 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
671 int r;
672
673 assert(message);
70a5db58
LP
674
675 o = operation_new(OPERATION_RELEASE, message);
676 if (!o)
677 return -ENOMEM;
678
679 r = home_schedule_operation(h, o, error);
680 if (r < 0)
681 return r;
682
683 return 1;
684}
685
691b9916
AV
686int bus_home_method_inhibit_suspend(
687 sd_bus_message *message,
688 void *userdata,
689 sd_bus_error *error) {
690
691 _cleanup_close_ int fd = -EBADF;
692 Home *h = ASSERT_PTR(userdata);
693 HomeState state;
694 int r;
695
696 r = bus_verify_polkit_async_full(
697 message,
698 "org.freedesktop.home1.inhibit-suspend",
699 /* details= */ NULL,
700 /* interactive= */ false,
701 h->uid,
702 &h->manager->polkit_registry,
703 error);
704 if (r < 0)
705 return r;
706 if (r == 0)
707 return 1; /* Will call us back */
708
709 state = home_get_state(h);
710 switch (state) {
711 case HOME_ABSENT:
712 return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
713 case HOME_UNFIXATED:
714 case HOME_INACTIVE:
715 case HOME_DIRTY:
716 return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
717 case HOME_LOCKED:
718 return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
719 default:
720 if (HOME_STATE_IS_ACTIVE(state))
721 break;
722
723 return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
724 }
725
726 fd = home_create_fifo(h, HOME_FIFO_INHIBIT_SUSPEND);
727 if (fd < 0)
728 return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
729
730 return sd_bus_reply_method_return(message, "h", fd);
731}
732
70a5db58
LP
733/* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
734assert_cc(sizeof(uid_t) == sizeof(uint32_t));
735
70a5db58
LP
736int bus_home_path(Home *h, char **ret) {
737 assert(ret);
738
739 return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret);
740}
741
cfd508a9 742static int bus_home_object_find(
70a5db58
LP
743 sd_bus *bus,
744 const char *path,
745 const char *interface,
746 void *userdata,
747 void **found,
748 sd_bus_error *error) {
749
750 _cleanup_free_ char *e = NULL;
751 Manager *m = userdata;
752 uid_t uid;
753 Home *h;
754 int r;
755
756 r = sd_bus_path_decode(path, "/org/freedesktop/home1/home", &e);
757 if (r <= 0)
758 return 0;
759
760 if (parse_uid(e, &uid) >= 0)
761 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
762 else
763 h = hashmap_get(m->homes_by_name, e);
764 if (!h)
765 return 0;
766
767 *found = h;
768 return 1;
769}
770
cfd508a9 771static int bus_home_node_enumerator(
70a5db58
LP
772 sd_bus *bus,
773 const char *path,
774 void *userdata,
775 char ***nodes,
776 sd_bus_error *error) {
777
778 _cleanup_strv_free_ char **l = NULL;
779 Manager *m = userdata;
780 size_t k = 0;
70a5db58
LP
781 Home *h;
782 int r;
783
784 assert(nodes);
785
786 l = new0(char*, hashmap_size(m->homes_by_uid) + 1);
787 if (!l)
788 return -ENOMEM;
789
90e74a66 790 HASHMAP_FOREACH(h, m->homes_by_uid) {
70a5db58
LP
791 r = bus_home_path(h, l + k);
792 if (r < 0)
793 return r;
52023622
YW
794
795 k++;
70a5db58
LP
796 }
797
798 *nodes = TAKE_PTR(l);
799 return 1;
800}
801
cfd508a9
ZJS
802const sd_bus_vtable home_vtable[] = {
803 SD_BUS_VTABLE_START(0),
804
805 SD_BUS_PROPERTY("UserName", "s",
806 NULL, offsetof(Home, user_name),
807 SD_BUS_VTABLE_PROPERTY_CONST),
808 SD_BUS_PROPERTY("UID", "u",
809 NULL, offsetof(Home, uid),
810 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
811 SD_BUS_PROPERTY("UnixRecord", "(suusss)",
812 property_get_unix_record, 0,
813 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
814 SD_BUS_PROPERTY("State", "s",
815 property_get_state, 0,
816 0),
817 SD_BUS_PROPERTY("UserRecord", "(sb)",
818 property_get_user_record, 0,
819 SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
820
9a814166
NK
821 SD_BUS_METHOD_WITH_ARGS("Activate",
822 SD_BUS_ARGS("s", secret),
823 SD_BUS_NO_RESULT,
824 bus_home_method_activate,
825 SD_BUS_VTABLE_SENSITIVE),
cfd508a9
ZJS
826 SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
827 SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
9a814166
NK
828 SD_BUS_METHOD_WITH_ARGS("Realize",
829 SD_BUS_ARGS("s", secret),
830 SD_BUS_NO_RESULT,
831 bus_home_method_realize,
832 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
cfd508a9
ZJS
833
834 SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
9a814166
NK
835 SD_BUS_METHOD_WITH_ARGS("Fixate",
836 SD_BUS_ARGS("s", secret),
837 SD_BUS_NO_RESULT,
838 bus_home_method_fixate,
839 SD_BUS_VTABLE_SENSITIVE),
840 SD_BUS_METHOD_WITH_ARGS("Authenticate",
841 SD_BUS_ARGS("s", secret),
842 SD_BUS_NO_RESULT,
843 bus_home_method_authenticate,
844 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
845 SD_BUS_METHOD_WITH_ARGS("Update",
846 SD_BUS_ARGS("s", user_record),
847 SD_BUS_NO_RESULT,
848 bus_home_method_update,
849 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
850 SD_BUS_METHOD_WITH_ARGS("Resize",
851 SD_BUS_ARGS("t", size, "s", secret),
852 SD_BUS_NO_RESULT,
853 bus_home_method_resize,
854 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
855 SD_BUS_METHOD_WITH_ARGS("ChangePassword",
856 SD_BUS_ARGS("s", new_secret, "s", old_secret),
857 SD_BUS_NO_RESULT,
858 bus_home_method_change_password,
859 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
cfd508a9 860 SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
9a814166
NK
861 SD_BUS_METHOD_WITH_ARGS("Unlock",
862 SD_BUS_ARGS("s", secret),
863 SD_BUS_NO_RESULT,
864 bus_home_method_unlock,
865 SD_BUS_VTABLE_SENSITIVE),
866 SD_BUS_METHOD_WITH_ARGS("Acquire",
867 SD_BUS_ARGS("s", secret, "b", please_suspend),
868 SD_BUS_RESULT("h", send_fd),
869 bus_home_method_acquire,
870 SD_BUS_VTABLE_SENSITIVE),
871 SD_BUS_METHOD_WITH_ARGS("Ref",
872 SD_BUS_ARGS("b", please_suspend),
873 SD_BUS_RESULT("h", send_fd),
508d344e
LP
874 bus_home_method_ref,
875 0),
876 SD_BUS_METHOD_WITH_ARGS("RefUnrestricted",
877 SD_BUS_ARGS("b", please_suspend),
878 SD_BUS_RESULT("h", send_fd),
9a814166
NK
879 bus_home_method_ref,
880 0),
cfd508a9 881 SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
691b9916
AV
882 SD_BUS_METHOD_WITH_ARGS("InhibitSuspend",
883 SD_BUS_NO_ARGS,
884 SD_BUS_RESULT("h", send_fd),
885 bus_home_method_inhibit_suspend,
886 SD_BUS_VTABLE_UNPRIVILEGED),
cfd508a9
ZJS
887 SD_BUS_VTABLE_END
888};
889
890const BusObjectImplementation home_object = {
891 "/org/freedesktop/home1/home",
892 "org.freedesktop.home1.Home",
893 .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
894 .node_enumerator = bus_home_node_enumerator,
895 .manager = true,
896};
897
70a5db58
LP
898static int on_deferred_change(sd_event_source *s, void *userdata) {
899 _cleanup_free_ char *path = NULL;
99534007 900 Home *h = ASSERT_PTR(userdata);
70a5db58
LP
901 int r;
902
cf536638 903 h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source);
70a5db58
LP
904
905 r = bus_home_path(h, &path);
906 if (r < 0) {
907 log_warning_errno(r, "Failed to generate home bus path, ignoring: %m");
908 return 0;
909 }
910
911 if (h->announced)
912 r = sd_bus_emit_properties_changed_strv(h->manager->bus, path, "org.freedesktop.home1.Home", NULL);
913 else
914 r = sd_bus_emit_object_added(h->manager->bus, path);
915 if (r < 0)
916 log_warning_errno(r, "Failed to send home change event, ignoring: %m");
917 else
918 h->announced = true;
919
920 return 0;
921}
922
923int bus_home_emit_change(Home *h) {
924 int r;
925
926 assert(h);
927
928 if (h->deferred_change_event_source)
929 return 1;
930
931 if (!h->manager->event)
932 return 0;
933
934 if (IN_SET(sd_event_get_state(h->manager->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
935 return 0;
936
937 r = sd_event_add_defer(h->manager->event, &h->deferred_change_event_source, on_deferred_change, h);
938 if (r < 0)
939 return log_error_errno(r, "Failed to allocate deferred change event source: %m");
940
941 r = sd_event_source_set_priority(h->deferred_change_event_source, SD_EVENT_PRIORITY_IDLE+5);
942 if (r < 0)
943 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
944
945 (void) sd_event_source_set_description(h->deferred_change_event_source, "deferred-change-event");
946 return 1;
947}
948
949int bus_home_emit_remove(Home *h) {
950 _cleanup_free_ char *path = NULL;
951 int r;
952
953 assert(h);
954
955 if (!h->announced)
956 return 0;
957
2ff45772
YW
958 if (!h->manager)
959 return 0;
960
961 if (!h->manager->bus)
962 return 0;
963
70a5db58
LP
964 r = bus_home_path(h, &path);
965 if (r < 0)
966 return r;
967
968 r = sd_bus_emit_object_removed(h->manager->bus, path);
969 if (r < 0)
970 return r;
971
972 h->announced = false;
973 return 1;
974}