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