]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homed-manager-bus.c
Merge pull request #15281 from keszybz/functional-test-rework
[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 Iterator i;
29 Home *h;
30 int r;
31
32 assert(bus);
33 assert(reply);
34 assert(m);
35
36 r = sd_bus_message_open_container(reply, 'a', "(sso)");
37 if (r < 0)
38 return r;
39
40 HASHMAP_FOREACH(h, m->homes_by_name, i) {
41 _cleanup_(strv_freep) char **seats = NULL;
42 _cleanup_free_ char *home_path = NULL;
43 char **s;
44
45 r = home_auto_login(h, &seats);
46 if (r < 0) {
47 log_debug_errno(r, "Failed to determine whether home '%s' is candidate for auto-login, ignoring: %m", h->user_name);
48 continue;
49 }
50 if (!r)
51 continue;
52
53 r = bus_home_path(h, &home_path);
54 if (r < 0)
55 return log_error_errno(r, "Failed to generate home bus path: %m");
56
57 STRV_FOREACH(s, seats) {
58 r = sd_bus_message_append(reply, "(sso)", h->user_name, *s, home_path);
59 if (r < 0)
60 return r;
61 }
62 }
63
64 return sd_bus_message_close_container(reply);
65 }
66
67 static int method_get_home_by_name(
68 sd_bus_message *message,
69 void *userdata,
70 sd_bus_error *error) {
71
72 _cleanup_free_ char *path = NULL;
73 const char *user_name;
74 Manager *m = userdata;
75 Home *h;
76 int r;
77
78 assert(message);
79 assert(m);
80
81 r = sd_bus_message_read(message, "s", &user_name);
82 if (r < 0)
83 return r;
84 if (!valid_user_group_name(user_name, 0))
85 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
86
87 h = hashmap_get(m->homes_by_name, user_name);
88 if (!h)
89 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
90
91 r = bus_home_path(h, &path);
92 if (r < 0)
93 return r;
94
95 return sd_bus_reply_method_return(
96 message, "usussso",
97 (uint32_t) h->uid,
98 home_state_to_string(home_get_state(h)),
99 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
100 h->record ? user_record_real_name(h->record) : NULL,
101 h->record ? user_record_home_directory(h->record) : NULL,
102 h->record ? user_record_shell(h->record) : NULL,
103 path);
104 }
105
106 static int method_get_home_by_uid(
107 sd_bus_message *message,
108 void *userdata,
109 sd_bus_error *error) {
110
111 _cleanup_free_ char *path = NULL;
112 Manager *m = userdata;
113 uint32_t uid;
114 int r;
115 Home *h;
116
117 assert(message);
118 assert(m);
119
120 r = sd_bus_message_read(message, "u", &uid);
121 if (r < 0)
122 return r;
123 if (!uid_is_valid(uid))
124 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "UID " UID_FMT " is not valid", uid);
125
126 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
127 if (!h)
128 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for UID " UID_FMT " known", uid);
129
130 /* Note that we don't use bus_home_path() here, but build the path manually, since if we are queried
131 * for a UID we should also generate the bus path with a UID, and bus_home_path() uses our more
132 * typical bus path by name. */
133 if (asprintf(&path, "/org/freedesktop/home1/home/" UID_FMT, h->uid) < 0)
134 return -ENOMEM;
135
136 return sd_bus_reply_method_return(
137 message, "ssussso",
138 h->user_name,
139 home_state_to_string(home_get_state(h)),
140 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
141 h->record ? user_record_real_name(h->record) : NULL,
142 h->record ? user_record_home_directory(h->record) : NULL,
143 h->record ? user_record_shell(h->record) : NULL,
144 path);
145 }
146
147 static int method_list_homes(
148 sd_bus_message *message,
149 void *userdata,
150 sd_bus_error *error) {
151
152 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
153 Manager *m = userdata;
154 Iterator i;
155 Home *h;
156 int r;
157
158 assert(message);
159 assert(m);
160
161 r = sd_bus_message_new_method_return(message, &reply);
162 if (r < 0)
163 return r;
164
165 r = sd_bus_message_open_container(reply, 'a', "(susussso)");
166 if (r < 0)
167 return r;
168
169 HASHMAP_FOREACH(h, m->homes_by_uid, i) {
170 _cleanup_free_ char *path = NULL;
171
172 r = bus_home_path(h, &path);
173 if (r < 0)
174 return r;
175
176 r = sd_bus_message_append(
177 reply, "(susussso)",
178 h->user_name,
179 (uint32_t) h->uid,
180 home_state_to_string(home_get_state(h)),
181 h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID,
182 h->record ? user_record_real_name(h->record) : NULL,
183 h->record ? user_record_home_directory(h->record) : NULL,
184 h->record ? user_record_shell(h->record) : NULL,
185 path);
186 if (r < 0)
187 return r;
188 }
189
190 r = sd_bus_message_close_container(reply);
191 if (r < 0)
192 return r;
193
194 return sd_bus_send(NULL, reply, NULL);
195 }
196
197 static int method_get_user_record_by_name(
198 sd_bus_message *message,
199 void *userdata,
200 sd_bus_error *error) {
201
202 _cleanup_free_ char *json = NULL, *path = NULL;
203 Manager *m = userdata;
204 const char *user_name;
205 bool incomplete;
206 Home *h;
207 int r;
208
209 assert(message);
210 assert(m);
211
212 r = sd_bus_message_read(message, "s", &user_name);
213 if (r < 0)
214 return r;
215 if (!valid_user_group_name(user_name, 0))
216 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
217
218 h = hashmap_get(m->homes_by_name, user_name);
219 if (!h)
220 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
221
222 r = bus_home_get_record_json(h, message, &json, &incomplete);
223 if (r < 0)
224 return r;
225
226 r = bus_home_path(h, &path);
227 if (r < 0)
228 return r;
229
230 return sd_bus_reply_method_return(
231 message, "sbo",
232 json,
233 incomplete,
234 path);
235 }
236
237 static int method_get_user_record_by_uid(
238 sd_bus_message *message,
239 void *userdata,
240 sd_bus_error *error) {
241
242 _cleanup_free_ char *json = NULL, *path = NULL;
243 Manager *m = userdata;
244 bool incomplete;
245 uint32_t uid;
246 Home *h;
247 int r;
248
249 assert(message);
250 assert(m);
251
252 r = sd_bus_message_read(message, "u", &uid);
253 if (r < 0)
254 return r;
255 if (!uid_is_valid(uid))
256 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "UID " UID_FMT " is not valid", uid);
257
258 h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid));
259 if (!h)
260 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for UID " UID_FMT " known", uid);
261
262 r = bus_home_get_record_json(h, message, &json, &incomplete);
263 if (r < 0)
264 return r;
265
266 if (asprintf(&path, "/org/freedesktop/home1/home/" UID_FMT, h->uid) < 0)
267 return -ENOMEM;
268
269 return sd_bus_reply_method_return(
270 message, "sbo",
271 json,
272 incomplete,
273 path);
274 }
275
276 static int generic_home_method(
277 Manager *m,
278 sd_bus_message *message,
279 sd_bus_message_handler_t handler,
280 sd_bus_error *error) {
281
282 const char *user_name;
283 Home *h;
284 int r;
285
286 r = sd_bus_message_read(message, "s", &user_name);
287 if (r < 0)
288 return r;
289
290 if (!valid_user_group_name(user_name, 0))
291 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
292
293 h = hashmap_get(m->homes_by_name, user_name);
294 if (!h)
295 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", user_name);
296
297 return handler(message, h, error);
298 }
299
300 static int method_activate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
301 return generic_home_method(userdata, message, bus_home_method_activate, error);
302 }
303
304 static int method_deactivate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 return generic_home_method(userdata, message, bus_home_method_deactivate, error);
306 }
307
308 static int validate_and_allocate_home(Manager *m, UserRecord *hr, Home **ret, sd_bus_error *error) {
309 _cleanup_(user_record_unrefp) UserRecord *signed_hr = NULL;
310 struct passwd *pw;
311 struct group *gr;
312 bool signed_locally;
313 Home *other;
314 int r;
315
316 assert(m);
317 assert(hr);
318 assert(ret);
319
320 r = user_record_is_supported(hr, error);
321 if (r < 0)
322 return r;
323
324 other = hashmap_get(m->homes_by_name, hr->user_name);
325 if (other)
326 return sd_bus_error_setf(error, BUS_ERROR_USER_NAME_EXISTS, "Specified user name %s exists already, refusing.", hr->user_name);
327
328 pw = getpwnam(hr->user_name);
329 if (pw)
330 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);
331
332 gr = getgrnam(hr->user_name);
333 if (gr)
334 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);
335
336 r = manager_verify_user_record(m, hr);
337 switch (r) {
338
339 case USER_RECORD_UNSIGNED:
340 /* If the record is unsigned, then let's sign it with our own key */
341 r = manager_sign_user_record(m, hr, &signed_hr, error);
342 if (r < 0)
343 return r;
344
345 hr = signed_hr;
346 _fallthrough_;
347
348 case USER_RECORD_SIGNED_EXCLUSIVE:
349 signed_locally = true;
350 break;
351
352 case USER_RECORD_SIGNED:
353 case USER_RECORD_FOREIGN:
354 signed_locally = false;
355 break;
356
357 case -ENOKEY:
358 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);
359
360 default:
361 return sd_bus_error_set_errnof(error, r, "Failed to validate signature for '%s': %m", hr->user_name);
362 }
363
364 if (uid_is_valid(hr->uid)) {
365 other = hashmap_get(m->homes_by_uid, UID_TO_PTR(hr->uid));
366 if (other)
367 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);
368
369 pw = getpwuid(hr->uid);
370 if (pw)
371 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);
372
373 gr = getgrgid(hr->uid);
374 if (gr)
375 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);
376 } else {
377 r = manager_augment_record_with_uid(m, hr);
378 if (r < 0)
379 return sd_bus_error_set_errnof(error, r, "Failed to acquire UID for '%s': %m", hr->user_name);
380 }
381
382 r = home_new(m, hr, NULL, ret);
383 if (r < 0)
384 return r;
385
386 (*ret)->signed_locally = signed_locally;
387 return r;
388 }
389
390 static int method_register_home(
391 sd_bus_message *message,
392 void *userdata,
393 sd_bus_error *error) {
394
395 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
396 Manager *m = userdata;
397 Home *h;
398 int r;
399
400 assert(message);
401 assert(m);
402
403 r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED, &hr, error);
404 if (r < 0)
405 return r;
406
407 r = bus_verify_polkit_async(
408 message,
409 CAP_SYS_ADMIN,
410 "org.freedesktop.home1.create-home",
411 NULL,
412 true,
413 UID_INVALID,
414 &m->polkit_registry,
415 error);
416 if (r < 0)
417 return r;
418 if (r == 0)
419 return 1; /* Will call us back */
420
421 r = validate_and_allocate_home(m, hr, &h, error);
422 if (r < 0)
423 return r;
424
425 r = home_save_record(h);
426 if (r < 0) {
427 home_free(h);
428 return r;
429 }
430
431 return sd_bus_reply_method_return(message, NULL);
432 }
433
434 static int method_unregister_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
435 return generic_home_method(userdata, message, bus_home_method_unregister, error);
436 }
437
438 static int method_create_home(
439 sd_bus_message *message,
440 void *userdata,
441 sd_bus_error *error) {
442
443 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
444 Manager *m = userdata;
445 Home *h;
446 int r;
447
448 assert(message);
449 assert(m);
450
451 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);
452 if (r < 0)
453 return r;
454
455 r = bus_verify_polkit_async(
456 message,
457 CAP_SYS_ADMIN,
458 "org.freedesktop.home1.create-home",
459 NULL,
460 true,
461 UID_INVALID,
462 &m->polkit_registry,
463 error);
464 if (r < 0)
465 return r;
466 if (r == 0)
467 return 1; /* Will call us back */
468
469 r = validate_and_allocate_home(m, hr, &h, error);
470 if (r < 0)
471 return r;
472
473 r = home_create(h, hr, error);
474 if (r < 0)
475 goto fail;
476
477 assert(r == 0);
478 h->unregister_on_failure = true;
479 assert(!h->current_operation);
480
481 r = home_set_current_message(h, message);
482 if (r < 0)
483 return r;
484
485 return 1;
486
487 fail:
488 (void) home_unlink_record(h);
489 h = home_free(h);
490 return r;
491 }
492
493 static int method_realize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
494 return generic_home_method(userdata, message, bus_home_method_realize, error);
495 }
496
497 static int method_remove_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
498 return generic_home_method(userdata, message, bus_home_method_remove, error);
499 }
500
501 static int method_fixate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
502 return generic_home_method(userdata, message, bus_home_method_fixate, error);
503 }
504
505 static int method_authenticate_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
506 return generic_home_method(userdata, message, bus_home_method_authenticate, error);
507 }
508
509 static int method_update_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
510 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
511 Manager *m = userdata;
512 Home *h;
513 int r;
514
515 assert(message);
516 assert(m);
517
518 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);
519 if (r < 0)
520 return r;
521
522 assert(hr->user_name);
523
524 h = hashmap_get(m->homes_by_name, hr->user_name);
525 if (!h)
526 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", hr->user_name);
527
528 return bus_home_method_update_record(h, message, hr, error);
529 }
530
531 static int method_resize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
532 return generic_home_method(userdata, message, bus_home_method_resize, error);
533 }
534
535 static int method_change_password_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
536 return generic_home_method(userdata, message, bus_home_method_change_password, error);
537 }
538
539 static int method_lock_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
540 return generic_home_method(userdata, message, bus_home_method_lock, error);
541 }
542
543 static int method_unlock_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
544 return generic_home_method(userdata, message, bus_home_method_unlock, error);
545 }
546
547 static int method_acquire_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
548 return generic_home_method(userdata, message, bus_home_method_acquire, error);
549 }
550
551 static int method_ref_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
552 return generic_home_method(userdata, message, bus_home_method_ref, error);
553 }
554
555 static int method_release_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
556 return generic_home_method(userdata, message, bus_home_method_release, error);
557 }
558
559 static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
560 _cleanup_(operation_unrefp) Operation *o = NULL;
561 bool waiting = false;
562 Manager *m = userdata;
563 Iterator i;
564 Home *h;
565 int r;
566
567 assert(m);
568
569 /* This is called from logind when we are preparing for system suspend. We enqueue a lock operation
570 * for every suitable home we have and only when all of them completed we send a reply indicating
571 * completion. */
572
573 HASHMAP_FOREACH(h, m->homes_by_name, i) {
574
575 /* Automatically suspend all homes that have at least one client referencing it that asked
576 * for "please suspend", and no client that asked for "please do not suspend". */
577 if (h->ref_event_source_dont_suspend ||
578 !h->ref_event_source_please_suspend)
579 continue;
580
581 if (!o) {
582 o = operation_new(OPERATION_LOCK_ALL, message);
583 if (!o)
584 return -ENOMEM;
585 }
586
587 log_info("Automatically locking home of user %s.", h->user_name);
588
589 r = home_schedule_operation(h, o, error);
590 if (r < 0)
591 return r;
592
593 waiting = true;
594 }
595
596 if (waiting) /* At least one lock operation was enqeued, let's leave here without a reply: it will
597 * be sent as soon as the last of the lock operations completed. */
598 return 1;
599
600 return sd_bus_reply_method_return(message, NULL);
601 }
602
603 const sd_bus_vtable manager_vtable[] = {
604 SD_BUS_VTABLE_START(0),
605
606 SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
607
608 SD_BUS_METHOD("GetHomeByName", "s", "usussso", method_get_home_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
609 SD_BUS_METHOD("GetHomeByUID", "u", "ssussso", method_get_home_by_uid, SD_BUS_VTABLE_UNPRIVILEGED),
610 SD_BUS_METHOD("GetUserRecordByName", "s", "sbo", method_get_user_record_by_name, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
611 SD_BUS_METHOD("GetUserRecordByUID", "u", "sbo", method_get_user_record_by_uid, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
612 SD_BUS_METHOD("ListHomes", NULL, "a(susussso)", method_list_homes, SD_BUS_VTABLE_UNPRIVILEGED),
613
614 /* The following methods directly execute an operation on a home area, without ref-counting, queing
615 * or anything, and are accessible through homectl. */
616 SD_BUS_METHOD("ActivateHome", "ss", NULL, method_activate_home, SD_BUS_VTABLE_SENSITIVE),
617 SD_BUS_METHOD("DeactivateHome", "s", NULL, method_deactivate_home, 0),
618 SD_BUS_METHOD("RegisterHome", "s", NULL, method_register_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Add JSON record to homed, but don't create actual $HOME */
619 SD_BUS_METHOD("UnregisterHome", "s", NULL, method_unregister_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Remove JSON record from homed, but don't remove actual $HOME */
620 SD_BUS_METHOD("CreateHome", "s", NULL, method_create_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Add JSON record, and create $HOME for it */
621 SD_BUS_METHOD("RealizeHome", "ss", NULL, method_realize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Create $HOME for already registered JSON entry */
622 SD_BUS_METHOD("RemoveHome", "s", NULL, method_remove_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Remove JSON record and remove $HOME */
623 SD_BUS_METHOD("FixateHome", "ss", NULL, method_fixate_home, SD_BUS_VTABLE_SENSITIVE), /* Investigate $HOME and propagate contained JSON record into our database */
624 SD_BUS_METHOD("AuthenticateHome", "ss", NULL, method_authenticate_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Just check credentials */
625 SD_BUS_METHOD("UpdateHome", "s", NULL, method_update_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Update JSON record of existing user */
626 SD_BUS_METHOD("ResizeHome", "sts", NULL, method_resize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
627 SD_BUS_METHOD("ChangePasswordHome", "sss", NULL, method_change_password_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
628 SD_BUS_METHOD("LockHome", "s", NULL, method_lock_home, 0), /* Prepare active home for system suspend: flush out passwords, suspend access */
629 SD_BUS_METHOD("UnlockHome", "ss", NULL, method_unlock_home, SD_BUS_VTABLE_SENSITIVE), /* Make $HOME usable after system resume again */
630
631 /* The following methods implement ref-counted activation, and are what the PAM module calls (and
632 * what "homectl with" runs). In contrast to the methods above which fail if an operation is already
633 * being executed on a home directory, these ones will queue the request, and are thus more
634 * reliable. Moreover, they are a bit smarter: AcquireHome() will fixate, activate, unlock, or
635 * authenticate depending on the state of the home, so that the end result is always the same
636 * (i.e. the home directory is accessible), and we always validate the specified passwords. RefHome()
637 * will not authenticate, and thus only works if home is already active. */
638 SD_BUS_METHOD("AcquireHome", "ssb", "h", method_acquire_home, SD_BUS_VTABLE_SENSITIVE),
639 SD_BUS_METHOD("RefHome", "sb", "h", method_ref_home, 0),
640 SD_BUS_METHOD("ReleaseHome", "s", NULL, method_release_home, 0),
641
642 /* An operation that acts on all homes that allow it */
643 SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
644
645 SD_BUS_VTABLE_END
646 };
647
648 static int on_deferred_auto_login(sd_event_source *s, void *userdata) {
649 Manager *m = userdata;
650 int r;
651
652 assert(m);
653
654 m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source);
655
656 r = sd_bus_emit_properties_changed(
657 m->bus,
658 "/org/freedesktop/home1",
659 "org.freedesktop.home1.Manager",
660 "AutoLogin", NULL);
661 if (r < 0)
662 log_warning_errno(r, "Failed to send AutoLogin property change event, ignoring: %m");
663
664 return 0;
665 }
666
667 int bus_manager_emit_auto_login_changed(Manager *m) {
668 int r;
669 assert(m);
670
671 if (m->deferred_auto_login_event_source)
672 return 0;
673
674 if (!m->event)
675 return 0;
676
677 if (IN_SET(sd_event_get_state(m->event), SD_EVENT_FINISHED, SD_EVENT_EXITING))
678 return 0;
679
680 r = sd_event_add_defer(m->event, &m->deferred_auto_login_event_source, on_deferred_auto_login, m);
681 if (r < 0)
682 return log_error_errno(r, "Failed to allocate auto login event source: %m");
683
684 r = sd_event_source_set_priority(m->deferred_auto_login_event_source, SD_EVENT_PRIORITY_IDLE+10);
685 if (r < 0)
686 log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m");
687
688 (void) sd_event_source_set_description(m->deferred_auto_login_event_source, "deferred-auto-login");
689 return 1;
690 }