]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/home/homework.c
Merge pull request #15442 from poettering/fido2
[thirdparty/systemd.git] / src / home / homework.c
CommitLineData
70a5db58
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <stddef.h>
4#include <sys/mount.h>
5
6#include "chown-recursive.h"
7#include "copy.h"
8#include "fd-util.h"
9#include "fileio.h"
1dfe5de0 10#include "fs-util.h"
70a5db58
LP
11#include "home-util.h"
12#include "homework-cifs.h"
13#include "homework-directory.h"
7b78db28 14#include "homework-fido2.h"
70a5db58
LP
15#include "homework-fscrypt.h"
16#include "homework-luks.h"
17#include "homework-mount.h"
18#include "homework-pkcs11.h"
19#include "homework.h"
20#include "main-func.h"
21#include "memory-util.h"
22#include "missing_magic.h"
23#include "mount-util.h"
24#include "path-util.h"
70a5db58
LP
25#include "rm-rf.h"
26#include "stat-util.h"
27#include "strv.h"
28#include "tmpfile-util.h"
29#include "user-util.h"
30#include "virt.h"
31
32/* Make sure a bad password always results in a 3s delay, no matter what */
33#define BAD_PASSWORD_DELAY_USEC (3 * USEC_PER_SEC)
34
7b78db28
LP
35void password_cache_free(PasswordCache *cache) {
36 if (!cache)
37 return;
38
39 cache->pkcs11_passwords = strv_free_erase(cache->pkcs11_passwords);
40 cache->fido2_passwords = strv_free_erase(cache->fido2_passwords);
41}
42
70a5db58
LP
43int user_record_authenticate(
44 UserRecord *h,
45 UserRecord *secret,
7b78db28 46 PasswordCache *cache,
c8f145ad 47 bool strict_verify) {
70a5db58 48
7b78db28
LP
49 bool need_password = false, need_token = false, need_pin = false, need_protected_authentication_path_permitted = false, need_user_presence_permitted = false,
50 pin_locked = false, pin_incorrect = false, pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false;
70a5db58
LP
51 int r;
52
53 assert(h);
54 assert(secret);
55
56 /* Tries to authenticate a user record with the supplied secrets. i.e. checks whether at least one
57 * supplied plaintext passwords matches a hashed password field of the user record. Or if a
7b78db28 58 * configured PKCS#11 or FIDO2 token is around and can unlock the record.
70a5db58 59 *
7b78db28
LP
60 * Note that the 'cache' parameter is both an input and output parameter: it contains lists of
61 * configured, decrypted PKCS#11/FIDO2 passwords. We typically have to call this function multiple
62 * times over the course of an operation (think: on login we authenticate the host user record, the
63 * record embedded in the LUKS record and the one embedded in $HOME). Hence we keep a list of
64 * passwords we already decrypted, so that we don't have to do the (slow and potentially interactive)
65 * PKCS#11/FIDO2 dance for the relevant token again and again. */
70a5db58
LP
66
67 /* First, let's see if the supplied plain-text passwords work? */
68 r = user_record_test_secret(h, secret);
69 if (r == -ENOKEY) {
70 log_info_errno(r, "None of the supplied plaintext passwords unlocks the user record's hashed passwords.");
71 need_password = true;
72 } else if (r == -ENXIO)
73 log_debug_errno(r, "User record has no hashed passwords, plaintext passwords not tested.");
74 else if (r < 0)
75 return log_error_errno(r, "Failed to validate password of record: %m");
76 else {
77 log_info("Provided password unlocks user record.");
c8f145ad 78 return 1;
70a5db58
LP
79 }
80
7b78db28 81 /* Second, test cached PKCS#11 passwords */
3aeea37d 82 for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) {
70a5db58
LP
83 char **pp;
84
7b78db28
LP
85 STRV_FOREACH(pp, cache->pkcs11_passwords) {
86 r = test_password_one(h->pkcs11_encrypted_key[n].hashed_password, *pp);
70a5db58
LP
87 if (r < 0)
88 return log_error_errno(r, "Failed to check supplied PKCS#11 password: %m");
89 if (r > 0) {
90 log_info("Previously acquired PKCS#11 password unlocks user record.");
c8f145ad 91 return 1;
70a5db58
LP
92 }
93 }
7b78db28
LP
94 }
95
96 /* Third, test cached FIDO2 passwords */
97 for (size_t n = 0; n < h->n_fido2_hmac_salt; n++) {
98 char **pp;
99
100 /* See if any of the previously calculated passwords work */
101 STRV_FOREACH(pp, cache->fido2_passwords) {
102 r = test_password_one(h->fido2_hmac_salt[n].hashed_password, *pp);
103 if (r < 0)
104 return log_error_errno(r, "Failed to check supplied FIDO2 password: %m");
105 if (r > 0) {
106 log_info("Previously acquired FIDO2 password unlocks user record.");
107 return 0;
108 }
109 }
110 }
111
112 /* Fourth, let's see if any of the PKCS#11 security tokens are plugged in and help us */
113 for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) {
114#if HAVE_P11KIT
115 _cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = {
116 .user_record = h,
117 .secret = secret,
118 .encrypted_key = h->pkcs11_encrypted_key + n,
119 };
70a5db58
LP
120
121 r = pkcs11_find_token(data.encrypted_key->uri, pkcs11_callback, &data);
122 switch (r) {
123 case -EAGAIN:
124 need_token = true;
125 break;
126 case -ENOANO:
127 need_pin = true;
128 break;
129 case -ERFKILL:
130 need_protected_authentication_path_permitted = true;
131 break;
132 case -EOWNERDEAD:
133 pin_locked = true;
134 break;
135 case -ENOLCK:
136 pin_incorrect = true;
137 break;
138 case -ETOOMANYREFS:
139 pin_incorrect = pin_incorrect_few_tries_left = true;
140 break;
141 case -EUCLEAN:
142 pin_incorrect = pin_incorrect_few_tries_left = pin_incorrect_one_try_left = true;
143 break;
144 default:
145 if (r < 0)
146 return r;
147
148 r = test_password_one(data.encrypted_key->hashed_password, data.decrypted_password);
149 if (r < 0)
150 return log_error_errno(r, "Failed to test PKCS#11 password: %m");
151 if (r == 0)
152 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Configured PKCS#11 security token %s does not decrypt encrypted key correctly.", data.encrypted_key->uri);
153
154 log_info("Decrypted password from PKCS#11 security token %s unlocks user record.", data.encrypted_key->uri);
155
7b78db28
LP
156 r = strv_extend(&cache->pkcs11_passwords, data.decrypted_password);
157 if (r < 0)
158 return log_oom();
159
160 return 0;
161 }
162#else
163 need_token = true;
164 break;
165#endif
166 }
167
168 /* Fifth, let's see if any of the FIDO2 security tokens are plugged in and help us */
169 for (size_t n = 0; n < h->n_fido2_hmac_salt; n++) {
170#if HAVE_LIBFIDO2
171 _cleanup_(erase_and_freep) char *decrypted_password = NULL;
172
173 r = fido2_use_token(h, secret, h->fido2_hmac_salt + n, &decrypted_password);
174 switch (r) {
175 case -EAGAIN:
176 need_token = true;
177 break;
178 case -ENOANO:
179 need_pin = true;
180 break;
181 case -EOWNERDEAD:
182 pin_locked = true;
183 break;
184 case -ENOLCK:
185 pin_incorrect = true;
186 break;
187 case -EMEDIUMTYPE:
188 need_user_presence_permitted = true;
189 break;
190 case -ENOSTR:
191 token_action_timeout = true;
192 break;
193 default:
194 if (r < 0)
195 return r;
196
197 r = test_password_one(h->fido2_hmac_salt[n].hashed_password, decrypted_password);
198 if (r < 0)
199 return log_error_errno(r, "Failed to test FIDO2 password: %m");
200 if (r == 0)
201 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Configured FIDO2 security token does not decrypt encrypted key correctly.");
202
203 log_info("Decrypted password from FIDO2 security token unlocks user record.");
204
205 r = strv_extend(&cache->fido2_passwords, decrypted_password);
70a5db58
LP
206 if (r < 0)
207 return log_oom();
208
c8f145ad 209 return 1;
70a5db58
LP
210 }
211#else
212 need_token = true;
213 break;
214#endif
215 }
216
217 /* Ordered by "relevance", i.e. the most "important" or "interesting" error condition is returned. */
218 if (pin_incorrect_one_try_left)
219 return -EUCLEAN;
220 if (pin_incorrect_few_tries_left)
221 return -ETOOMANYREFS;
222 if (pin_incorrect)
223 return -ENOLCK;
224 if (pin_locked)
225 return -EOWNERDEAD;
7b78db28
LP
226 if (token_action_timeout)
227 return -ENOSTR;
70a5db58
LP
228 if (need_protected_authentication_path_permitted)
229 return -ERFKILL;
7b78db28
LP
230 if (need_user_presence_permitted)
231 return -EMEDIUMTYPE;
70a5db58
LP
232 if (need_pin)
233 return -ENOANO;
234 if (need_token)
235 return -EBADSLT;
236 if (need_password)
237 return -ENOKEY;
238
7b78db28
LP
239 /* Hmm, this means neither PCKS#11/FIDO2 nor classic hashed passwords were supplied, we cannot
240 * authenticate this reasonably */
c8f145ad
LP
241 if (strict_verify)
242 return log_debug_errno(SYNTHETIC_ERRNO(EKEYREVOKED),
7b78db28 243 "No hashed passwords and no PKCS#11/FIDO2 tokens defined, cannot authenticate user record, refusing.");
c8f145ad
LP
244
245 /* If strict verification is off this means we are possibly in the case where we encountered an
246 * unfixated record, i.e. a synthetic one that accordingly lacks any authentication data. In this
247 * case, allow the authentication to pass for now, so that the second (or third) authentication level
248 * (the ones of the user record in the LUKS header or inside the home directory) will then catch
249 * invalid passwords. The second/third authentication always runs in strict verification mode. */
250 log_debug("No hashed passwords and no PKCS#11 tokens defined in record, cannot authenticate user record. "
251 "Deferring to embedded user record.");
252 return 0;
70a5db58
LP
253}
254
255int home_setup_undo(HomeSetup *setup) {
256 int r = 0, q;
257
258 assert(setup);
259
28a7f106
LP
260 if (setup->root_fd >= 0) {
261 if (setup->do_offline_fitrim) {
262 q = run_fitrim(setup->root_fd);
263 if (q < 0)
264 r = q;
265 }
266
267 setup->root_fd = safe_close(setup->root_fd);
268 }
70a5db58
LP
269
270 if (setup->undo_mount) {
271 q = umount_verbose("/run/systemd/user-home-mount");
272 if (q < 0)
273 r = q;
274 }
275
276 if (setup->undo_dm && setup->crypt_device && setup->dm_name) {
277 q = crypt_deactivate(setup->crypt_device, setup->dm_name);
278 if (q < 0)
279 r = q;
280 }
281
28a7f106
LP
282 if (setup->image_fd >= 0) {
283 if (setup->do_offline_fallocate) {
284 q = run_fallocate(setup->image_fd, NULL);
285 if (q < 0)
286 r = q;
287 }
288
289 setup->image_fd = safe_close(setup->image_fd);
290 }
291
70a5db58
LP
292 setup->undo_mount = false;
293 setup->undo_dm = false;
28a7f106
LP
294 setup->do_offline_fitrim = false;
295 setup->do_offline_fallocate = false;
70a5db58
LP
296
297 setup->dm_name = mfree(setup->dm_name);
298 setup->dm_node = mfree(setup->dm_node);
299
300 setup->loop = loop_device_unref(setup->loop);
301 crypt_free(setup->crypt_device);
302 setup->crypt_device = NULL;
303
304 explicit_bzero_safe(setup->volume_key, setup->volume_key_size);
305 setup->volume_key = mfree(setup->volume_key);
306 setup->volume_key_size = 0;
307
308 return r;
309}
310
311int home_prepare(
312 UserRecord *h,
313 bool already_activated,
7b78db28 314 PasswordCache *cache,
70a5db58
LP
315 HomeSetup *setup,
316 UserRecord **ret_header_home) {
317
318 int r;
319
320 assert(h);
321 assert(setup);
322 assert(!setup->loop);
323 assert(!setup->crypt_device);
324 assert(setup->root_fd < 0);
325 assert(!setup->undo_dm);
326 assert(!setup->undo_mount);
327
328 /* Makes a home directory accessible (through the root_fd file descriptor, not by path!). */
329
330 switch (user_record_storage(h)) {
331
332 case USER_LUKS:
7b78db28 333 return home_prepare_luks(h, already_activated, NULL, cache, setup, ret_header_home);
70a5db58
LP
334
335 case USER_SUBVOLUME:
336 case USER_DIRECTORY:
337 r = home_prepare_directory(h, already_activated, setup);
338 break;
339
340 case USER_FSCRYPT:
7b78db28 341 r = home_prepare_fscrypt(h, already_activated, cache, setup);
70a5db58
LP
342 break;
343
344 case USER_CIFS:
345 r = home_prepare_cifs(h, already_activated, setup);
346 break;
347
348 default:
349 return log_error_errno(SYNTHETIC_ERRNO(ENOLINK), "Processing home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
350 }
351
352 if (r < 0)
353 return r;
354
355 if (ret_header_home)
356 *ret_header_home = NULL;
357
358 return r;
359}
360
361int home_sync_and_statfs(int root_fd, struct statfs *ret) {
362 assert(root_fd >= 0);
363
364 /* Let's sync this to disk, so that the disk space reported by fstatfs() below is accurate (for file
365 * systems such as btrfs where this is determined lazily). */
366
367 if (syncfs(root_fd) < 0)
368 return log_error_errno(errno, "Failed to synchronize file system: %m");
369
370 if (ret)
371 if (fstatfs(root_fd, ret) < 0)
372 return log_error_errno(errno, "Failed to statfs() file system: %m");
373
374 log_info("Synchronized disk.");
375
376 return 0;
377}
378
379static int read_identity_file(int root_fd, JsonVariant **ret) {
380 _cleanup_(fclosep) FILE *identity_file = NULL;
381 _cleanup_close_ int identity_fd = -1;
382 unsigned line, column;
383 int r;
384
385 assert(root_fd >= 0);
386 assert(ret);
387
388 identity_fd = openat(root_fd, ".identity", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
389 if (identity_fd < 0)
390 return log_error_errno(errno, "Failed to open .identity file in home directory: %m");
391
392 r = fd_verify_regular(identity_fd);
393 if (r < 0)
394 return log_error_errno(r, "Embedded identity file is not a regular file, refusing: %m");
395
4fa744a3 396 identity_file = take_fdopen(&identity_fd, "r");
70a5db58
LP
397 if (!identity_file)
398 return log_oom();
399
70a5db58
LP
400 r = json_parse_file(identity_file, ".identity", JSON_PARSE_SENSITIVE, ret, &line, &column);
401 if (r < 0)
402 return log_error_errno(r, "[.identity:%u:%u] Failed to parse JSON data: %m", line, column);
403
404 log_info("Read embedded .identity file.");
405
406 return 0;
407}
408
409static int write_identity_file(int root_fd, JsonVariant *v, uid_t uid) {
410 _cleanup_(json_variant_unrefp) JsonVariant *normalized = NULL;
411 _cleanup_(fclosep) FILE *identity_file = NULL;
412 _cleanup_close_ int identity_fd = -1;
413 _cleanup_free_ char *fn = NULL;
414 int r;
415
416 assert(root_fd >= 0);
417 assert(v);
418
419 normalized = json_variant_ref(v);
420
421 r = json_variant_normalize(&normalized);
422 if (r < 0)
423 log_warning_errno(r, "Failed to normalize user record, ignoring: %m");
424
425 r = tempfn_random(".identity", NULL, &fn);
426 if (r < 0)
427 return r;
428
429 identity_fd = openat(root_fd, fn, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
430 if (identity_fd < 0)
431 return log_error_errno(errno, "Failed to create .identity file in home directory: %m");
432
4fa744a3 433 identity_file = take_fdopen(&identity_fd, "w");
70a5db58
LP
434 if (!identity_file) {
435 r = log_oom();
436 goto fail;
437 }
438
70a5db58
LP
439 json_variant_dump(normalized, JSON_FORMAT_PRETTY, identity_file, NULL);
440
441 r = fflush_and_check(identity_file);
442 if (r < 0) {
443 log_error_errno(r, "Failed to write .identity file: %m");
444 goto fail;
445 }
446
447 if (fchown(fileno(identity_file), uid, uid) < 0) {
448 log_error_errno(r, "Failed to change ownership of identity file: %m");
449 goto fail;
450 }
451
452 if (renameat(root_fd, fn, root_fd, ".identity") < 0) {
453 r = log_error_errno(errno, "Failed to move identity file into place: %m");
454 goto fail;
455 }
456
457 log_info("Wrote embedded .identity file.");
458
459 return 0;
460
461fail:
462 (void) unlinkat(root_fd, fn, 0);
463 return r;
464}
465
466int home_load_embedded_identity(
467 UserRecord *h,
468 int root_fd,
469 UserRecord *header_home,
470 UserReconcileMode mode,
7b78db28 471 PasswordCache *cache,
70a5db58
LP
472 UserRecord **ret_embedded_home,
473 UserRecord **ret_new_home) {
474
475 _cleanup_(user_record_unrefp) UserRecord *embedded_home = NULL, *intermediate_home = NULL, *new_home = NULL;
476 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
477 int r;
478
479 assert(h);
480 assert(root_fd >= 0);
481
482 r = read_identity_file(root_fd, &v);
483 if (r < 0)
484 return r;
485
486 embedded_home = user_record_new();
487 if (!embedded_home)
488 return log_oom();
489
490 r = user_record_load(embedded_home, v, USER_RECORD_LOAD_EMBEDDED);
491 if (r < 0)
492 return r;
493
494 if (!user_record_compatible(h, embedded_home))
80ace4f2 495 return log_error_errno(SYNTHETIC_ERRNO(EREMCHG), "Embedded home record not compatible with host record, refusing.");
70a5db58
LP
496
497 /* Insist that credentials the user supplies also unlocks any embedded records. */
7b78db28 498 r = user_record_authenticate(embedded_home, h, cache, /* strict_verify= */ true);
70a5db58
LP
499 if (r < 0)
500 return r;
c8f145ad 501 assert(r > 0); /* Insist that a password was verified */
70a5db58
LP
502
503 /* At this point we have three records to deal with:
504 *
505 * · The record we got passed from the host
506 * · The record included in the LUKS header (only if LUKS is used)
507 * · The record in the home directory itself (~.identity)
508 *
509 * Now we have to reconcile all three, and let the newest one win. */
510
511 if (header_home) {
512 /* Note we relax the requirements here. Instead of insisting that the host record is strictly
513 * newer, let's also be OK if its equally new. If it is, we'll however insist that the
514 * embedded record must be newer, so that we update at least one of the two. */
515
516 r = user_record_reconcile(h, header_home, mode == USER_RECONCILE_REQUIRE_NEWER ? USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL : mode, &intermediate_home);
517 if (r == -EREMCHG) /* this was supposed to be checked earlier already, but let's check this again */
518 return log_error_errno(r, "Identity stored on host and in header don't match, refusing.");
519 if (r == -ESTALE)
520 return log_error_errno(r, "Embedded identity record is newer than supplied record, refusing.");
521 if (r < 0)
522 return log_error_errno(r, "Failed to reconcile host and header identities: %m");
523 if (r == USER_RECONCILE_EMBEDDED_WON)
524 log_info("Reconciling header user identity completed (header version was newer).");
525 else if (r == USER_RECONCILE_HOST_WON) {
526 log_info("Reconciling header user identity completed (host version was newer).");
527
528 if (mode == USER_RECONCILE_REQUIRE_NEWER) /* Host version is newer than the header
529 * version, hence we'll update
530 * something. This means we can relax the
531 * requirements on the embedded
532 * identity. */
533 mode = USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL;
534 } else {
535 assert(r == USER_RECONCILE_IDENTICAL);
536 log_info("Reconciling user identities completed (host and header version were identical).");
537 }
538
539 h = intermediate_home;
540 }
541
542 r = user_record_reconcile(h, embedded_home, mode, &new_home);
543 if (r == -EREMCHG)
544 return log_error_errno(r, "Identity stored on host and in home don't match, refusing.");
545 if (r == -ESTALE)
546 return log_error_errno(r, "Embedded identity record is equally new or newer than supplied record, refusing.");
547 if (r < 0)
548 return log_error_errno(r, "Failed to reconcile host and embedded identities: %m");
549 if (r == USER_RECONCILE_EMBEDDED_WON)
550 log_info("Reconciling embedded user identity completed (embedded version was newer).");
551 else if (r == USER_RECONCILE_HOST_WON)
552 log_info("Reconciling embedded user identity completed (host version was newer).");
553 else {
554 assert(r == USER_RECONCILE_IDENTICAL);
555 log_info("Reconciling embedded user identity completed (host and embedded version were identical).");
556 }
557
558 if (ret_embedded_home)
559 *ret_embedded_home = TAKE_PTR(embedded_home);
560
561 if (ret_new_home)
562 *ret_new_home = TAKE_PTR(new_home);
563
564 return 0;
565}
566
567int home_store_embedded_identity(UserRecord *h, int root_fd, uid_t uid, UserRecord *old_home) {
568 _cleanup_(user_record_unrefp) UserRecord *embedded = NULL;
569 int r;
570
571 assert(h);
572 assert(root_fd >= 0);
573 assert(uid_is_valid(uid));
574
575 r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED, &embedded);
576 if (r < 0)
577 return log_error_errno(r, "Failed to determine new embedded record: %m");
578
579 if (old_home && user_record_equal(old_home, embedded)) {
580 log_debug("Not updating embedded home record.");
581 return 0;
582 }
583
584 /* The identity has changed, let's update it in the image */
585 r = write_identity_file(root_fd, embedded->json, h->uid);
586 if (r < 0)
587 return r;
588
589 return 1;
590}
591
592static const char *file_system_type_fd(int fd) {
593 struct statfs sfs;
594
595 assert(fd >= 0);
596
597 if (fstatfs(fd, &sfs) < 0) {
598 log_debug_errno(errno, "Failed to statfs(): %m");
599 return NULL;
600 }
601
602 if (is_fs_type(&sfs, XFS_SB_MAGIC))
603 return "xfs";
604 if (is_fs_type(&sfs, EXT4_SUPER_MAGIC))
605 return "ext4";
606 if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC))
607 return "btrfs";
608
609 return NULL;
610}
611
612int home_extend_embedded_identity(UserRecord *h, UserRecord *used, HomeSetup *setup) {
613 int r;
614
615 assert(h);
616 assert(used);
617 assert(setup);
618
619 r = user_record_add_binding(
620 h,
621 user_record_storage(used),
622 user_record_image_path(used),
623 setup->found_partition_uuid,
624 setup->found_luks_uuid,
625 setup->found_fs_uuid,
626 setup->crypt_device ? crypt_get_cipher(setup->crypt_device) : NULL,
627 setup->crypt_device ? crypt_get_cipher_mode(setup->crypt_device) : NULL,
628 setup->crypt_device ? luks_volume_key_size_convert(setup->crypt_device) : UINT64_MAX,
629 file_system_type_fd(setup->root_fd),
630 user_record_home_directory(used),
631 used->uid,
632 (gid_t) used->uid);
633 if (r < 0)
634 return log_error_errno(r, "Failed to update binding in record: %m");
635
636 return 0;
637}
638
639static int chown_recursive_directory(int root_fd, uid_t uid) {
640 int r;
641
642 assert(root_fd >= 0);
643 assert(uid_is_valid(uid));
644
645 r = fd_chown_recursive(root_fd, uid, (gid_t) uid, 0777);
646 if (r < 0)
647 return log_error_errno(r, "Failed to change ownership of files and directories: %m");
648 if (r == 0)
649 log_info("Recursive changing of ownership not necessary, skipped.");
650 else
651 log_info("Recursive changing of ownership completed.");
652
653 return 0;
654}
655
656int home_refresh(
657 UserRecord *h,
658 HomeSetup *setup,
659 UserRecord *header_home,
7b78db28 660 PasswordCache *cache,
70a5db58
LP
661 struct statfs *ret_statfs,
662 UserRecord **ret_new_home) {
663
664 _cleanup_(user_record_unrefp) UserRecord *embedded_home = NULL, *new_home = NULL;
665 int r;
666
667 assert(h);
668 assert(setup);
669 assert(ret_new_home);
670
671 /* When activating a home directory, does the identity work: loads the identity from the $HOME
672 * directory, reconciles it with our idea, chown()s everything. */
673
7b78db28 674 r = home_load_embedded_identity(h, setup->root_fd, header_home, USER_RECONCILE_ANY, cache, &embedded_home, &new_home);
70a5db58
LP
675 if (r < 0)
676 return r;
677
678 r = home_store_header_identity_luks(new_home, setup, header_home);
679 if (r < 0)
680 return r;
681
682 r = home_store_embedded_identity(new_home, setup->root_fd, h->uid, embedded_home);
683 if (r < 0)
684 return r;
685
686 r = chown_recursive_directory(setup->root_fd, h->uid);
687 if (r < 0)
688 return r;
689
690 r = home_sync_and_statfs(setup->root_fd, ret_statfs);
691 if (r < 0)
692 return r;
693
694 *ret_new_home = TAKE_PTR(new_home);
695 return 0;
696}
697
698static int home_activate(UserRecord *h, UserRecord **ret_home) {
7b78db28 699 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
700 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
701 int r;
702
703 assert(h);
704
705 if (!h->user_name)
706 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks user name, refusing.");
707 if (!uid_is_valid(h->uid))
708 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks UID, refusing.");
709 if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
710 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Activating home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
711
7b78db28 712 r = user_record_authenticate(h, h, &cache, /* strict_verify= */ false);
70a5db58
LP
713 if (r < 0)
714 return r;
715
716 r = user_record_test_home_directory_and_warn(h);
717 if (r < 0)
718 return r;
719 if (r == USER_TEST_MOUNTED)
720 return log_error_errno(SYNTHETIC_ERRNO(EALREADY), "Home directory %s is already mounted, refusing.", user_record_home_directory(h));
721
722 r = user_record_test_image_path_and_warn(h);
723 if (r < 0)
724 return r;
725 if (r == USER_TEST_ABSENT)
726 return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Image path %s is missing, refusing.", user_record_image_path(h));
727
728 switch (user_record_storage(h)) {
729
730 case USER_LUKS:
7b78db28 731 r = home_activate_luks(h, &cache, &new_home);
70a5db58
LP
732 if (r < 0)
733 return r;
734
735 break;
736
737 case USER_SUBVOLUME:
738 case USER_DIRECTORY:
739 case USER_FSCRYPT:
7b78db28 740 r = home_activate_directory(h, &cache, &new_home);
70a5db58
LP
741 if (r < 0)
742 return r;
743
744 break;
745
746 case USER_CIFS:
7b78db28 747 r = home_activate_cifs(h, &cache, &new_home);
70a5db58
LP
748 if (r < 0)
749 return r;
750
751 break;
752
753 default:
754 assert_not_reached("unexpected type");
755 }
756
757 /* Note that the returned object might either be a reference to an updated version of the existing
758 * home object, or a reference to a newly allocated home object. The caller has to be able to deal
759 * with both, and consider the old object out-of-date. */
760 if (user_record_equal(h, new_home)) {
761 *ret_home = NULL;
762 return 0; /* no identity change */
763 }
764
765 *ret_home = TAKE_PTR(new_home);
766 return 1; /* identity updated */
767}
768
769static int home_deactivate(UserRecord *h, bool force) {
770 bool done = false;
771 int r;
772
773 assert(h);
774
775 if (!h->user_name)
776 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record incomplete, refusing.");
777 if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
778 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Deactivating home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
779
780 r = user_record_test_home_directory_and_warn(h);
781 if (r < 0)
782 return r;
783 if (r == USER_TEST_MOUNTED) {
28a7f106
LP
784 if (user_record_storage(h) == USER_LUKS) {
785 r = home_trim_luks(h);
786 if (r < 0)
787 return r;
788 }
789
70a5db58
LP
790 if (umount2(user_record_home_directory(h), UMOUNT_NOFOLLOW | (force ? MNT_FORCE|MNT_DETACH : 0)) < 0)
791 return log_error_errno(errno, "Failed to unmount %s: %m", user_record_home_directory(h));
792
793 log_info("Unmounting completed.");
794 done = true;
795 } else
796 log_info("Directory %s is already unmounted.", user_record_home_directory(h));
797
798 if (user_record_storage(h) == USER_LUKS) {
799 r = home_deactivate_luks(h);
800 if (r < 0)
801 return r;
802 if (r > 0)
803 done = true;
804 }
805
806 if (!done)
807 return log_error_errno(SYNTHETIC_ERRNO(ENOEXEC), "Home is not active.");
808
809 log_info("Everything completed.");
810 return 0;
811}
812
813static int copy_skel(int root_fd, const char *skel) {
814 int r;
815
816 assert(root_fd >= 0);
817
818 r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE);
819 if (r == -ENOENT) {
820 log_info("Skeleton directory %s missing, ignoring.", skel);
821 return 0;
822 }
823 if (r < 0)
824 return log_error_errno(r, "Failed to copy in %s: %m", skel);
825
826 log_info("Copying in %s completed.", skel);
827 return 0;
828}
829
830static int change_access_mode(int root_fd, mode_t m) {
831 assert(root_fd >= 0);
832
833 if (fchmod(root_fd, m) < 0)
834 return log_error_errno(errno, "Failed to change access mode of top-level directory: %m");
835
836 log_info("Changed top-level directory access mode to 0%o.", m);
837 return 0;
838}
839
840int home_populate(UserRecord *h, int dir_fd) {
841 int r;
842
843 assert(h);
844 assert(dir_fd >= 0);
845
846 r = copy_skel(dir_fd, user_record_skeleton_directory(h));
847 if (r < 0)
848 return r;
849
850 r = home_store_embedded_identity(h, dir_fd, h->uid, NULL);
851 if (r < 0)
852 return r;
853
854 r = chown_recursive_directory(dir_fd, h->uid);
855 if (r < 0)
856 return r;
857
858 r = change_access_mode(dir_fd, user_record_access_mode(h));
859 if (r < 0)
860 return r;
861
862 return 0;
863}
864
865static int user_record_compile_effective_passwords(
866 UserRecord *h,
7b78db28
LP
867 PasswordCache *cache,
868 char ***ret_effective_passwords) {
70a5db58 869
7b78db28 870 _cleanup_(strv_free_erasep) char **effective = NULL;
70a5db58
LP
871 size_t n;
872 char **i;
873 int r;
874
875 assert(h);
7b78db28 876 assert(cache);
70a5db58
LP
877
878 /* We insist on at least one classic hashed password to be defined in addition to any PKCS#11 one, as
879 * a safe fallback, but also to simplify the password changing algorithm: there we require providing
880 * the old literal password only (and do not care for the old PKCS#11 token) */
881
882 if (strv_isempty(h->hashed_password))
883 return log_error_errno(EINVAL, "User record has no hashed passwords, refusing.");
884
885 /* Generates the list of plaintext passwords to propagate to LUKS/fscrypt devices, and checks whether
886 * we have a plaintext password for each hashed one. If we are missing one we'll fail, since we
887 * couldn't sync fscrypt/LUKS to the login account properly. */
888
889 STRV_FOREACH(i, h->hashed_password) {
890 bool found = false;
891 char **j;
892
893 log_debug("Looking for plaintext password for: %s", *i);
894
895 /* Let's scan all provided plaintext passwords */
896 STRV_FOREACH(j, h->password) {
897 r = test_password_one(*i, *j);
898 if (r < 0)
899 return log_error_errno(r, "Failed to test plain text password: %m");
900 if (r > 0) {
901 if (ret_effective_passwords) {
902 r = strv_extend(&effective, *j);
903 if (r < 0)
904 return log_oom();
905 }
906
907 log_debug("Found literal plaintext password.");
908 found = true;
909 break;
910 }
911 }
912
913 if (!found)
914 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Missing plaintext password for defined hashed password");
915 }
916
917 for (n = 0; n < h->n_pkcs11_encrypted_key; n++) {
918#if HAVE_P11KIT
919 _cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = {
920 .user_record = h,
921 .secret = h,
922 .encrypted_key = h->pkcs11_encrypted_key + n,
923 };
924
925 r = pkcs11_find_token(data.encrypted_key->uri, pkcs11_callback, &data);
926 if (r == -EAGAIN)
927 return -EBADSLT;
928 if (r < 0)
929 return r;
930
931 r = test_password_one(data.encrypted_key->hashed_password, data.decrypted_password);
932 if (r < 0)
933 return log_error_errno(r, "Failed to test PKCS#11 password: %m");
934 if (r == 0)
935 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Decrypted password from token is not correct, refusing.");
936
937 if (ret_effective_passwords) {
938 r = strv_extend(&effective, data.decrypted_password);
939 if (r < 0)
940 return log_oom();
941 }
942
7b78db28
LP
943 r = strv_extend(&cache->pkcs11_passwords, data.decrypted_password);
944 if (r < 0)
945 return log_oom();
946#else
947 return -EBADSLT;
948#endif
949 }
950
951 for (n = 0; n < h->n_fido2_hmac_salt; n++) {
952#if HAVE_LIBFIDO2
953 _cleanup_(erase_and_freep) char *decrypted_password = NULL;
954
955 r = fido2_use_token(h, h, h->fido2_hmac_salt + n, &decrypted_password);
956 if (r < 0)
957 return r;
958
959 r = test_password_one(h->fido2_hmac_salt[n].hashed_password, decrypted_password);
960 if (r < 0)
961 return log_error_errno(r, "Failed to test FIDO2 password: %m");
962 if (r == 0)
963 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Decrypted password from token is not correct, refusing.");
964
965 if (ret_effective_passwords) {
966 r = strv_extend(&effective, decrypted_password);
70a5db58
LP
967 if (r < 0)
968 return log_oom();
969 }
7b78db28
LP
970
971 r = strv_extend(&cache->fido2_passwords, decrypted_password);
972 if (r < 0)
973 return log_oom();
70a5db58
LP
974#else
975 return -EBADSLT;
976#endif
977 }
978
979 if (ret_effective_passwords)
980 *ret_effective_passwords = TAKE_PTR(effective);
70a5db58
LP
981
982 return 0;
983}
984
1dfe5de0
LP
985static int determine_default_storage(UserStorage *ret) {
986 UserStorage storage = _USER_STORAGE_INVALID;
987 const char *e;
988 int r;
989
990 assert(ret);
991
992 /* homed tells us via an environment variable which default storage to use */
993 e = getenv("SYSTEMD_HOME_DEFAULT_STORAGE");
994 if (e) {
995 storage = user_storage_from_string(e);
996 if (storage < 0)
997 log_warning("$SYSTEMD_HOME_DEFAULT_STORAGE set to invalid storage type, ignoring: %s", e);
998 else {
999 log_info("Using configured default storage '%s'.", user_storage_to_string(storage));
1000 *ret = storage;
1001 return 0;
1002 }
1003 }
1004
1005 /* When neither user nor admin specified the storage type to use, fix it to be LUKS — unless we run
1006 * in a container where loopback devices and LUKS/DM are not available. Also, if /home is encrypted
1007 * anyway, let's avoid duplicate encryption. Note that we typically default to the assumption of
1008 * "classic" storage for most operations. However, if we create a new home, then let's user LUKS if
1009 * nothing is specified. */
1010
1011 r = detect_container();
1012 if (r < 0)
1013 return log_error_errno(r, "Failed to determine whether we are in a container: %m");
1014 if (r == 0) {
1015 r = path_is_encrypted("/home");
1016 if (r < 0)
1017 log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
1018 if (r <= 0) {
1019 log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
1020 *ret = USER_LUKS;
1021 return 0;
1022 }
1023
1024 log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
1025 } else
1026 log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS));
1027
1028 r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC);
1029 if (r < 0)
1030 log_warning_errno(r, "Failed to determine file system of /home, ignoring: %m");
1031 if (r > 0) {
1032 log_info("/home is on btrfs, using '%s' as storage.", user_storage_to_string(USER_SUBVOLUME));
1033 *ret = USER_SUBVOLUME;
1034 } else {
1035 log_info("/home is on simple file system, using '%s' as storage.", user_storage_to_string(USER_DIRECTORY));
1036 *ret = USER_DIRECTORY;
1037 }
1038
1039 return 0;
1040}
1041
70a5db58 1042static int home_create(UserRecord *h, UserRecord **ret_home) {
7b78db28 1043 _cleanup_(strv_free_erasep) char **effective_passwords = NULL;
70a5db58 1044 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
7b78db28 1045 _cleanup_(password_cache_free) PasswordCache cache = {};
1dfe5de0
LP
1046 UserStorage new_storage = _USER_STORAGE_INVALID;
1047 const char *new_fs = NULL;
70a5db58
LP
1048 int r;
1049
1050 assert(h);
1051
1052 if (!h->user_name)
1053 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks name, refusing.");
1054 if (!uid_is_valid(h->uid))
1055 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks UID, refusing.");
1056
7b78db28 1057 r = user_record_compile_effective_passwords(h, &cache, &effective_passwords);
70a5db58
LP
1058 if (r < 0)
1059 return r;
1060
1061 r = user_record_test_home_directory_and_warn(h);
1062 if (r < 0)
1063 return r;
1064 if (r != USER_TEST_ABSENT)
1065 return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Home directory %s already exists, refusing.", user_record_home_directory(h));
1066
70a5db58 1067 if (h->storage < 0) {
1dfe5de0 1068 r = determine_default_storage(&new_storage);
70a5db58 1069 if (r < 0)
1dfe5de0
LP
1070 return r;
1071 }
70a5db58 1072
1dfe5de0
LP
1073 if ((h->storage == USER_LUKS ||
1074 (h->storage < 0 && new_storage == USER_LUKS)) &&
1075 !h->file_system_type)
1076 new_fs = getenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE");
70a5db58 1077
1dfe5de0 1078 if (new_storage >= 0 || new_fs) {
70a5db58
LP
1079 r = user_record_add_binding(
1080 h,
1081 new_storage,
1082 NULL,
1083 SD_ID128_NULL,
1084 SD_ID128_NULL,
1085 SD_ID128_NULL,
1086 NULL,
1087 NULL,
1088 UINT64_MAX,
1dfe5de0 1089 new_fs,
70a5db58
LP
1090 NULL,
1091 UID_INVALID,
1092 GID_INVALID);
1093 if (r < 0)
1094 return log_error_errno(r, "Failed to change storage type to LUKS: %m");
70a5db58
LP
1095 }
1096
1097 r = user_record_test_image_path_and_warn(h);
1098 if (r < 0)
1099 return r;
1100 if (!IN_SET(r, USER_TEST_ABSENT, USER_TEST_UNDEFINED, USER_TEST_MAYBE))
1101 return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Image path %s already exists, refusing.", user_record_image_path(h));
1102
1103 switch (user_record_storage(h)) {
1104
1105 case USER_LUKS:
7b78db28 1106 r = home_create_luks(h, &cache, effective_passwords, &new_home);
70a5db58
LP
1107 break;
1108
1109 case USER_DIRECTORY:
1110 case USER_SUBVOLUME:
1111 r = home_create_directory_or_subvolume(h, &new_home);
1112 break;
1113
1114 case USER_FSCRYPT:
1115 r = home_create_fscrypt(h, effective_passwords, &new_home);
1116 break;
1117
1118 case USER_CIFS:
1119 r = home_create_cifs(h, &new_home);
1120 break;
1121
1122 default:
1123 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
1124 "Creating home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1125 }
1126 if (r < 0)
1127 return r;
1128
1129 if (user_record_equal(h, new_home)) {
1130 *ret_home = NULL;
1131 return 0;
1132 }
1133
1134 *ret_home = TAKE_PTR(new_home);
1135 return 1;
1136}
1137
1138static int home_remove(UserRecord *h) {
1139 bool deleted = false;
1140 const char *ip, *hd;
1141 int r;
1142
1143 assert(h);
1144
1145 if (!h->user_name)
1146 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks user name, refusing.");
1147 if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
1148 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Removing home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1149
1150 hd = user_record_home_directory(h);
1151
1152 r = user_record_test_home_directory_and_warn(h);
1153 if (r < 0)
1154 return r;
1155 if (r == USER_TEST_MOUNTED)
1156 return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Directory %s is still mounted, refusing.", hd);
1157
1158 assert(hd);
1159
1160 r = user_record_test_image_path_and_warn(h);
1161 if (r < 0)
1162 return r;
1163
1164 ip = user_record_image_path(h);
1165
1166 switch (user_record_storage(h)) {
1167
1168 case USER_LUKS: {
1169 struct stat st;
1170
1171 assert(ip);
1172
1173 if (stat(ip, &st) < 0) {
6b8664cb 1174 if (errno != ENOENT)
80ace4f2 1175 return log_error_errno(errno, "Failed to stat() %s: %m", ip);
70a5db58
LP
1176
1177 } else {
1178 if (S_ISREG(st.st_mode)) {
1179 if (unlink(ip) < 0) {
1180 if (errno != ENOENT)
1181 return log_error_errno(errno, "Failed to remove %s: %m", ip);
1182 } else
1183 deleted = true;
1184
1185 } else if (S_ISBLK(st.st_mode))
1186 log_info("Not removing file system on block device %s.", ip);
1187 else
1188 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Image file %s is neither block device, nor regular, refusing removal.", ip);
1189 }
1190
1191 break;
1192 }
1193
1194 case USER_SUBVOLUME:
1195 case USER_DIRECTORY:
1196 case USER_FSCRYPT:
1197 assert(ip);
1198
1199 r = rm_rf(ip, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
1200 if (r < 0) {
1201 if (r != -ENOENT)
1202 return log_warning_errno(r, "Failed to remove %s: %m", ip);
1203 } else
1204 deleted = true;
1205
1206 /* If the image path and the home directory are the same invalidate the home directory, so
1207 * that we don't remove it anymore */
1208 if (path_equal(ip, hd))
1209 hd = NULL;
1210
1211 break;
1212
1213 case USER_CIFS:
1214 /* Nothing else to do here: we won't remove remote stuff. */
1215 log_info("Not removing home directory on remote server.");
1216 break;
1217
1218 default:
1219 assert_not_reached("unknown storage type");
1220 }
1221
1222 if (hd) {
1223 if (rmdir(hd) < 0) {
1224 if (errno != ENOENT)
1225 return log_error_errno(errno, "Failed to remove %s, ignoring: %m", hd);
1226 } else
1227 deleted = true;
1228 }
1229
1230 if (deleted)
1231 log_info("Everything completed.");
e4ff0393
FS
1232 else
1233 return log_notice_errno(SYNTHETIC_ERRNO(EALREADY),
1234 "Nothing to remove.");
70a5db58
LP
1235
1236 return 0;
1237}
1238
1239static int home_validate_update(UserRecord *h, HomeSetup *setup) {
1240 bool has_mount = false;
1241 int r;
1242
1243 assert(h);
1244 assert(setup);
1245
1246 if (!h->user_name)
1247 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks user name, refusing.");
1248 if (!uid_is_valid(h->uid))
1249 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks UID, refusing.");
1250 if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
1251 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Processing home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1252
1253 r = user_record_test_home_directory_and_warn(h);
1254 if (r < 0)
1255 return r;
1256
1257 has_mount = r == USER_TEST_MOUNTED;
1258
1259 r = user_record_test_image_path_and_warn(h);
1260 if (r < 0)
1261 return r;
1262 if (r == USER_TEST_ABSENT)
1263 return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Image path %s does not exist", user_record_image_path(h));
1264
1265 switch (user_record_storage(h)) {
1266
1267 case USER_DIRECTORY:
1268 case USER_SUBVOLUME:
1269 case USER_FSCRYPT:
1270 case USER_CIFS:
1271 break;
1272
1273 case USER_LUKS: {
1274 r = home_validate_update_luks(h, setup);
1275 if (r < 0)
1276 return r;
1277 if ((r > 0) != has_mount)
1278 return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Home mount incompletely set up.");
1279
1280 break;
1281 }
1282
1283 default:
1284 assert_not_reached("unexpected storage type");
1285 }
1286
1287 return has_mount; /* return true if the home record is already active */
1288}
1289
1290static int home_update(UserRecord *h, UserRecord **ret) {
1291 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL, *header_home = NULL, *embedded_home = NULL;
70a5db58 1292 _cleanup_(home_setup_undo) HomeSetup setup = HOME_SETUP_INIT;
7b78db28 1293 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
1294 bool already_activated = false;
1295 int r;
1296
1297 assert(h);
1298 assert(ret);
1299
7b78db28 1300 r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
70a5db58
LP
1301 if (r < 0)
1302 return r;
c8f145ad 1303 assert(r > 0); /* Insist that a password was verified */
70a5db58
LP
1304
1305 r = home_validate_update(h, &setup);
1306 if (r < 0)
1307 return r;
1308
1309 already_activated = r > 0;
1310
7b78db28 1311 r = home_prepare(h, already_activated, &cache, &setup, &header_home);
70a5db58
LP
1312 if (r < 0)
1313 return r;
1314
7b78db28 1315 r = home_load_embedded_identity(h, setup.root_fd, header_home, USER_RECONCILE_REQUIRE_NEWER, &cache, &embedded_home, &new_home);
70a5db58
LP
1316 if (r < 0)
1317 return r;
1318
1319 r = home_store_header_identity_luks(new_home, &setup, header_home);
1320 if (r < 0)
1321 return r;
1322
1323 r = home_store_embedded_identity(new_home, setup.root_fd, h->uid, embedded_home);
1324 if (r < 0)
1325 return r;
1326
1327 r = home_extend_embedded_identity(new_home, h, &setup);
1328 if (r < 0)
1329 return r;
1330
1331 r = home_sync_and_statfs(setup.root_fd, NULL);
1332 if (r < 0)
1333 return r;
1334
1335 r = home_setup_undo(&setup);
1336 if (r < 0)
1337 return r;
1338
1339 log_info("Everything completed.");
1340
1341 *ret = TAKE_PTR(new_home);
1342 return 0;
1343}
1344
1345static int home_resize(UserRecord *h, UserRecord **ret) {
1346 _cleanup_(home_setup_undo) HomeSetup setup = HOME_SETUP_INIT;
7b78db28 1347 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
1348 bool already_activated = false;
1349 int r;
1350
1351 assert(h);
1352 assert(ret);
1353
1354 if (h->disk_size == UINT64_MAX)
1355 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No target size specified, refusing.");
1356
7b78db28 1357 r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
70a5db58
LP
1358 if (r < 0)
1359 return r;
c8f145ad 1360 assert(r > 0); /* Insist that a password was verified */
70a5db58
LP
1361
1362 r = home_validate_update(h, &setup);
1363 if (r < 0)
1364 return r;
1365
1366 already_activated = r > 0;
1367
1368 switch (user_record_storage(h)) {
1369
1370 case USER_LUKS:
7b78db28 1371 return home_resize_luks(h, already_activated, &cache, &setup, ret);
70a5db58
LP
1372
1373 case USER_DIRECTORY:
1374 case USER_SUBVOLUME:
1375 case USER_FSCRYPT:
7b78db28 1376 return home_resize_directory(h, already_activated, &cache, &setup, ret);
70a5db58
LP
1377
1378 default:
1379 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Resizing home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1380 }
1381}
1382
1383static int home_passwd(UserRecord *h, UserRecord **ret_home) {
1384 _cleanup_(user_record_unrefp) UserRecord *header_home = NULL, *embedded_home = NULL, *new_home = NULL;
7b78db28 1385 _cleanup_(strv_free_erasep) char **effective_passwords = NULL;
70a5db58 1386 _cleanup_(home_setup_undo) HomeSetup setup = HOME_SETUP_INIT;
7b78db28 1387 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
1388 bool already_activated = false;
1389 int r;
1390
1391 assert(h);
1392 assert(ret_home);
1393
1394 if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
1395 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Changing password of home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1396
7b78db28 1397 r = user_record_compile_effective_passwords(h, &cache, &effective_passwords);
70a5db58
LP
1398 if (r < 0)
1399 return r;
1400
1401 r = home_validate_update(h, &setup);
1402 if (r < 0)
1403 return r;
1404
1405 already_activated = r > 0;
1406
7b78db28 1407 r = home_prepare(h, already_activated, &cache, &setup, &header_home);
70a5db58
LP
1408 if (r < 0)
1409 return r;
1410
7b78db28 1411 r = home_load_embedded_identity(h, setup.root_fd, header_home, USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL, &cache, &embedded_home, &new_home);
70a5db58
LP
1412 if (r < 0)
1413 return r;
1414
1415 switch (user_record_storage(h)) {
1416
1417 case USER_LUKS:
7b78db28 1418 r = home_passwd_luks(h, &setup, &cache, effective_passwords);
70a5db58
LP
1419 if (r < 0)
1420 return r;
1421 break;
1422
1423 case USER_FSCRYPT:
7b78db28 1424 r = home_passwd_fscrypt(h, &setup, &cache, effective_passwords);
70a5db58
LP
1425 if (r < 0)
1426 return r;
1427 break;
1428
1429 default:
1430 break;
1431 }
1432
1433 r = home_store_header_identity_luks(new_home, &setup, header_home);
1434 if (r < 0)
1435 return r;
1436
1437 r = home_store_embedded_identity(new_home, setup.root_fd, h->uid, embedded_home);
1438 if (r < 0)
1439 return r;
1440
1441 r = home_extend_embedded_identity(new_home, h, &setup);
1442 if (r < 0)
1443 return r;
1444
1445 r = home_sync_and_statfs(setup.root_fd, NULL);
1446 if (r < 0)
1447 return r;
1448
1449 r = home_setup_undo(&setup);
1450 if (r < 0)
1451 return r;
1452
1453 log_info("Everything completed.");
1454
1455 *ret_home = TAKE_PTR(new_home);
1456 return 1;
1457}
1458
1459static int home_inspect(UserRecord *h, UserRecord **ret_home) {
1460 _cleanup_(user_record_unrefp) UserRecord *header_home = NULL, *new_home = NULL;
1461 _cleanup_(home_setup_undo) HomeSetup setup = HOME_SETUP_INIT;
7b78db28 1462 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
1463 bool already_activated = false;
1464 int r;
1465
1466 assert(h);
1467 assert(ret_home);
1468
7b78db28 1469 r = user_record_authenticate(h, h, &cache, /* strict_verify= */ false);
70a5db58
LP
1470 if (r < 0)
1471 return r;
1472
1473 r = home_validate_update(h, &setup);
1474 if (r < 0)
1475 return r;
1476
1477 already_activated = r > 0;
1478
7b78db28 1479 r = home_prepare(h, already_activated, &cache, &setup, &header_home);
70a5db58
LP
1480 if (r < 0)
1481 return r;
1482
7b78db28 1483 r = home_load_embedded_identity(h, setup.root_fd, header_home, USER_RECONCILE_ANY, &cache, NULL, &new_home);
70a5db58
LP
1484 if (r < 0)
1485 return r;
1486
1487 r = home_extend_embedded_identity(new_home, h, &setup);
1488 if (r < 0)
1489 return r;
1490
1491 r = home_setup_undo(&setup);
1492 if (r < 0)
1493 return r;
1494
1495 log_info("Everything completed.");
1496
1497 *ret_home = TAKE_PTR(new_home);
1498 return 1;
1499}
1500
1501static int home_lock(UserRecord *h) {
1502 int r;
1503
1504 assert(h);
1505
1506 if (!h->user_name)
1507 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record incomplete, refusing.");
1508 if (user_record_storage(h) != USER_LUKS)
1509 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Locking home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1510
1511 r = user_record_test_home_directory_and_warn(h);
1512 if (r < 0)
1513 return r;
1514 if (r != USER_TEST_MOUNTED)
1515 return log_error_errno(SYNTHETIC_ERRNO(ENOEXEC), "Home directory of %s is not mounted, can't lock.", h->user_name);
1516
1517 r = home_lock_luks(h);
1518 if (r < 0)
1519 return r;
1520
1521 log_info("Everything completed.");
1522 return 1;
1523}
1524
1525static int home_unlock(UserRecord *h) {
7b78db28 1526 _cleanup_(password_cache_free) PasswordCache cache = {};
70a5db58
LP
1527 int r;
1528
1529 assert(h);
1530
1531 if (!h->user_name)
1532 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record incomplete, refusing.");
1533 if (user_record_storage(h) != USER_LUKS)
1534 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Unlocking home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
1535
1536 /* Note that we don't check if $HOME is actually mounted, since we want to avoid disk accesses on
1537 * that mount until we have resumed the device. */
1538
7b78db28 1539 r = user_record_authenticate(h, h, &cache, /* strict_verify= */ false);
70a5db58
LP
1540 if (r < 0)
1541 return r;
1542
7b78db28 1543 r = home_unlock_luks(h, &cache);
70a5db58
LP
1544 if (r < 0)
1545 return r;
1546
1547 log_info("Everything completed.");
1548 return 1;
1549}
1550
1551static int run(int argc, char *argv[]) {
1552 _cleanup_(user_record_unrefp) UserRecord *home = NULL, *new_home = NULL;
1553 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1554 _cleanup_(fclosep) FILE *opened_file = NULL;
1555 unsigned line = 0, column = 0;
1556 const char *json_path = NULL;
1557 FILE *json_file;
1558 usec_t start;
1559 int r;
1560
1561 start = now(CLOCK_MONOTONIC);
1562
1563 log_setup_service();
1564
1565 umask(0022);
1566
1567 if (argc < 2 || argc > 3)
1568 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes one or two arguments.");
1569
1570 if (argc > 2) {
1571 json_path = argv[2];
1572
1573 opened_file = fopen(json_path, "re");
1574 if (!opened_file)
1575 return log_error_errno(errno, "Failed to open %s: %m", json_path);
1576
1577 json_file = opened_file;
1578 } else {
1579 json_path = "<stdin>";
1580 json_file = stdin;
1581 }
1582
1583 r = json_parse_file(json_file, json_path, JSON_PARSE_SENSITIVE, &v, &line, &column);
1584 if (r < 0)
1585 return log_error_errno(r, "[%s:%u:%u] Failed to parse JSON data: %m", json_path, line, column);
1586
1587 home = user_record_new();
1588 if (!home)
1589 return log_oom();
1590
1591 r = user_record_load(home, v, USER_RECORD_LOAD_FULL|USER_RECORD_LOG);
1592 if (r < 0)
1593 return r;
1594
1595 /* Well known return values of these operations, that systemd-homed knows and converts to proper D-Bus errors:
1596 *
162392b7
ZJS
1597 * EMSGSIZE → file systems of this type cannot be shrunk
1598 * ETXTBSY → file systems of this type can only be shrunk offline
70a5db58
LP
1599 * ERANGE → file system size too small
1600 * ENOLINK → system does not support selected storage backend
1601 * EPROTONOSUPPORT → system does not support selected file system
1602 * ENOTTY → operation not support on this storage
1603 * ESOCKTNOSUPPORT → operation not support on this file system
1604 * ENOKEY → password incorrect (or not sufficient, or not supplied)
1605 * EBADSLT → similar, but PKCS#11 device is defined and might be able to provide password, if it was plugged in which it is not
7b78db28 1606 * ENOANO → suitable PKCS#11/FIDO2 device found, but PIN is missing to unlock it
70a5db58 1607 * ERFKILL → suitable PKCS#11 device found, but OK to ask for on-device interactive authentication not given
7b78db28
LP
1608 * EMEDIUMTYPE → suitable FIDO2 device found, but OK to ask for user presence not given
1609 * ENOSTR → suitable FIDO2 device found, but user didn't react to action request on token quickly enough
1610 * EOWNERDEAD → suitable PKCS#11/FIDO2 device found, but its PIN is locked
1611 * ENOLCK → suitable PKCS#11/FIDO2 device found, but PIN incorrect
70a5db58
LP
1612 * ETOOMANYREFS → suitable PKCS#11 device found, but PIN incorrect, and only few tries left
1613 * EUCLEAN → suitable PKCS#11 device found, but PIN incorrect, and only one try left
1614 * EBUSY → file system is currently active
1615 * ENOEXEC → file system is currently not active
1616 * ENOSPC → not enough disk space for operation
cbffdcec 1617 * EKEYREVOKED → user record has not suitable hashed password or pkcs#11 entry, we cannot authenticate
70a5db58
LP
1618 */
1619
1620 if (streq(argv[1], "activate"))
1621 r = home_activate(home, &new_home);
1622 else if (streq(argv[1], "deactivate"))
1623 r = home_deactivate(home, false);
1624 else if (streq(argv[1], "deactivate-force"))
1625 r = home_deactivate(home, true);
1626 else if (streq(argv[1], "create"))
1627 r = home_create(home, &new_home);
1628 else if (streq(argv[1], "remove"))
1629 r = home_remove(home);
1630 else if (streq(argv[1], "update"))
1631 r = home_update(home, &new_home);
1632 else if (streq(argv[1], "resize"))
1633 r = home_resize(home, &new_home);
1634 else if (streq(argv[1], "passwd"))
1635 r = home_passwd(home, &new_home);
1636 else if (streq(argv[1], "inspect"))
1637 r = home_inspect(home, &new_home);
1638 else if (streq(argv[1], "lock"))
1639 r = home_lock(home);
1640 else if (streq(argv[1], "unlock"))
1641 r = home_unlock(home);
1642 else
1643 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb '%s'.", argv[1]);
1644 if (r == -ENOKEY && !strv_isempty(home->password)) { /* There were passwords specified but they were incorrect */
1645 usec_t end, n, d;
1646
1647 /* Make sure bad password replies always take at least 3s, and if longer multiples of 3s, so
1648 * that it's not clear how long we actually needed for our calculations. */
1649 n = now(CLOCK_MONOTONIC);
1650 assert(n >= start);
1651
1652 d = usec_sub_unsigned(n, start);
1653 if (d > BAD_PASSWORD_DELAY_USEC)
1654 end = start + DIV_ROUND_UP(d, BAD_PASSWORD_DELAY_USEC) * BAD_PASSWORD_DELAY_USEC;
1655 else
1656 end = start + BAD_PASSWORD_DELAY_USEC;
1657
1658 if (n < end)
1659 (void) usleep(usec_sub_unsigned(end, n));
1660 }
1661 if (r < 0)
1662 return r;
1663
1664 /* We always pass the new record back, regardless if it changed or not. This allows our caller to
1665 * prepare a fresh record, send to us, and only if it works use it without having to keep a local
1666 * copy. */
1667 if (new_home)
1668 json_variant_dump(new_home->json, JSON_FORMAT_NEWLINE, stdout, NULL);
1669
1670 return 0;
1671}
1672
1673DEFINE_MAIN_FUNCTION(run);