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