]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/user-record-util.c
Merge pull request #15442 from poettering/fido2
[thirdparty/systemd.git] / src / home / user-record-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "errno-util.h"
4 #include "home-util.h"
5 #include "id128-util.h"
6 #include "libcrypt-util.h"
7 #include "mountpoint-util.h"
8 #include "path-util.h"
9 #include "stat-util.h"
10 #include "user-record-util.h"
11 #include "user-util.h"
12
13 int user_record_synthesize(
14 UserRecord *h,
15 const char *user_name,
16 const char *realm,
17 const char *image_path,
18 UserStorage storage,
19 uid_t uid,
20 gid_t gid) {
21
22 _cleanup_free_ char *hd = NULL, *un = NULL, *ip = NULL, *rr = NULL, *user_name_and_realm = NULL;
23 char smid[SD_ID128_STRING_MAX];
24 sd_id128_t mid;
25 int r;
26
27 assert(h);
28 assert(user_name);
29 assert(image_path);
30 assert(IN_SET(storage, USER_LUKS, USER_SUBVOLUME, USER_FSCRYPT, USER_DIRECTORY));
31 assert(uid_is_valid(uid));
32 assert(gid_is_valid(gid));
33
34 /* Fill in a home record from just a username and an image path. */
35
36 if (h->json)
37 return -EBUSY;
38
39 if (!suitable_user_name(user_name))
40 return -EINVAL;
41
42 if (realm) {
43 r = suitable_realm(realm);
44 if (r < 0)
45 return r;
46 if (r == 0)
47 return -EINVAL;
48 }
49
50 if (!suitable_image_path(image_path))
51 return -EINVAL;
52
53 r = sd_id128_get_machine(&mid);
54 if (r < 0)
55 return r;
56
57 un = strdup(user_name);
58 if (!un)
59 return -ENOMEM;
60
61 if (realm) {
62 rr = strdup(realm);
63 if (!rr)
64 return -ENOMEM;
65
66 user_name_and_realm = strjoin(user_name, "@", realm);
67 if (!user_name_and_realm)
68 return -ENOMEM;
69 }
70
71 ip = strdup(image_path);
72 if (!ip)
73 return -ENOMEM;
74
75 hd = path_join("/home/", user_name);
76 if (!hd)
77 return -ENOMEM;
78
79 r = json_build(&h->json,
80 JSON_BUILD_OBJECT(
81 JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(user_name)),
82 JSON_BUILD_PAIR_CONDITION(!!rr, "realm", JSON_BUILD_STRING(realm)),
83 JSON_BUILD_PAIR("disposition", JSON_BUILD_STRING("regular")),
84 JSON_BUILD_PAIR("binding", JSON_BUILD_OBJECT(
85 JSON_BUILD_PAIR(sd_id128_to_string(mid, smid), JSON_BUILD_OBJECT(
86 JSON_BUILD_PAIR("imagePath", JSON_BUILD_STRING(image_path)),
87 JSON_BUILD_PAIR("homeDirectory", JSON_BUILD_STRING(hd)),
88 JSON_BUILD_PAIR("storage", JSON_BUILD_STRING(user_storage_to_string(storage))),
89 JSON_BUILD_PAIR("uid", JSON_BUILD_UNSIGNED(uid)),
90 JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(gid))))))));
91 if (r < 0)
92 return r;
93
94 free_and_replace(h->user_name, un);
95 free_and_replace(h->realm, rr);
96 free_and_replace(h->user_name_and_realm_auto, user_name_and_realm);
97 free_and_replace(h->image_path, ip);
98 free_and_replace(h->home_directory, hd);
99 h->storage = storage;
100 h->uid = uid;
101
102 h->mask = USER_RECORD_REGULAR|USER_RECORD_BINDING;
103 return 0;
104 }
105
106 int group_record_synthesize(GroupRecord *g, UserRecord *h) {
107 _cleanup_free_ char *un = NULL, *rr = NULL, *group_name_and_realm = NULL;
108 char smid[SD_ID128_STRING_MAX];
109 sd_id128_t mid;
110 int r;
111
112 assert(g);
113 assert(h);
114
115 if (g->json)
116 return -EBUSY;
117
118 r = sd_id128_get_machine(&mid);
119 if (r < 0)
120 return r;
121
122 un = strdup(h->user_name);
123 if (!un)
124 return -ENOMEM;
125
126 if (h->realm) {
127 rr = strdup(h->realm);
128 if (!rr)
129 return -ENOMEM;
130
131 group_name_and_realm = strjoin(un, "@", rr);
132 if (!group_name_and_realm)
133 return -ENOMEM;
134 }
135
136 r = json_build(&g->json,
137 JSON_BUILD_OBJECT(
138 JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(un)),
139 JSON_BUILD_PAIR_CONDITION(!!rr, "realm", JSON_BUILD_STRING(rr)),
140 JSON_BUILD_PAIR("binding", JSON_BUILD_OBJECT(
141 JSON_BUILD_PAIR(sd_id128_to_string(mid, smid), JSON_BUILD_OBJECT(
142 JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(user_record_gid(h))))))),
143 JSON_BUILD_PAIR_CONDITION(h->disposition >= 0, "disposition", JSON_BUILD_STRING(user_disposition_to_string(user_record_disposition(h)))),
144 JSON_BUILD_PAIR("status", JSON_BUILD_OBJECT(
145 JSON_BUILD_PAIR(sd_id128_to_string(mid, smid), JSON_BUILD_OBJECT(
146 JSON_BUILD_PAIR("service", JSON_BUILD_STRING("io.systemd.Home"))))))));
147 if (r < 0)
148 return r;
149
150 free_and_replace(g->group_name, un);
151 free_and_replace(g->realm, rr);
152 free_and_replace(g->group_name_and_realm_auto, group_name_and_realm);
153 g->gid = user_record_gid(h);
154 g->disposition = h->disposition;
155
156 g->mask = USER_RECORD_REGULAR|USER_RECORD_BINDING;
157 return 0;
158 }
159
160 int user_record_reconcile(
161 UserRecord *host,
162 UserRecord *embedded,
163 UserReconcileMode mode,
164 UserRecord **ret) {
165
166 int r, result;
167
168 /* Reconciles the identity record stored on the host with the one embedded in a $HOME
169 * directory. Returns the following error codes:
170 *
171 * -EINVAL: one of the records not valid
172 * -REMCHG: identity records are not about the same user
173 * -ESTALE: embedded identity record is equally new or newer than supplied record
174 *
175 * Return the new record to use, which is either the embedded record updated with the host
176 * binding or the host record. In both cases the secret data is stripped. */
177
178 assert(host);
179 assert(embedded);
180
181 /* Make sure both records are initialized */
182 if (!host->json || !embedded->json)
183 return -EINVAL;
184
185 /* Ensure these records actually contain user data */
186 if (!(embedded->mask & host->mask & USER_RECORD_REGULAR))
187 return -EINVAL;
188
189 /* Make sure the user name and realm matches */
190 if (!user_record_compatible(host, embedded))
191 return -EREMCHG;
192
193 /* Embedded identities may not contain secrets or binding info*/
194 if ((embedded->mask & (USER_RECORD_SECRET|USER_RECORD_BINDING)) != 0)
195 return -EINVAL;
196
197 /* The embedded record checked out, let's now figure out which of the two identities we'll consider
198 * in effect from now on. We do this by checking the last change timestamp, and in doubt always let
199 * the embedded data win. */
200 if (host->last_change_usec != UINT64_MAX &&
201 (embedded->last_change_usec == UINT64_MAX || host->last_change_usec > embedded->last_change_usec))
202
203 /* The host version is definitely newer, either because it has a version at all and the
204 * embedded version doesn't or because it is numerically newer. */
205 result = USER_RECONCILE_HOST_WON;
206
207 else if (host->last_change_usec == embedded->last_change_usec) {
208
209 /* The nominal version number of the host and the embedded identity is the same. If so, let's
210 * verify that, and tell the caller if we are ignoring embedded data. */
211
212 r = user_record_masked_equal(host, embedded, USER_RECORD_REGULAR|USER_RECORD_PRIVILEGED|USER_RECORD_PER_MACHINE);
213 if (r < 0)
214 return r;
215 if (r > 0) {
216 if (mode == USER_RECONCILE_REQUIRE_NEWER)
217 return -ESTALE;
218
219 result = USER_RECONCILE_IDENTICAL;
220 } else
221 result = USER_RECONCILE_HOST_WON;
222 } else {
223 _cleanup_(json_variant_unrefp) JsonVariant *extended = NULL;
224 _cleanup_(user_record_unrefp) UserRecord *merged = NULL;
225 JsonVariant *e;
226
227 /* The embedded version is newer */
228
229 if (mode == USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL)
230 return -ESTALE;
231
232 /* Copy in the binding data */
233 extended = json_variant_ref(embedded->json);
234
235 e = json_variant_by_key(host->json, "binding");
236 if (e) {
237 r = json_variant_set_field(&extended, "binding", e);
238 if (r < 0)
239 return r;
240 }
241
242 merged = user_record_new();
243 if (!merged)
244 return -ENOMEM;
245
246 r = user_record_load(merged, extended, USER_RECORD_LOAD_MASK_SECRET);
247 if (r < 0)
248 return r;
249
250 *ret = TAKE_PTR(merged);
251 return USER_RECONCILE_EMBEDDED_WON; /* update */
252 }
253
254 /* Strip out secrets */
255 r = user_record_clone(host, USER_RECORD_LOAD_MASK_SECRET, ret);
256 if (r < 0)
257 return r;
258
259 return result;
260 }
261
262 int user_record_add_binding(
263 UserRecord *h,
264 UserStorage storage,
265 const char *image_path,
266 sd_id128_t partition_uuid,
267 sd_id128_t luks_uuid,
268 sd_id128_t fs_uuid,
269 const char *luks_cipher,
270 const char *luks_cipher_mode,
271 uint64_t luks_volume_key_size,
272 const char *file_system_type,
273 const char *home_directory,
274 uid_t uid,
275 gid_t gid) {
276
277 _cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL;
278 char smid[SD_ID128_STRING_MAX], partition_uuids[37], luks_uuids[37], fs_uuids[37];
279 _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL;
280 sd_id128_t mid;
281 int r;
282
283 assert(h);
284
285 if (!h->json)
286 return -EUNATCH;
287
288 r = sd_id128_get_machine(&mid);
289 if (r < 0)
290 return r;
291 sd_id128_to_string(mid, smid);
292
293 if (image_path) {
294 ip = strdup(image_path);
295 if (!ip)
296 return -ENOMEM;
297 } else if (!h->image_path && storage >= 0) {
298 r = user_record_build_image_path(storage, user_record_user_name_and_realm(h), &ip_auto);
299 if (r < 0)
300 return r;
301 }
302
303 if (home_directory) {
304 hd = strdup(home_directory);
305 if (!hd)
306 return -ENOMEM;
307 }
308
309 if (file_system_type) {
310 fst = strdup(file_system_type);
311 if (!fst)
312 return -ENOMEM;
313 }
314
315 if (luks_cipher) {
316 lc = strdup(luks_cipher);
317 if (!lc)
318 return -ENOMEM;
319 }
320
321 if (luks_cipher_mode) {
322 lcm = strdup(luks_cipher_mode);
323 if (!lcm)
324 return -ENOMEM;
325 }
326
327 r = json_build(&new_binding_entry,
328 JSON_BUILD_OBJECT(
329 JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)),
330 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(id128_to_uuid_string(partition_uuid, partition_uuids))),
331 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(id128_to_uuid_string(luks_uuid, luks_uuids))),
332 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(id128_to_uuid_string(fs_uuid, fs_uuids))),
333 JSON_BUILD_PAIR_CONDITION(!!luks_cipher, "luksCipher", JSON_BUILD_STRING(luks_cipher)),
334 JSON_BUILD_PAIR_CONDITION(!!luks_cipher_mode, "luksCipherMode", JSON_BUILD_STRING(luks_cipher_mode)),
335 JSON_BUILD_PAIR_CONDITION(luks_volume_key_size != UINT64_MAX, "luksVolumeKeySize", JSON_BUILD_UNSIGNED(luks_volume_key_size)),
336 JSON_BUILD_PAIR_CONDITION(!!file_system_type, "fileSystemType", JSON_BUILD_STRING(file_system_type)),
337 JSON_BUILD_PAIR_CONDITION(!!home_directory, "homeDirectory", JSON_BUILD_STRING(home_directory)),
338 JSON_BUILD_PAIR_CONDITION(uid_is_valid(uid), "uid", JSON_BUILD_UNSIGNED(uid)),
339 JSON_BUILD_PAIR_CONDITION(gid_is_valid(gid), "gid", JSON_BUILD_UNSIGNED(gid)),
340 JSON_BUILD_PAIR_CONDITION(storage >= 0, "storage", JSON_BUILD_STRING(user_storage_to_string(storage)))));
341 if (r < 0)
342 return r;
343
344 binding = json_variant_ref(json_variant_by_key(h->json, "binding"));
345 if (binding) {
346 _cleanup_(json_variant_unrefp) JsonVariant *be = NULL;
347
348 /* Merge the new entry with an old one, if that exists */
349 be = json_variant_ref(json_variant_by_key(binding, smid));
350 if (be) {
351 r = json_variant_merge(&be, new_binding_entry);
352 if (r < 0)
353 return r;
354
355 json_variant_unref(new_binding_entry);
356 new_binding_entry = TAKE_PTR(be);
357 }
358 }
359
360 r = json_variant_set_field(&binding, smid, new_binding_entry);
361 if (r < 0)
362 return r;
363
364 r = json_variant_set_field(&h->json, "binding", binding);
365 if (r < 0)
366 return r;
367
368 if (storage >= 0)
369 h->storage = storage;
370
371 if (ip)
372 free_and_replace(h->image_path, ip);
373 if (ip_auto)
374 free_and_replace(h->image_path_auto, ip_auto);
375
376 if (!sd_id128_is_null(partition_uuid))
377 h->partition_uuid = partition_uuid;
378
379 if (!sd_id128_is_null(luks_uuid))
380 h->luks_uuid = luks_uuid;
381
382 if (!sd_id128_is_null(fs_uuid))
383 h->file_system_uuid = fs_uuid;
384
385 if (lc)
386 free_and_replace(h->luks_cipher, lc);
387 if (lcm)
388 free_and_replace(h->luks_cipher_mode, lcm);
389 if (luks_volume_key_size != UINT64_MAX)
390 h->luks_volume_key_size = luks_volume_key_size;
391
392 if (fst)
393 free_and_replace(h->file_system_type, fst);
394 if (hd)
395 free_and_replace(h->home_directory, hd);
396
397 if (uid_is_valid(uid))
398 h->uid = uid;
399 if (gid_is_valid(gid))
400 h->gid = gid;
401
402 h->mask |= USER_RECORD_BINDING;
403 return 1;
404 }
405
406 int user_record_test_home_directory(UserRecord *h) {
407 const char *hd;
408 int r;
409
410 assert(h);
411
412 /* Returns one of USER_TEST_ABSENT, USER_TEST_MOUNTED, USER_TEST_EXISTS on success */
413
414 hd = user_record_home_directory(h);
415 if (!hd)
416 return -ENXIO;
417
418 r = is_dir(hd, false);
419 if (r == -ENOENT)
420 return USER_TEST_ABSENT;
421 if (r < 0)
422 return r;
423 if (r == 0)
424 return -ENOTDIR;
425
426 r = path_is_mount_point(hd, NULL, 0);
427 if (r < 0)
428 return r;
429 if (r > 0)
430 return USER_TEST_MOUNTED;
431
432 /* If the image path and the home directory are identical, then it's OK if the directory is
433 * populated. */
434 if (IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT)) {
435 const char *ip;
436
437 ip = user_record_image_path(h);
438 if (ip && path_equal(ip, hd))
439 return USER_TEST_EXISTS;
440 }
441
442 /* Otherwise it's not OK */
443 r = dir_is_empty(hd);
444 if (r < 0)
445 return r;
446 if (r == 0)
447 return -EBUSY;
448
449 return USER_TEST_EXISTS;
450 }
451
452 int user_record_test_home_directory_and_warn(UserRecord *h) {
453 int r;
454
455 assert(h);
456
457 r = user_record_test_home_directory(h);
458 if (r == -ENXIO)
459 return log_error_errno(r, "User record lacks home directory, refusing.");
460 if (r == -ENOTDIR)
461 return log_error_errno(r, "Home directory %s is not a directory, refusing.", user_record_home_directory(h));
462 if (r == -EBUSY)
463 return log_error_errno(r, "Home directory %s exists, is not mounted but populated, refusing.", user_record_home_directory(h));
464 if (r < 0)
465 return log_error_errno(r, "Failed to test whether the home directory %s exists: %m", user_record_home_directory(h));
466
467 return r;
468 }
469
470 int user_record_test_image_path(UserRecord *h) {
471 const char *ip;
472 struct stat st;
473
474 assert(h);
475
476 if (user_record_storage(h) == USER_CIFS)
477 return USER_TEST_UNDEFINED;
478
479 ip = user_record_image_path(h);
480 if (!ip)
481 return -ENXIO;
482
483 if (stat(ip, &st) < 0) {
484 if (errno == ENOENT)
485 return USER_TEST_ABSENT;
486
487 return -errno;
488 }
489
490 switch (user_record_storage(h)) {
491
492 case USER_LUKS:
493 if (S_ISREG(st.st_mode))
494 return USER_TEST_EXISTS;
495 if (S_ISBLK(st.st_mode)) {
496 /* For block devices we can't really be sure if the device referenced actually is the
497 * fs we look for or some other file system (think: what does /dev/sdb1 refer
498 * to?). Hence, let's return USER_TEST_MAYBE as an ambiguous return value for these
499 * case, except if the device path used is one of the paths that is based on a
500 * filesystem or partition UUID or label, because in those cases we can be sure we
501 * are referring to the right device. */
502
503 if (PATH_STARTSWITH_SET(ip,
504 "/dev/disk/by-uuid/",
505 "/dev/disk/by-partuuid/",
506 "/dev/disk/by-partlabel/",
507 "/dev/disk/by-label/"))
508 return USER_TEST_EXISTS;
509
510 return USER_TEST_MAYBE;
511 }
512
513 return -EBADFD;
514
515 case USER_CLASSIC:
516 case USER_DIRECTORY:
517 case USER_SUBVOLUME:
518 case USER_FSCRYPT:
519 if (S_ISDIR(st.st_mode))
520 return USER_TEST_EXISTS;
521
522 return -ENOTDIR;
523
524 default:
525 assert_not_reached("Unexpected record type");
526 }
527 }
528
529 int user_record_test_image_path_and_warn(UserRecord *h) {
530 int r;
531
532 assert(h);
533
534 r = user_record_test_image_path(h);
535 if (r == -ENXIO)
536 return log_error_errno(r, "User record lacks image path, refusing.");
537 if (r == -EBADFD)
538 return log_error_errno(r, "Image path %s is not a regular file or block device, refusing.", user_record_image_path(h));
539 if (r == -ENOTDIR)
540 return log_error_errno(r, "Image path %s is not a directory, refusing.", user_record_image_path(h));
541 if (r < 0)
542 return log_error_errno(r, "Failed to test whether image path %s exists: %m", user_record_image_path(h));
543
544 return r;
545 }
546
547 int user_record_test_secret(UserRecord *h, UserRecord *secret) {
548 char **i;
549 int r;
550
551 assert(h);
552
553 /* Checks whether any of the specified passwords matches any of the hashed passwords of the entry */
554
555 if (strv_isempty(h->hashed_password))
556 return -ENXIO;
557
558 STRV_FOREACH(i, secret->password) {
559 r = test_password_many(h->hashed_password, *i);
560 if (r < 0)
561 return r;
562 if (r > 0)
563 return 0;
564 }
565
566 return -ENOKEY;
567 }
568
569 int user_record_set_disk_size(UserRecord *h, uint64_t disk_size) {
570 _cleanup_(json_variant_unrefp) JsonVariant *new_per_machine = NULL, *midv = NULL, *midav = NULL, *ne = NULL;
571 _cleanup_free_ JsonVariant **array = NULL;
572 char smid[SD_ID128_STRING_MAX];
573 size_t idx = SIZE_MAX, n;
574 JsonVariant *per_machine;
575 sd_id128_t mid;
576 int r;
577
578 assert(h);
579
580 if (!h->json)
581 return -EUNATCH;
582
583 if (disk_size < USER_DISK_SIZE_MIN || disk_size > USER_DISK_SIZE_MAX)
584 return -ERANGE;
585
586 r = sd_id128_get_machine(&mid);
587 if (r < 0)
588 return r;
589
590 sd_id128_to_string(mid, smid);
591
592 r = json_variant_new_string(&midv, smid);
593 if (r < 0)
594 return r;
595
596 r = json_variant_new_array(&midav, (JsonVariant*[]) { midv }, 1);
597 if (r < 0)
598 return r;
599
600 per_machine = json_variant_by_key(h->json, "perMachine");
601 if (per_machine) {
602 size_t i;
603
604 if (!json_variant_is_array(per_machine))
605 return -EINVAL;
606
607 n = json_variant_elements(per_machine);
608
609 array = new(JsonVariant*, n + 1);
610 if (!array)
611 return -ENOMEM;
612
613 for (i = 0; i < n; i++) {
614 JsonVariant *m;
615
616 array[i] = json_variant_by_index(per_machine, i);
617
618 if (!json_variant_is_object(array[i]))
619 return -EINVAL;
620
621 m = json_variant_by_key(array[i], "matchMachineId");
622 if (!m) {
623 /* No machineId field? Let's ignore this, but invalidate what we found so far */
624 idx = SIZE_MAX;
625 continue;
626 }
627
628 if (json_variant_equal(m, midv) ||
629 json_variant_equal(m, midav)) {
630 /* Matches exactly what we are looking for. Let's use this */
631 idx = i;
632 continue;
633 }
634
635 r = per_machine_id_match(m, JSON_PERMISSIVE);
636 if (r < 0)
637 return r;
638 if (r > 0)
639 /* Also matches what we are looking for, but with a broader match. In this
640 * case let's ignore this entry, and add a new specific one to the end. */
641 idx = SIZE_MAX;
642 }
643
644 if (idx == SIZE_MAX)
645 idx = n++; /* Nothing suitable found, place new entry at end */
646 else
647 ne = json_variant_ref(array[idx]);
648
649 } else {
650 array = new(JsonVariant*, 1);
651 if (!array)
652 return -ENOMEM;
653
654 idx = 0;
655 n = 1;
656 }
657
658 if (!ne) {
659 r = json_variant_set_field(&ne, "matchMachineId", midav);
660 if (r < 0)
661 return r;
662 }
663
664 r = json_variant_set_field_unsigned(&ne, "diskSize", disk_size);
665 if (r < 0)
666 return r;
667
668 assert(idx < n);
669 array[idx] = ne;
670
671 r = json_variant_new_array(&new_per_machine, array, n);
672 if (r < 0)
673 return r;
674
675 r = json_variant_set_field(&h->json, "perMachine", new_per_machine);
676 if (r < 0)
677 return r;
678
679 h->disk_size = disk_size;
680 h->mask |= USER_RECORD_PER_MACHINE;
681 return 0;
682 }
683
684 int user_record_update_last_changed(UserRecord *h, bool with_password) {
685 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
686 usec_t n;
687 int r;
688
689 assert(h);
690
691 if (!h->json)
692 return -EUNATCH;
693
694 n = now(CLOCK_REALTIME);
695
696 /* refuse downgrading */
697 if (h->last_change_usec != UINT64_MAX && h->last_change_usec >= n)
698 return -ECHRNG;
699 if (h->last_password_change_usec != UINT64_MAX && h->last_password_change_usec >= n)
700 return -ECHRNG;
701
702 v = json_variant_ref(h->json);
703
704 r = json_variant_set_field_unsigned(&v, "lastChangeUSec", n);
705 if (r < 0)
706 return r;
707
708 if (with_password) {
709 r = json_variant_set_field_unsigned(&v, "lastPasswordChangeUSec", n);
710 if (r < 0)
711 return r;
712
713 h->last_password_change_usec = n;
714 }
715
716 h->last_change_usec = n;
717
718 json_variant_unref(h->json);
719 h->json = TAKE_PTR(v);
720
721 h->mask |= USER_RECORD_REGULAR;
722 return 0;
723 }
724
725 int user_record_make_hashed_password(UserRecord *h, char **secret, bool extend) {
726 _cleanup_(json_variant_unrefp) JsonVariant *priv = NULL;
727 _cleanup_strv_free_ char **np = NULL;
728 char **i;
729 int r;
730
731 assert(h);
732 assert(secret);
733
734 /* Initializes the hashed password list from the specified plaintext passwords */
735
736 if (extend) {
737 np = strv_copy(h->hashed_password);
738 if (!np)
739 return -ENOMEM;
740
741 strv_uniq(np);
742 }
743
744 STRV_FOREACH(i, secret) {
745 _cleanup_free_ char *salt = NULL;
746 struct crypt_data cd = {};
747 char *k;
748
749 r = make_salt(&salt);
750 if (r < 0)
751 return r;
752
753 errno = 0;
754 k = crypt_r(*i, salt, &cd);
755 if (!k)
756 return errno_or_else(EINVAL);
757
758 r = strv_extend(&np, k);
759 if (r < 0)
760 return r;
761 }
762
763 priv = json_variant_ref(json_variant_by_key(h->json, "privileged"));
764
765 if (strv_isempty(np))
766 r = json_variant_filter(&priv, STRV_MAKE("hashedPassword"));
767 else {
768 _cleanup_(json_variant_unrefp) JsonVariant *new_array = NULL;
769
770 r = json_variant_new_array_strv(&new_array, np);
771 if (r < 0)
772 return r;
773
774 r = json_variant_set_field(&priv, "hashedPassword", new_array);
775 if (r < 0)
776 return r;
777 }
778
779 r = json_variant_set_field(&h->json, "privileged", priv);
780 if (r < 0)
781 return r;
782
783 strv_free_and_replace(h->hashed_password, np);
784
785 SET_FLAG(h->mask, USER_RECORD_PRIVILEGED, !json_variant_is_blank_object(priv));
786 return 0;
787 }
788
789 int user_record_set_hashed_password(UserRecord *h, char **hashed_password) {
790 _cleanup_(json_variant_unrefp) JsonVariant *priv = NULL;
791 _cleanup_strv_free_ char **copy = NULL;
792 int r;
793
794 assert(h);
795
796 priv = json_variant_ref(json_variant_by_key(h->json, "privileged"));
797
798 if (strv_isempty(hashed_password))
799 r = json_variant_filter(&priv, STRV_MAKE("hashedPassword"));
800 else {
801 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
802
803 copy = strv_copy(hashed_password);
804 if (!copy)
805 return -ENOMEM;
806
807 strv_uniq(copy);
808
809 r = json_variant_new_array_strv(&array, copy);
810 if (r < 0)
811 return r;
812
813 r = json_variant_set_field(&priv, "hashedPassword", array);
814 }
815 if (r < 0)
816 return r;
817
818 r = json_variant_set_field(&h->json, "privileged", priv);
819 if (r < 0)
820 return r;
821
822 strv_free_and_replace(h->hashed_password, copy);
823
824 SET_FLAG(h->mask, USER_RECORD_PRIVILEGED, !json_variant_is_blank_object(priv));
825 return 0;
826 }
827
828 int user_record_set_password(UserRecord *h, char **password, bool prepend) {
829 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
830 _cleanup_(strv_free_erasep) char **e = NULL;
831 int r;
832
833 assert(h);
834
835 if (prepend) {
836 e = strv_copy(password);
837 if (!e)
838 return -ENOMEM;
839
840 r = strv_extend_strv(&e, h->password, true);
841 if (r < 0)
842 return r;
843
844 strv_uniq(e);
845
846 if (strv_equal(h->password, e))
847 return 0;
848
849 } else {
850 if (strv_equal(h->password, password))
851 return 0;
852
853 e = strv_copy(password);
854 if (!e)
855 return -ENOMEM;
856
857 strv_uniq(e);
858 }
859
860 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
861
862 if (strv_isempty(e))
863 r = json_variant_filter(&w, STRV_MAKE("password"));
864 else {
865 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
866
867 r = json_variant_new_array_strv(&l, e);
868 if (r < 0)
869 return r;
870
871 json_variant_sensitive(l);
872
873 r = json_variant_set_field(&w, "password", l);
874 }
875 if (r < 0)
876 return r;
877
878 json_variant_sensitive(w);
879
880 r = json_variant_set_field(&h->json, "secret", w);
881 if (r < 0)
882 return r;
883
884 strv_free_and_replace(h->password, e);
885
886 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
887 return 0;
888 }
889
890 int user_record_set_token_pin(UserRecord *h, char **pin, bool prepend) {
891 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
892 _cleanup_(strv_free_erasep) char **e = NULL;
893 int r;
894
895 assert(h);
896
897 if (prepend) {
898 e = strv_copy(pin);
899 if (!e)
900 return -ENOMEM;
901
902 r = strv_extend_strv(&e, h->token_pin, true);
903 if (r < 0)
904 return r;
905
906 strv_uniq(e);
907
908 if (strv_equal(h->token_pin, e))
909 return 0;
910
911 } else {
912 if (strv_equal(h->token_pin, pin))
913 return 0;
914
915 e = strv_copy(pin);
916 if (!e)
917 return -ENOMEM;
918
919 strv_uniq(e);
920 }
921
922 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
923
924 if (strv_isempty(e))
925 r = json_variant_filter(&w, STRV_MAKE("tokenPin"));
926 else {
927 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
928
929 r = json_variant_new_array_strv(&l, e);
930 if (r < 0)
931 return r;
932
933 json_variant_sensitive(l);
934
935 r = json_variant_set_field(&w, "tokenPin", l);
936 }
937 if (r < 0)
938 return r;
939
940 json_variant_sensitive(w);
941
942 r = json_variant_set_field(&h->json, "secret", w);
943 if (r < 0)
944 return r;
945
946 strv_free_and_replace(h->token_pin, e);
947
948 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
949 return 0;
950 }
951
952 int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b) {
953 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
954 int r;
955
956 assert(h);
957
958 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
959
960 if (b < 0)
961 r = json_variant_filter(&w, STRV_MAKE("pkcs11ProtectedAuthenticationPathPermitted"));
962 else
963 r = json_variant_set_field_boolean(&w, "pkcs11ProtectedAuthenticationPathPermitted", b);
964 if (r < 0)
965 return r;
966
967 if (json_variant_is_blank_object(w))
968 r = json_variant_filter(&h->json, STRV_MAKE("secret"));
969 else {
970 json_variant_sensitive(w);
971
972 r = json_variant_set_field(&h->json, "secret", w);
973 }
974 if (r < 0)
975 return r;
976
977 h->pkcs11_protected_authentication_path_permitted = b;
978
979 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
980 return 0;
981 }
982
983 int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b) {
984 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
985 int r;
986
987 assert(h);
988
989 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
990
991 if (b < 0)
992 r = json_variant_filter(&w, STRV_MAKE("fido2UserPresencePermitted"));
993 else
994 r = json_variant_set_field_boolean(&w, "fido2UserPresencePermitted", b);
995 if (r < 0)
996 return r;
997
998 if (json_variant_is_blank_object(w))
999 r = json_variant_filter(&h->json, STRV_MAKE("secret"));
1000 else
1001 r = json_variant_set_field(&h->json, "secret", w);
1002 if (r < 0)
1003 return r;
1004
1005 h->fido2_user_presence_permitted = b;
1006
1007 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
1008 return 0;
1009 }
1010
1011 static bool per_machine_entry_empty(JsonVariant *v) {
1012 const char *k;
1013 _unused_ JsonVariant *e;
1014
1015 JSON_VARIANT_OBJECT_FOREACH(k, e, v)
1016 if (!STR_IN_SET(k, "matchMachineId", "matchHostname"))
1017 return false;
1018
1019 return true;
1020 }
1021
1022 int user_record_set_password_change_now(UserRecord *h, int b) {
1023 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
1024 JsonVariant *per_machine;
1025 int r;
1026
1027 assert(h);
1028
1029 w = json_variant_ref(h->json);
1030
1031 if (b < 0)
1032 r = json_variant_filter(&w, STRV_MAKE("passwordChangeNow"));
1033 else
1034 r = json_variant_set_field_boolean(&w, "passwordChangeNow", b);
1035 if (r < 0)
1036 return r;
1037
1038 /* Also drop the field from all perMachine entries */
1039 per_machine = json_variant_by_key(w, "perMachine");
1040 if (per_machine) {
1041 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
1042 JsonVariant *e;
1043
1044 JSON_VARIANT_ARRAY_FOREACH(e, per_machine) {
1045 _cleanup_(json_variant_unrefp) JsonVariant *z = NULL;
1046
1047 if (!json_variant_is_object(e))
1048 return -EINVAL;
1049
1050 z = json_variant_ref(e);
1051
1052 r = json_variant_filter(&z, STRV_MAKE("passwordChangeNow"));
1053 if (r < 0)
1054 return r;
1055
1056 if (per_machine_entry_empty(z))
1057 continue;
1058
1059 r = json_variant_append_array(&array, z);
1060 if (r < 0)
1061 return r;
1062 }
1063
1064 if (json_variant_is_blank_array(array))
1065 r = json_variant_filter(&w, STRV_MAKE("perMachine"));
1066 else
1067 r = json_variant_set_field(&w, "perMachine", array);
1068 if (r < 0)
1069 return r;
1070
1071 SET_FLAG(h->mask, USER_RECORD_PER_MACHINE, !json_variant_is_blank_array(array));
1072 }
1073
1074 json_variant_unref(h->json);
1075 h->json = TAKE_PTR(w);
1076
1077 h->password_change_now = b;
1078
1079 return 0;
1080 }
1081
1082 int user_record_merge_secret(UserRecord *h, UserRecord *secret) {
1083 int r;
1084
1085 assert(h);
1086
1087 /* Merges the secrets from 'secret' into 'h'. */
1088
1089 r = user_record_set_password(h, secret->password, true);
1090 if (r < 0)
1091 return r;
1092
1093 r = user_record_set_token_pin(h, secret->token_pin, true);
1094 if (r < 0)
1095 return r;
1096
1097 if (secret->pkcs11_protected_authentication_path_permitted >= 0) {
1098 r = user_record_set_pkcs11_protected_authentication_path_permitted(
1099 h,
1100 secret->pkcs11_protected_authentication_path_permitted);
1101 if (r < 0)
1102 return r;
1103 }
1104
1105 if (secret->fido2_user_presence_permitted >= 0) {
1106 r = user_record_set_fido2_user_presence_permitted(
1107 h,
1108 secret->fido2_user_presence_permitted);
1109 if (r < 0)
1110 return r;
1111 }
1112
1113 return 0;
1114 }
1115
1116 int user_record_good_authentication(UserRecord *h) {
1117 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1118 char buf[SD_ID128_STRING_MAX];
1119 uint64_t counter, usec;
1120 sd_id128_t mid;
1121 int r;
1122
1123 assert(h);
1124
1125 switch (h->good_authentication_counter) {
1126 case UINT64_MAX:
1127 counter = 1;
1128 break;
1129 case UINT64_MAX-1:
1130 counter = h->good_authentication_counter; /* saturate */
1131 break;
1132 default:
1133 counter = h->good_authentication_counter + 1;
1134 break;
1135 }
1136
1137 usec = now(CLOCK_REALTIME);
1138
1139 r = sd_id128_get_machine(&mid);
1140 if (r < 0)
1141 return r;
1142
1143 v = json_variant_ref(h->json);
1144 w = json_variant_ref(json_variant_by_key(v, "status"));
1145 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1146
1147 r = json_variant_set_field_unsigned(&z, "goodAuthenticationCounter", counter);
1148 if (r < 0)
1149 return r;
1150
1151 r = json_variant_set_field_unsigned(&z, "lastGoodAuthenticationUSec", usec);
1152 if (r < 0)
1153 return r;
1154
1155 r = json_variant_set_field(&w, buf, z);
1156 if (r < 0)
1157 return r;
1158
1159 r = json_variant_set_field(&v, "status", w);
1160 if (r < 0)
1161 return r;
1162
1163 json_variant_unref(h->json);
1164 h->json = TAKE_PTR(v);
1165
1166 h->good_authentication_counter = counter;
1167 h->last_good_authentication_usec = usec;
1168
1169 h->mask |= USER_RECORD_STATUS;
1170 return 0;
1171 }
1172
1173 int user_record_bad_authentication(UserRecord *h) {
1174 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1175 char buf[SD_ID128_STRING_MAX];
1176 uint64_t counter, usec;
1177 sd_id128_t mid;
1178 int r;
1179
1180 assert(h);
1181
1182 switch (h->bad_authentication_counter) {
1183 case UINT64_MAX:
1184 counter = 1;
1185 break;
1186 case UINT64_MAX-1:
1187 counter = h->bad_authentication_counter; /* saturate */
1188 break;
1189 default:
1190 counter = h->bad_authentication_counter + 1;
1191 break;
1192 }
1193
1194 usec = now(CLOCK_REALTIME);
1195
1196 r = sd_id128_get_machine(&mid);
1197 if (r < 0)
1198 return r;
1199
1200 v = json_variant_ref(h->json);
1201 w = json_variant_ref(json_variant_by_key(v, "status"));
1202 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1203
1204 r = json_variant_set_field_unsigned(&z, "badAuthenticationCounter", counter);
1205 if (r < 0)
1206 return r;
1207
1208 r = json_variant_set_field_unsigned(&z, "lastBadAuthenticationUSec", usec);
1209 if (r < 0)
1210 return r;
1211
1212 r = json_variant_set_field(&w, buf, z);
1213 if (r < 0)
1214 return r;
1215
1216 r = json_variant_set_field(&v, "status", w);
1217 if (r < 0)
1218 return r;
1219
1220 json_variant_unref(h->json);
1221 h->json = TAKE_PTR(v);
1222
1223 h->bad_authentication_counter = counter;
1224 h->last_bad_authentication_usec = usec;
1225
1226 h->mask |= USER_RECORD_STATUS;
1227 return 0;
1228 }
1229
1230 int user_record_ratelimit(UserRecord *h) {
1231 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1232 usec_t usec, new_ratelimit_begin_usec, new_ratelimit_count;
1233 char buf[SD_ID128_STRING_MAX];
1234 sd_id128_t mid;
1235 int r;
1236
1237 assert(h);
1238
1239 usec = now(CLOCK_REALTIME);
1240
1241 if (h->ratelimit_begin_usec != UINT64_MAX && h->ratelimit_begin_usec > usec)
1242 /* Hmm, time is running backwards? Say no! */
1243 return 0;
1244 else if (h->ratelimit_begin_usec == UINT64_MAX ||
1245 usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h)) <= usec) {
1246 /* Fresh start */
1247 new_ratelimit_begin_usec = usec;
1248 new_ratelimit_count = 1;
1249 } else if (h->ratelimit_count < user_record_ratelimit_burst(h)) {
1250 /* Count up */
1251 new_ratelimit_begin_usec = h->ratelimit_begin_usec;
1252 new_ratelimit_count = h->ratelimit_count + 1;
1253 } else
1254 /* Limit hit */
1255 return 0;
1256
1257 r = sd_id128_get_machine(&mid);
1258 if (r < 0)
1259 return r;
1260
1261 v = json_variant_ref(h->json);
1262 w = json_variant_ref(json_variant_by_key(v, "status"));
1263 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1264
1265 r = json_variant_set_field_unsigned(&z, "rateLimitBeginUSec", new_ratelimit_begin_usec);
1266 if (r < 0)
1267 return r;
1268
1269 r = json_variant_set_field_unsigned(&z, "rateLimitCount", new_ratelimit_count);
1270 if (r < 0)
1271 return r;
1272
1273 r = json_variant_set_field(&w, buf, z);
1274 if (r < 0)
1275 return r;
1276
1277 r = json_variant_set_field(&v, "status", w);
1278 if (r < 0)
1279 return r;
1280
1281 json_variant_unref(h->json);
1282 h->json = TAKE_PTR(v);
1283
1284 h->ratelimit_begin_usec = new_ratelimit_begin_usec;
1285 h->ratelimit_count = new_ratelimit_count;
1286
1287 h->mask |= USER_RECORD_STATUS;
1288 return 1;
1289 }
1290
1291 int user_record_is_supported(UserRecord *hr, sd_bus_error *error) {
1292 assert(hr);
1293
1294 if (hr->disposition >= 0 && hr->disposition != USER_REGULAR)
1295 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage anything but regular users.");
1296
1297 if (hr->storage >= 0 && !IN_SET(hr->storage, USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
1298 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has storage type this service cannot manage.");
1299
1300 if (gid_is_valid(hr->gid) && hr->uid != (uid_t) hr->gid)
1301 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has to have matching UID/GID fields.");
1302
1303 if (hr->service && !streq(hr->service, "io.systemd.Home"))
1304 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home.");
1305
1306 return 0;
1307 }