]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homed-manager-bus.c
homed: explicitly deactivate all home directories on shutdown
[thirdparty/systemd.git] / src / home / homed-manager-bus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <linux/capability.h>
4
5 #include "alloc-util.h"
6 #include "bus-common-errors.h"
7 #include "bus-polkit.h"
8 #include "format-util.h"
9 #include "homed-bus.h"
10 #include "homed-home-bus.h"
11 #include "homed-manager-bus.h"
12 #include "homed-manager.h"
13 #include "strv.h"
14 #include "user-record-sign.h"
15 #include "user-record-util.h"
16 #include "user-util.h"
17
18 static int property_get_auto_login(
19 sd_bus *bus,
20 const char *path,
21 const char *interface,
22 const char *property,
23 sd_bus_message *reply,
24 void *userdata,
25 sd_bus_error *error) {
26
27 Manager *m = userdata;
28 Home *h;
29 int r;
30
31 assert(bus);
32 assert(reply);
33 assert(m);
34
35 r = sd_bus_message_open_container(reply, 'a', "(sso)");
36 if (r < 0)
37 return r;
38
39 HASHMAP_FOREACH(h, m->homes_by_name) {
40 _cleanup_(strv_freep) char **seats = NULL;
41 _cleanup_free_ char *home_path = NULL;
42 char **s;
43
44 r = home_auto_login(h, &seats);
45 if (r < 0) {
46 log_debug_errno(r, "Failed to determine whether home '%s' is candidate for auto-login, ignoring: %m", h->user_name);
47 continue;
48 }
49 if (!r)
50 continue;
51
52 r = bus_home_path(h, &home_path);
53 if (r < 0)
54 return log_error_errno(r, "Failed to generate home bus path: %m");
55
56 STRV_FOREACH(s, seats) {
57 r = sd_bus_message_append(reply, "(sso)", h->user_name, *s, home_path);
58 if (r < 0)
59 return r;
60 }
61 }
62
63 return sd_bus_message_close_container(reply);
64 }
65
66 static int method_get_home_by_name(
67 sd_bus_message *message,
68 void *userdata,
69 sd_bus_error *error) {
70
71 _cleanup_free_ char *path = NULL;
72 const char *user_name;
73 Manager *m = userdata;
74 Home *h;
75 int r;
76
77 assert(message);
78 assert(m);
79
80 r = sd_bus_message_read(message, "s", &user_name);
81 if (r < 0)
82 return r;
83 if (!valid_user_group_name(user_name, 0))
84 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
85
86 h = hashmap_get(m->homes_by_name, user_name);
87 if (!h)
88 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
89
90 r = bus_home_path(h, &path);
91 if (r < 0)
92 return r;
93
94 return sd_bus_reply_method_return(
95 message, "usussso",
96 (uint32_t) h->uid,
97 home_state_to_string(home_get_state(h)),
98 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
99 h->record ? user_record_real_name(h->record) : NULL,
100 h->record ? user_record_home_directory(h->record) : NULL,
101 h->record ? user_record_shell(h->record) : NULL,
102 path);
103 }
104
105 static int method_get_home_by_uid(
106 sd_bus_message *message,
107 void *userdata,
108 sd_bus_error *error) {
109
110 _cleanup_free_ char *path = NULL;
111 Manager *m = userdata;
112 uint32_t uid;
113 int r;
114 Home *h;
115
116 assert(message);
117 assert(m);
118
119 r = sd_bus_message_read(message, "u", &uid);
120 if (r < 0)
121 return r;
122 if (!uid_is_valid(uid))
123 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "UID " UID_FMT " is not valid", uid);
124
125 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
126 if (!h)
127 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for UID " UID_FMT " known", uid);
128
129 /* Note that we don't use bus_home_path() here, but build the path manually, since if we are queried
130 * for a UID we should also generate the bus path with a UID, and bus_home_path() uses our more
131 * typical bus path by name. */
132 if (asprintf(&path, "/org/freedesktop/home1/home/" UID_FMT, h->uid) < 0)
133 return -ENOMEM;
134
135 return sd_bus_reply_method_return(
136 message, "ssussso",
137 h->user_name,
138 home_state_to_string(home_get_state(h)),
139 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
140 h->record ? user_record_real_name(h->record) : NULL,
141 h->record ? user_record_home_directory(h->record) : NULL,
142 h->record ? user_record_shell(h->record) : NULL,
143 path);
144 }
145
146 static int method_list_homes(
147 sd_bus_message *message,
148 void *userdata,
149 sd_bus_error *error) {
150
151 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
152 Manager *m = userdata;
153 Home *h;
154 int r;
155
156 assert(message);
157 assert(m);
158
159 r = sd_bus_message_new_method_return(message, &reply);
160 if (r < 0)
161 return r;
162
163 r = sd_bus_message_open_container(reply, 'a', "(susussso)");
164 if (r < 0)
165 return r;
166
167 HASHMAP_FOREACH(h, m->homes_by_uid) {
168 _cleanup_free_ char *path = NULL;
169
170 r = bus_home_path(h, &path);
171 if (r < 0)
172 return r;
173
174 r = sd_bus_message_append(
175 reply, "(susussso)",
176 h->user_name,
177 (uint32_t) h->uid,
178 home_state_to_string(home_get_state(h)),
179 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
180 h->record ? user_record_real_name(h->record) : NULL,
181 h->record ? user_record_home_directory(h->record) : NULL,
182 h->record ? user_record_shell(h->record) : NULL,
183 path);
184 if (r < 0)
185 return r;
186 }
187
188 r = sd_bus_message_close_container(reply);
189 if (r < 0)
190 return r;
191
192 return sd_bus_send(NULL, reply, NULL);
193 }
194
195 static int method_get_user_record_by_name(
196 sd_bus_message *message,
197 void *userdata,
198 sd_bus_error *error) {
199
200 _cleanup_free_ char *json = NULL, *path = NULL;
201 Manager *m = userdata;
202 const char *user_name;
203 bool incomplete;
204 Home *h;
205 int r;
206
207 assert(message);
208 assert(m);
209
210 r = sd_bus_message_read(message, "s", &user_name);
211 if (r < 0)
212 return r;
213 if (!valid_user_group_name(user_name, 0))
214 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
215
216 h = hashmap_get(m->homes_by_name, user_name);
217 if (!h)
218 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
219
220 r = bus_home_get_record_json(h, message, &json, &incomplete);
221 if (r < 0)
222 return r;
223
224 r = bus_home_path(h, &path);
225 if (r < 0)
226 return r;
227
228 return sd_bus_reply_method_return(
229 message, "sbo",
230 json,
231 incomplete,
232 path);
233 }
234
235 static int method_get_user_record_by_uid(
236 sd_bus_message *message,
237 void *userdata,
238 sd_bus_error *error) {
239
240 _cleanup_free_ char *json = NULL, *path = NULL;
241 Manager *m = userdata;
242 bool incomplete;
243 uint32_t uid;
244 Home *h;
245 int r;
246
247 assert(message);
248 assert(m);
249
250 r = sd_bus_message_read(message, "u", &uid);
251 if (r < 0)
252 return r;
253 if (!uid_is_valid(uid))
254 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "UID " UID_FMT " is not valid", uid);
255
256 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
257 if (!h)
258 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for UID " UID_FMT " known", uid);
259
260 r = bus_home_get_record_json(h, message, &json, &incomplete);
261 if (r < 0)
262 return r;
263
264 if (asprintf(&path, "/org/freedesktop/home1/home/" UID_FMT, h->uid) < 0)
265 return -ENOMEM;
266
267 return sd_bus_reply_method_return(
268 message, "sbo",
269 json,
270 incomplete,
271 path);
272 }
273
274 static int generic_home_method(
275 Manager *m,
276 sd_bus_message *message,
277 sd_bus_message_handler_t handler,
278 sd_bus_error *error) {
279
280 const char *user_name;
281 Home *h;
282 int r;
283
284 r = sd_bus_message_read(message, "s", &user_name);
285 if (r < 0)
286 return r;
287
288 if (!valid_user_group_name(user_name, 0))
289 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
290
291 h = hashmap_get(m->homes_by_name, user_name);
292 if (!h)
293 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
294
295 return handler(message, h, error);
296 }
297
298 static int method_activate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
299 return generic_home_method(userdata, message, bus_home_method_activate, error);
300 }
301
302 static int method_deactivate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
303 return generic_home_method(userdata, message, bus_home_method_deactivate, error);
304 }
305
306 static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd_bus_error *error) {
307 _cleanup_(user_record_unrefp) UserRecord *signed_hr = NULL;
308 struct passwd *pw;
309 struct group *gr;
310 bool signed_locally;
311 Home *other;
312 int r;
313
314 assert(m);
315 assert(hr);
316 assert(ret);
317
318 r = user_record_is_supported(hr, error);
319 if (r < 0)
320 return r;
321
322 other = hashmap_get(m->homes_by_name, hr->user_name);
323 if (other)
324 return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists already, refusing.", hr->user_name);
325
326 pw = getpwnam(hr->user_name);
327 if (pw)
328 return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists in the NSS user database, refusing.", hr->user_name);
329
330 gr = getgrnam(hr->user_name);
331 if (gr)
332 return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s conflicts with an NSS group by the same name, refusing.", hr->user_name);
333
334 r = manager_verify_user_record(m, hr);
335 switch (r) {
336
337 case USER_RECORD_UNSIGNED:
338 /* If the record is unsigned, then let's sign it with our own key */
339 r = manager_sign_user_record(m, hr, &signed_hr, error);
340 if (r < 0)
341 return r;
342
343 hr = signed_hr;
344 _fallthrough_;
345
346 case USER_RECORD_SIGNED_EXCLUSIVE:
347 signed_locally = true;
348 break;
349
350 case USER_RECORD_SIGNED:
351 case USER_RECORD_FOREIGN:
352 signed_locally = false;
353 break;
354
355 case -ENOKEY:
356 return sd_bus_error_setf(error, BUS_ERROR_BAD_SIGNATURE, "Specified user record for %s is signed by a key we don't recognize, refusing.", hr->user_name);
357
358 default:
359 return sd_bus_error_set_errnof(error, r, "Failed to validate signature for '%s': %m", hr->user_name);
360 }
361
362 if (uid_is_valid(hr->uid)) {
363 other = hashmap_get(m->homes_by_uid, UID_TO_PTR(hr->uid));
364 if (other)
365 return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by home %s, refusing.", hr->uid, other->user_name);
366
367 pw = getpwuid(hr->uid);
368 if (pw)
369 return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use by NSS user %s, refusing.", hr->uid, pw->pw_name);
370
371 gr = getgrgid(hr->uid);
372 if (gr)
373 return sd_bus_error_setf(error, BUS_ERROR_UID_IN_USE, "Specified UID " UID_FMT " already in use as GID by NSS group %s, refusing.", hr->uid, gr->gr_name);
374 } else {
375 r = manager_augment_record_with_uid(m, hr);
376 if (r < 0)
377 return sd_bus_error_set_errnof(error, r, "Failed to acquire UID for '%s': %m", hr->user_name);
378 }
379
380 r = home_new(m, hr, NULL, ret);
381 if (r < 0)
382 return r;
383
384 (*ret)->signed_locally = signed_locally;
385 return r;
386 }
387
388 static int method_register_home(
389 sd_bus_message *message,
390 void *userdata,
391 sd_bus_error *error) {
392
393 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
394 Manager *m = userdata;
395 Home *h;
396 int r;
397
398 assert(message);
399 assert(m);
400
401 r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED, &hr, error);
402 if (r < 0)
403 return r;
404
405 r = bus_verify_polkit_async(
406 message,
407 CAP_SYS_ADMIN,
408 "org.freedesktop.home1.create-home",
409 NULL,
410 true,
411 UID_INVALID,
412 &m->polkit_registry,
413 error);
414 if (r < 0)
415 return r;
416 if (r == 0)
417 return 1; /* Will call us back */
418
419 r = validate_and_allocate_home(m, hr, &h, error);
420 if (r < 0)
421 return r;
422
423 r = home_save_record(h);
424 if (r < 0) {
425 home_free(h);
426 return r;
427 }
428
429 return sd_bus_reply_method_return(message, NULL);
430 }
431
432 static int method_unregister_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
433 return generic_home_method(userdata, message, bus_home_method_unregister, error);
434 }
435
436 static int method_create_home(
437 sd_bus_message *message,
438 void *userdata,
439 sd_bus_error *error) {
440
441 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
442 Manager *m = userdata;
443 Home *h;
444 int r;
445
446 assert(message);
447 assert(m);
448
449 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, &hr, error);
450 if (r < 0)
451 return r;
452
453 r = bus_verify_polkit_async(
454 message,
455 CAP_SYS_ADMIN,
456 "org.freedesktop.home1.create-home",
457 NULL,
458 true,
459 UID_INVALID,
460 &m->polkit_registry,
461 error);
462 if (r < 0)
463 return r;
464 if (r == 0)
465 return 1; /* Will call us back */
466
467 r = validate_and_allocate_home(m, hr, &h, error);
468 if (r < 0)
469 return r;
470
471 r = home_create(h, hr, error);
472 if (r < 0)
473 goto fail;
474
475 assert(r == 0);
476 h->unregister_on_failure = true;
477 assert(!h->current_operation);
478
479 r = home_set_current_message(h, message);
480 if (r < 0)
481 return r;
482
483 return 1;
484
485 fail:
486 (void) home_unlink_record(h);
487 h = home_free(h);
488 return r;
489 }
490
491 static int method_realize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
492 return generic_home_method(userdata, message, bus_home_method_realize, error);
493 }
494
495 static int method_remove_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
496 return generic_home_method(userdata, message, bus_home_method_remove, error);
497 }
498
499 static int method_fixate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
500 return generic_home_method(userdata, message, bus_home_method_fixate, error);
501 }
502
503 static int method_authenticate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
504 return generic_home_method(userdata, message, bus_home_method_authenticate, error);
505 }
506
507 static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
508 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
509 Manager *m = userdata;
510 Home *h;
511 int r;
512
513 assert(message);
514 assert(m);
515
516 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, &hr, error);
517 if (r < 0)
518 return r;
519
520 assert(hr->user_name);
521
522 h = hashmap_get(m->homes_by_name, hr->user_name);
523 if (!h)
524 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", hr->user_name);
525
526 return bus_home_method_update_record(h, message, hr, error);
527 }
528
529 static int method_resize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
530 return generic_home_method(userdata, message, bus_home_method_resize, error);
531 }
532
533 static int method_change_password_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
534 return generic_home_method(userdata, message, bus_home_method_change_password, error);
535 }
536
537 static int method_lock_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
538 return generic_home_method(userdata, message, bus_home_method_lock, error);
539 }
540
541 static int method_unlock_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
542 return generic_home_method(userdata, message, bus_home_method_unlock, error);
543 }
544
545 static int method_acquire_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
546 return generic_home_method(userdata, message, bus_home_method_acquire, error);
547 }
548
549 static int method_ref_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
550 return generic_home_method(userdata, message, bus_home_method_ref, error);
551 }
552
553 static int method_release_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
554 return generic_home_method(userdata, message, bus_home_method_release, error);
555 }
556
557 static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
558 _cleanup_(operation_unrefp) Operation *o = NULL;
559 bool waiting = false;
560 Manager *m = userdata;
561 Home *h;
562 int r;
563
564 assert(m);
565
566 /* This is called from logind when we are preparing for system suspend. We enqueue a lock operation
567 * for every suitable home we have and only when all of them completed we send a reply indicating
568 * completion. */
569
570 HASHMAP_FOREACH(h, m->homes_by_name) {
571
572 /* Automatically suspend all homes that have at least one client referencing it that asked
573 * for "please suspend", and no client that asked for "please do not suspend". */
574 if (h->ref_event_source_dont_suspend ||
575 !h->ref_event_source_please_suspend)
576 continue;
577
578 if (!o) {
579 o = operation_new(OPERATION_LOCK_ALL, message);
580 if (!o)
581 return -ENOMEM;
582 }
583
584 log_info("Automatically locking home of user %s.", h->user_name);
585
586 r = home_schedule_operation(h, o, error);
587 if (r < 0)
588 return r;
589
590 waiting = true;
591 }
592
593 if (waiting) /* At least one lock operation was enqeued, let's leave here without a reply: it will
594 * be sent as soon as the last of the lock operations completed. */
595 return 1;
596
597 return sd_bus_reply_method_return(message, NULL);
598 }
599
600 static int method_deactivate_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
601 _cleanup_(operation_unrefp) Operation *o = NULL;
602 bool waiting = false;
603 Manager *m = userdata;
604 Home *h;
605 int r;
606
607 assert(m);
608
609 /* This is called from systemd-homed-activate.service's ExecStop= command to ensure that all home
610 * directories are shutdown before the system goes down. Note that we don't do this from
611 * systemd-homed.service itself since we want to allow restarting of it without tearing down all home
612 * directories. */
613
614 HASHMAP_FOREACH(h, m->homes_by_name) {
615
616 if (!o) {
617 o = operation_new(OPERATION_DEACTIVATE_ALL, message);
618 if (!o)
619 return -ENOMEM;
620 }
621
622 log_info("Automatically deactivating home of user %s.", h->user_name);
623
624 r = home_schedule_operation(h, o, error);
625 if (r < 0)
626 return r;
627
628 waiting = true;
629 }
630
631 if (waiting) /* At least one lock operation was enqeued, let's leave here without a reply: it will be
632 * sent as soon as the last of the deactivation operations completed. */
633 return 1;
634
635 return sd_bus_reply_method_return(message, NULL);
636 }
637
638 static const sd_bus_vtable manager_vtable[] = {
639 SD_BUS_VTABLE_START(0),
640
641 SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
642
643 SD_BUS_METHOD_WITH_NAMES("GetHomeByName",
644 "s",
645 SD_BUS_PARAM(user_name),
646 "usussso",
647 SD_BUS_PARAM(uid)
648 SD_BUS_PARAM(home_state)
649 SD_BUS_PARAM(gid)
650 SD_BUS_PARAM(real_name)
651 SD_BUS_PARAM(home_directory)
652 SD_BUS_PARAM(shell)
653 SD_BUS_PARAM(bus_path),
654 method_get_home_by_name,
655 SD_BUS_VTABLE_UNPRIVILEGED),
656 SD_BUS_METHOD_WITH_NAMES("GetHomeByUID",
657 "u",
658 SD_BUS_PARAM(uid),
659 "ssussso",
660 SD_BUS_PARAM(user_name)
661 SD_BUS_PARAM(home_state)
662 SD_BUS_PARAM(gid)
663 SD_BUS_PARAM(real_name)
664 SD_BUS_PARAM(home_directory)
665 SD_BUS_PARAM(shell)
666 SD_BUS_PARAM(bus_path),
667 method_get_home_by_uid,
668 SD_BUS_VTABLE_UNPRIVILEGED),
669 SD_BUS_METHOD_WITH_NAMES("GetUserRecordByName",
670 "s",
671 SD_BUS_PARAM(user_name),
672 "sbo",
673 SD_BUS_PARAM(user_record)
674 SD_BUS_PARAM(incomplete)
675 SD_BUS_PARAM(bus_path),
676 method_get_user_record_by_name,
677 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
678 SD_BUS_METHOD_WITH_NAMES("GetUserRecordByUID",
679 "u",
680 SD_BUS_PARAM(uid),
681 "sbo",
682 SD_BUS_PARAM(user_record)
683 SD_BUS_PARAM(incomplete)
684 SD_BUS_PARAM(bus_path),
685 method_get_user_record_by_uid,
686 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
687 SD_BUS_METHOD_WITH_NAMES("ListHomes",
688 NULL,,
689 "a(susussso)",
690 SD_BUS_PARAM(home_areas),
691 method_list_homes,
692 SD_BUS_VTABLE_UNPRIVILEGED),
693
694 /* The following methods directly execute an operation on a home area, without ref-counting, queueing
695 * or anything, and are accessible through homectl. */
696 SD_BUS_METHOD_WITH_NAMES("ActivateHome",
697 "ss",
698 SD_BUS_PARAM(user_name)
699 SD_BUS_PARAM(secret),
700 NULL,,
701 method_activate_home,
702 SD_BUS_VTABLE_SENSITIVE),
703 SD_BUS_METHOD_WITH_NAMES("DeactivateHome",
704 "s",
705 SD_BUS_PARAM(user_name),
706 NULL,,
707 method_deactivate_home,
708 0),
709
710 /* Add the JSON record to homed, but don't create actual $HOME */
711 SD_BUS_METHOD_WITH_NAMES("RegisterHome",
712 "s",
713 SD_BUS_PARAM(user_record),
714 NULL,,
715 method_register_home,
716 SD_BUS_VTABLE_UNPRIVILEGED),
717
718 /* Remove the JSON record from homed, but don't remove actual $HOME */
719 SD_BUS_METHOD_WITH_NAMES("UnregisterHome",
720 "s",
721 SD_BUS_PARAM(user_name),
722 NULL,,
723 method_unregister_home,
724 SD_BUS_VTABLE_UNPRIVILEGED),
725
726 /* Add JSON record, and create $HOME for it */
727 SD_BUS_METHOD_WITH_NAMES("CreateHome",
728 "s",
729 SD_BUS_PARAM(user_record),
730 NULL,,
731 method_create_home,
732 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
733
734 /* Create $HOME for already registered JSON entry */
735 SD_BUS_METHOD_WITH_NAMES("RealizeHome",
736 "ss",
737 SD_BUS_PARAM(user_name)
738 SD_BUS_PARAM(secret),
739 NULL,,
740 method_realize_home,
741 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
742
743 /* Remove the JSON record and remove $HOME */
744 SD_BUS_METHOD_WITH_NAMES("RemoveHome",
745 "s",
746 SD_BUS_PARAM(user_name),
747 NULL,,
748 method_remove_home,
749 SD_BUS_VTABLE_UNPRIVILEGED),
750
751 /* Investigate $HOME and propagate contained JSON record into our database */
752 SD_BUS_METHOD_WITH_NAMES("FixateHome",
753 "ss",
754 SD_BUS_PARAM(user_name)
755 SD_BUS_PARAM(secret),
756 NULL,,
757 method_fixate_home,
758 SD_BUS_VTABLE_SENSITIVE),
759
760 /* Just check credentials */
761 SD_BUS_METHOD_WITH_NAMES("AuthenticateHome",
762 "ss",
763 SD_BUS_PARAM(user_name)
764 SD_BUS_PARAM(secret),
765 NULL,,
766 method_authenticate_home,
767 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
768
769 /* Update the JSON record of existing user */
770 SD_BUS_METHOD_WITH_NAMES("UpdateHome",
771 "s",
772 SD_BUS_PARAM(user_record),
773 NULL,,
774 method_update_home,
775 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
776
777 SD_BUS_METHOD_WITH_NAMES("ResizeHome",
778 "sts",
779 SD_BUS_PARAM(user_name)
780 SD_BUS_PARAM(size)
781 SD_BUS_PARAM(secret),
782 NULL,,
783 method_resize_home,
784 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
785
786 SD_BUS_METHOD_WITH_NAMES("ChangePasswordHome",
787 "sss",
788 SD_BUS_PARAM(user_name)
789 SD_BUS_PARAM(new_secret)
790 SD_BUS_PARAM(old_secret),
791 NULL,,
792 method_change_password_home,
793 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
794
795 /* Prepare active home for system suspend: flush out passwords, suspend access */
796 SD_BUS_METHOD_WITH_NAMES("LockHome",
797 "s",
798 SD_BUS_PARAM(user_name),
799 NULL,,
800 method_lock_home,
801 0),
802
803 /* Make $HOME usable after system resume again */
804 SD_BUS_METHOD_WITH_NAMES("UnlockHome",
805 "ss",
806 SD_BUS_PARAM(user_name)
807 SD_BUS_PARAM(secret),
808 NULL,,
809 method_unlock_home,
810 SD_BUS_VTABLE_SENSITIVE),
811
812 /* The following methods implement ref-counted activation, and are what the PAM module and "homectl
813 * with" use. In contrast to the methods above which fail if an operation is already being executed
814 * on a home directory, these ones will queue the request, and are thus more reliable. Moreover,
815 * they are a bit smarter: AcquireHome() will fixate, activate, unlock, or authenticate depending on
816 * the state of the home area, so that the end result is always the same (i.e. the home directory is
817 * accessible), and we always validate the specified passwords. RefHome() will not authenticate, and
818 * thus only works if the home area is already active. */
819 SD_BUS_METHOD_WITH_NAMES("AcquireHome",
820 "ssb",
821 SD_BUS_PARAM(user_name)
822 SD_BUS_PARAM(secret)
823 SD_BUS_PARAM(please_suspend),
824 "h",
825 SD_BUS_PARAM(send_fd),
826 method_acquire_home,
827 SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
828 SD_BUS_METHOD_WITH_NAMES("RefHome",
829 "sb",
830 SD_BUS_PARAM(user_name)
831 SD_BUS_PARAM(please_suspend),
832 "h",
833 SD_BUS_PARAM(send_fd),
834 method_ref_home,
835 0),
836 SD_BUS_METHOD_WITH_NAMES("ReleaseHome",
837 "s",
838 SD_BUS_PARAM(user_name),
839 NULL,,
840 method_release_home,
841 0),
842
843 /* An operation that acts on all homes that allow it */
844 SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
845 SD_BUS_METHOD("DeactivateAllHomes", NULL, NULL, method_deactivate_all_homes, 0),
846
847 SD_BUS_VTABLE_END
848 };
849
850 const BusObjectImplementation manager_object = {
851 "/org/freedesktop/home1",
852 "org.freedesktop.home1.Manager",
853 .vtables = BUS_VTABLES(manager_vtable),
854 .children = BUS_IMPLEMENTATIONS(&home_object),
855 };
856
857 static int on_deferred_auto_login(sd_event_source *s, void *userdata) {
858 Manager *m = userdata;
859 int r;
860
861 assert(m);
862
863 m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source);
864
865 r = sd_bus_emit_properties_changed(
866 m->bus,
867 "/org/freedesktop/home1",
868 "org.freedesktop.home1.Manager",
869 "AutoLogin", NULL);
870 if (r < 0)
871 log_warning_errno(r, "Failed to send AutoLogin property change event, ignoring: %m");
872
873 return 0;
874 }
875
876 int bus_manager_emit_auto_login_changed(Manager *m) {
877 int r;
878 assert(m);
879
880 if (m->deferred_auto_login_event_source)
881 return 0;
882
883 if (!m->event)
884 return 0;
885
886 if (IN_SET(sd_event_get_state(m->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
887 return 0;
888
889 r = sd_event_add_defer(m->event, &m->deferred_auto_login_event_source, on_deferred_auto_login, m);
890 if (r < 0)
891 return log_error_errno(r, "Failed to allocate auto login event source: %m");
892
893 r = sd_event_source_set_priority(m->deferred_auto_login_event_source, SD_EVENT_PRIORITY_IDLE+10);
894 if (r < 0)
895 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
896
897 (void) sd_event_source_set_description(m->deferred_auto_login_event_source, "deferred-auto-login");
898 return 1;
899 }