]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/user-record-util.c
Merge pull request #14589 from keszybz/sysctl-downgrade-messages
[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 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;
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 }
298
299 if (home_directory) {
300 hd = strdup(home_directory);
301 if (!hd)
302 return -ENOMEM;
303 }
304
305 r = json_build(&new_binding_entry,
306 JSON_BUILD_OBJECT(
307 JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)),
308 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(id128_to_uuid_string(partition_uuid, partition_uuids))),
309 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(id128_to_uuid_string(luks_uuid, luks_uuids))),
310 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(id128_to_uuid_string(fs_uuid, fs_uuids))),
311 JSON_BUILD_PAIR_CONDITION(!!luks_cipher, "luksCipher", JSON_BUILD_STRING(luks_cipher)),
312 JSON_BUILD_PAIR_CONDITION(!!luks_cipher_mode, "luksCipherMode", JSON_BUILD_STRING(luks_cipher_mode)),
313 JSON_BUILD_PAIR_CONDITION(luks_volume_key_size != UINT64_MAX, "luksVolumeKeySize", JSON_BUILD_UNSIGNED(luks_volume_key_size)),
314 JSON_BUILD_PAIR_CONDITION(!!file_system_type, "fileSystemType", JSON_BUILD_STRING(file_system_type)),
315 JSON_BUILD_PAIR_CONDITION(!!home_directory, "homeDirectory", JSON_BUILD_STRING(home_directory)),
316 JSON_BUILD_PAIR_CONDITION(uid_is_valid(uid), "uid", JSON_BUILD_UNSIGNED(uid)),
317 JSON_BUILD_PAIR_CONDITION(gid_is_valid(gid), "gid", JSON_BUILD_UNSIGNED(gid)),
318 JSON_BUILD_PAIR_CONDITION(storage >= 0, "storage", JSON_BUILD_STRING(user_storage_to_string(storage)))));
319 if (r < 0)
320 return r;
321
322 binding = json_variant_ref(json_variant_by_key(h->json, "binding"));
323 if (binding) {
324 _cleanup_(json_variant_unrefp) JsonVariant *be = NULL;
325
326 /* Merge the new entry with an old one, if that exists */
327 be = json_variant_ref(json_variant_by_key(binding, smid));
328 if (be) {
329 r = json_variant_merge(&be, new_binding_entry);
330 if (r < 0)
331 return r;
332
333 json_variant_unref(new_binding_entry);
334 new_binding_entry = TAKE_PTR(be);
335 }
336 }
337
338 r = json_variant_set_field(&binding, smid, new_binding_entry);
339 if (r < 0)
340 return r;
341
342 r = json_variant_set_field(&h->json, "binding", binding);
343 if (r < 0)
344 return r;
345
346 if (storage >= 0)
347 h->storage = storage;
348
349 if (ip)
350 free_and_replace(h->image_path, ip);
351
352 if (!sd_id128_is_null(partition_uuid))
353 h->partition_uuid = partition_uuid;
354
355 if (!sd_id128_is_null(luks_uuid))
356 h->luks_uuid = luks_uuid;
357
358 if (!sd_id128_is_null(fs_uuid))
359 h->file_system_uuid = fs_uuid;
360
361 if (hd)
362 free_and_replace(h->home_directory, hd);
363
364 if (uid_is_valid(uid))
365 h->uid = uid;
366
367 h->mask |= USER_RECORD_BINDING;
368 return 1;
369 }
370
371 int user_record_test_home_directory(UserRecord *h) {
372 const char *hd;
373 int r;
374
375 assert(h);
376
377 /* Returns one of USER_TEST_ABSENT, USER_TEST_MOUNTED, USER_TEST_EXISTS on success */
378
379 hd = user_record_home_directory(h);
380 if (!hd)
381 return -ENXIO;
382
383 r = is_dir(hd, false);
384 if (r == -ENOENT)
385 return USER_TEST_ABSENT;
386 if (r < 0)
387 return r;
388 if (r == 0)
389 return -ENOTDIR;
390
391 r = path_is_mount_point(hd, NULL, 0);
392 if (r < 0)
393 return r;
394 if (r > 0)
395 return USER_TEST_MOUNTED;
396
397 /* If the image path and the home directory are identical, then it's OK if the directory is
398 * populated. */
399 if (IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT)) {
400 const char *ip;
401
402 ip = user_record_image_path(h);
403 if (ip && path_equal(ip, hd))
404 return USER_TEST_EXISTS;
405 }
406
407 /* Otherwise it's not OK */
408 r = dir_is_empty(hd);
409 if (r < 0)
410 return r;
411 if (r == 0)
412 return -EBUSY;
413
414 return USER_TEST_EXISTS;
415 }
416
417 int user_record_test_home_directory_and_warn(UserRecord *h) {
418 int r;
419
420 assert(h);
421
422 r = user_record_test_home_directory(h);
423 if (r == -ENXIO)
424 return log_error_errno(r, "User record lacks home directory, refusing.");
425 if (r == -ENOTDIR)
426 return log_error_errno(r, "Home directory %s is not a directory, refusing.", user_record_home_directory(h));
427 if (r == -EBUSY)
428 return log_error_errno(r, "Home directory %s exists, is not mounted but populated, refusing.", user_record_home_directory(h));
429 if (r < 0)
430 return log_error_errno(r, "Failed to test whether the home directory %s exists: %m", user_record_home_directory(h));
431
432 return r;
433 }
434
435 int user_record_test_image_path(UserRecord *h) {
436 const char *ip;
437 struct stat st;
438
439 assert(h);
440
441 if (user_record_storage(h) == USER_CIFS)
442 return USER_TEST_UNDEFINED;
443
444 ip = user_record_image_path(h);
445 if (!ip)
446 return -ENXIO;
447
448 if (stat(ip, &st) < 0) {
449 if (errno == ENOENT)
450 return USER_TEST_ABSENT;
451
452 return -errno;
453 }
454
455 switch (user_record_storage(h)) {
456
457 case USER_LUKS:
458 if (S_ISREG(st.st_mode))
459 return USER_TEST_EXISTS;
460 if (S_ISBLK(st.st_mode)) {
461 /* For block devices we can't really be sure if the device referenced actually is the
462 * fs we look for or some other file system (think: what does /dev/sdb1 refer
463 * to?). Hence, let's return USER_TEST_MAYBE as an ambigious return value for these
464 * case, except if the device path used is one of the paths that is based on a
465 * filesystem or partition UUID or label, because in those cases we can be sure we
466 * are referring to the right device. */
467
468 if (PATH_STARTSWITH_SET(ip,
469 "/dev/disk/by-uuid/",
470 "/dev/disk/by-partuuid/",
471 "/dev/disk/by-partlabel/",
472 "/dev/disk/by-label/"))
473 return USER_TEST_EXISTS;
474
475 return USER_TEST_MAYBE;
476 }
477
478 return -EBADFD;
479
480 case USER_CLASSIC:
481 case USER_DIRECTORY:
482 case USER_SUBVOLUME:
483 case USER_FSCRYPT:
484 if (S_ISDIR(st.st_mode))
485 return USER_TEST_EXISTS;
486
487 return -ENOTDIR;
488
489 default:
490 assert_not_reached("Unexpected record type");
491 }
492 }
493
494 int user_record_test_image_path_and_warn(UserRecord *h) {
495 int r;
496
497 assert(h);
498
499 r = user_record_test_image_path(h);
500 if (r == -ENXIO)
501 return log_error_errno(r, "User record lacks image path, refusing.");
502 if (r == -EBADFD)
503 return log_error_errno(r, "Image path %s is not a regular file or block device, refusing.", user_record_image_path(h));
504 if (r == -ENOTDIR)
505 return log_error_errno(r, "Image path %s is not a directory, refusing.", user_record_image_path(h));
506 if (r < 0)
507 return log_error_errno(r, "Failed to test whether image path %s exists: %m", user_record_image_path(h));
508
509 return r;
510 }
511
512 int user_record_test_secret(UserRecord *h, UserRecord *secret) {
513 char **i;
514 int r;
515
516 assert(h);
517
518 /* Checks whether any of the specified passwords matches any of the hashed passwords of the entry */
519
520 if (strv_isempty(h->hashed_password))
521 return -ENXIO;
522
523 STRV_FOREACH(i, secret->password) {
524 r = test_password_many(h->hashed_password, *i);
525 if (r < 0)
526 return r;
527 if (r > 0)
528 return 0;
529 }
530
531 return -ENOKEY;
532 }
533
534 int user_record_set_disk_size(UserRecord *h, uint64_t disk_size) {
535 _cleanup_(json_variant_unrefp) JsonVariant *new_per_machine = NULL, *midv = NULL, *midav = NULL, *ne = NULL;
536 _cleanup_free_ JsonVariant **array = NULL;
537 char smid[SD_ID128_STRING_MAX];
538 size_t idx = SIZE_MAX, n;
539 JsonVariant *per_machine;
540 sd_id128_t mid;
541 int r;
542
543 assert(h);
544
545 if (!h->json)
546 return -EUNATCH;
547
548 if (disk_size < USER_DISK_SIZE_MIN || disk_size > USER_DISK_SIZE_MAX)
549 return -ERANGE;
550
551 r = sd_id128_get_machine(&mid);
552 if (r < 0)
553 return r;
554
555 sd_id128_to_string(mid, smid);
556
557 r = json_variant_new_string(&midv, smid);
558 if (r < 0)
559 return r;
560
561 r = json_variant_new_array(&midav, (JsonVariant*[]) { midv }, 1);
562 if (r < 0)
563 return r;
564
565 per_machine = json_variant_by_key(h->json, "perMachine");
566 if (per_machine) {
567 size_t i;
568
569 if (!json_variant_is_array(per_machine))
570 return -EINVAL;
571
572 n = json_variant_elements(per_machine);
573
574 array = new(JsonVariant*, n + 1);
575 if (!array)
576 return -ENOMEM;
577
578 for (i = 0; i < n; i++) {
579 JsonVariant *m;
580
581 array[i] = json_variant_by_index(per_machine, i);
582
583 if (!json_variant_is_object(array[i]))
584 return -EINVAL;
585
586 m = json_variant_by_key(array[i], "matchMachineId");
587 if (!m) {
588 /* No machineId field? Let's ignore this, but invalidate what we found so far */
589 idx = SIZE_MAX;
590 continue;
591 }
592
593 if (json_variant_equal(m, midv) ||
594 json_variant_equal(m, midav)) {
595 /* Matches exactly what we are looking for. Let's use this */
596 idx = i;
597 continue;
598 }
599
600 r = per_machine_id_match(m, JSON_PERMISSIVE);
601 if (r < 0)
602 return r;
603 if (r > 0)
604 /* Also matches what we are looking for, but with a broader match. In this
605 * case let's ignore this entry, and add a new specific one to the end. */
606 idx = SIZE_MAX;
607 }
608
609 if (idx == SIZE_MAX)
610 idx = n++; /* Nothing suitable found, place new entry at end */
611 else
612 ne = json_variant_ref(array[idx]);
613
614 } else {
615 array = new(JsonVariant*, 1);
616 if (!array)
617 return -ENOMEM;
618
619 idx = 0;
620 n = 1;
621 }
622
623 if (!ne) {
624 r = json_variant_set_field(&ne, "matchMachineId", midav);
625 if (r < 0)
626 return r;
627 }
628
629 r = json_variant_set_field_unsigned(&ne, "diskSize", disk_size);
630 if (r < 0)
631 return r;
632
633 assert(idx < n);
634 array[idx] = ne;
635
636 r = json_variant_new_array(&new_per_machine, array, n);
637 if (r < 0)
638 return r;
639
640 r = json_variant_set_field(&h->json, "perMachine", new_per_machine);
641 if (r < 0)
642 return r;
643
644 h->disk_size = disk_size;
645 h->mask |= USER_RECORD_PER_MACHINE;
646 return 0;
647 }
648
649 int user_record_update_last_changed(UserRecord *h, bool with_password) {
650 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
651 usec_t n;
652 int r;
653
654 assert(h);
655
656 if (!h->json)
657 return -EUNATCH;
658
659 n = now(CLOCK_REALTIME);
660
661 /* refuse downgrading */
662 if (h->last_change_usec != UINT64_MAX && h->last_change_usec >= n)
663 return -ECHRNG;
664 if (h->last_password_change_usec != UINT64_MAX && h->last_password_change_usec >= n)
665 return -ECHRNG;
666
667 v = json_variant_ref(h->json);
668
669 r = json_variant_set_field_unsigned(&v, "lastChangeUSec", n);
670 if (r < 0)
671 return r;
672
673 if (with_password) {
674 r = json_variant_set_field_unsigned(&v, "lastPasswordChangeUSec", n);
675 if (r < 0)
676 return r;
677
678 h->last_password_change_usec = n;
679 }
680
681 h->last_change_usec = n;
682
683 json_variant_unref(h->json);
684 h->json = TAKE_PTR(v);
685
686 h->mask |= USER_RECORD_REGULAR;
687 return 0;
688 }
689
690 int user_record_make_hashed_password(UserRecord *h, char **secret, bool extend) {
691 _cleanup_(json_variant_unrefp) JsonVariant *priv = NULL;
692 _cleanup_strv_free_ char **np = NULL;
693 char **i;
694 int r;
695
696 assert(h);
697 assert(secret);
698
699 /* Initializes the hashed password list from the specified plaintext passwords */
700
701 if (extend) {
702 np = strv_copy(h->hashed_password);
703 if (!np)
704 return -ENOMEM;
705
706 strv_uniq(np);
707 }
708
709 STRV_FOREACH(i, secret) {
710 _cleanup_free_ char *salt = NULL;
711 struct crypt_data cd = {};
712 char *k;
713
714 r = make_salt(&salt);
715 if (r < 0)
716 return r;
717
718 errno = 0;
719 k = crypt_r(*i, salt, &cd);
720 if (!k)
721 return errno_or_else(EINVAL);
722
723 r = strv_extend(&np, k);
724 if (r < 0)
725 return r;
726 }
727
728 priv = json_variant_ref(json_variant_by_key(h->json, "privileged"));
729
730 if (strv_isempty(np))
731 r = json_variant_filter(&priv, STRV_MAKE("hashedPassword"));
732 else {
733 _cleanup_(json_variant_unrefp) JsonVariant *new_array = NULL;
734
735 r = json_variant_new_array_strv(&new_array, np);
736 if (r < 0)
737 return r;
738
739 r = json_variant_set_field(&priv, "hashedPassword", new_array);
740 if (r < 0)
741 return r;
742 }
743
744 r = json_variant_set_field(&h->json, "privileged", priv);
745 if (r < 0)
746 return r;
747
748 strv_free_and_replace(h->hashed_password, np);
749
750 SET_FLAG(h->mask, USER_RECORD_PRIVILEGED, !json_variant_is_blank_object(priv));
751 return 0;
752 }
753
754 int user_record_set_hashed_password(UserRecord *h, char **hashed_password) {
755 _cleanup_(json_variant_unrefp) JsonVariant *priv = NULL;
756 _cleanup_strv_free_ char **copy = NULL;
757 int r;
758
759 assert(h);
760
761 priv = json_variant_ref(json_variant_by_key(h->json, "privileged"));
762
763 if (strv_isempty(hashed_password))
764 r = json_variant_filter(&priv, STRV_MAKE("hashedPassword"));
765 else {
766 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
767
768 copy = strv_copy(hashed_password);
769 if (!copy)
770 return -ENOMEM;
771
772 strv_uniq(copy);
773
774 r = json_variant_new_array_strv(&array, copy);
775 if (r < 0)
776 return r;
777
778 r = json_variant_set_field(&priv, "hashedPassword", array);
779 }
780 if (r < 0)
781 return r;
782
783 r = json_variant_set_field(&h->json, "privileged", priv);
784 if (r < 0)
785 return r;
786
787 strv_free_and_replace(h->hashed_password, copy);
788
789 SET_FLAG(h->mask, USER_RECORD_PRIVILEGED, !json_variant_is_blank_object(priv));
790 return 0;
791 }
792
793 int user_record_set_password(UserRecord *h, char **password, bool prepend) {
794 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
795 _cleanup_(strv_free_erasep) char **e = NULL;
796 int r;
797
798 assert(h);
799
800 if (prepend) {
801 e = strv_copy(password);
802 if (!e)
803 return -ENOMEM;
804
805 r = strv_extend_strv(&e, h->password, true);
806 if (r < 0)
807 return r;
808
809 strv_uniq(e);
810
811 if (strv_equal(h->password, e))
812 return 0;
813
814 } else {
815 if (strv_equal(h->password, password))
816 return 0;
817
818 e = strv_copy(password);
819 if (!e)
820 return -ENOMEM;
821
822 strv_uniq(e);
823 }
824
825 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
826
827 if (strv_isempty(e))
828 r = json_variant_filter(&w, STRV_MAKE("password"));
829 else {
830 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
831
832 r = json_variant_new_array_strv(&l, e);
833 if (r < 0)
834 return r;
835
836 json_variant_sensitive(l);
837
838 r = json_variant_set_field(&w, "password", l);
839 }
840 if (r < 0)
841 return r;
842
843 r = json_variant_set_field(&h->json, "secret", w);
844 if (r < 0)
845 return r;
846
847 strv_free_and_replace(h->password, e);
848
849 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
850 return 0;
851 }
852
853 int user_record_set_pkcs11_pin(UserRecord *h, char **pin, bool prepend) {
854 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
855 _cleanup_(strv_free_erasep) char **e = NULL;
856 int r;
857
858 assert(h);
859
860 if (prepend) {
861 e = strv_copy(pin);
862 if (!e)
863 return -ENOMEM;
864
865 r = strv_extend_strv(&e, h->pkcs11_pin, true);
866 if (r < 0)
867 return r;
868
869 strv_uniq(e);
870
871 if (strv_equal(h->pkcs11_pin, e))
872 return 0;
873
874 } else {
875 if (strv_equal(h->pkcs11_pin, pin))
876 return 0;
877
878 e = strv_copy(pin);
879 if (!e)
880 return -ENOMEM;
881
882 strv_uniq(e);
883 }
884
885 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
886
887 if (strv_isempty(e))
888 r = json_variant_filter(&w, STRV_MAKE("pkcs11Pin"));
889 else {
890 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
891
892 r = json_variant_new_array_strv(&l, e);
893 if (r < 0)
894 return r;
895
896 json_variant_sensitive(l);
897
898 r = json_variant_set_field(&w, "pkcs11Pin", l);
899 }
900 if (r < 0)
901 return r;
902
903 r = json_variant_set_field(&h->json, "secret", w);
904 if (r < 0)
905 return r;
906
907 strv_free_and_replace(h->pkcs11_pin, e);
908
909 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
910 return 0;
911 }
912
913 int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b) {
914 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
915 int r;
916
917 assert(h);
918
919 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
920
921 if (b < 0)
922 r = json_variant_filter(&w, STRV_MAKE("pkcs11ProtectedAuthenticationPathPermitted"));
923 else
924 r = json_variant_set_field_boolean(&w, "pkcs11ProtectedAuthenticationPathPermitted", b);
925 if (r < 0)
926 return r;
927
928 if (json_variant_is_blank_object(w))
929 r = json_variant_filter(&h->json, STRV_MAKE("secret"));
930 else
931 r = json_variant_set_field(&h->json, "secret", w);
932 if (r < 0)
933 return r;
934
935 h->pkcs11_protected_authentication_path_permitted = b;
936
937 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
938 return 0;
939 }
940
941 static bool per_machine_entry_empty(JsonVariant *v) {
942 const char *k;
943 _unused_ JsonVariant *e;
944
945 JSON_VARIANT_OBJECT_FOREACH(k, e, v)
946 if (!STR_IN_SET(k, "matchMachineId", "matchHostname"))
947 return false;
948
949 return true;
950 }
951
952 int user_record_set_password_change_now(UserRecord *h, int b) {
953 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
954 JsonVariant *per_machine;
955 int r;
956
957 assert(h);
958
959 w = json_variant_ref(h->json);
960
961 if (b < 0)
962 r = json_variant_filter(&w, STRV_MAKE("passwordChangeNow"));
963 else
964 r = json_variant_set_field_boolean(&w, "passwordChangeNow", b);
965 if (r < 0)
966 return r;
967
968 /* Also drop the field from all perMachine entries */
969 per_machine = json_variant_by_key(w, "perMachine");
970 if (per_machine) {
971 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
972 JsonVariant *e;
973
974 JSON_VARIANT_ARRAY_FOREACH(e, per_machine) {
975 _cleanup_(json_variant_unrefp) JsonVariant *z = NULL;
976
977 if (!json_variant_is_object(e))
978 return -EINVAL;
979
980 z = json_variant_ref(e);
981
982 r = json_variant_filter(&z, STRV_MAKE("passwordChangeNow"));
983 if (r < 0)
984 return r;
985
986 if (per_machine_entry_empty(z))
987 continue;
988
989 r = json_variant_append_array(&array, z);
990 if (r < 0)
991 return r;
992 }
993
994 if (json_variant_is_blank_array(array))
995 r = json_variant_filter(&w, STRV_MAKE("perMachine"));
996 else
997 r = json_variant_set_field(&w, "perMachine", array);
998 if (r < 0)
999 return r;
1000
1001 SET_FLAG(h->mask, USER_RECORD_PER_MACHINE, !json_variant_is_blank_array(array));
1002 }
1003
1004 json_variant_unref(h->json);
1005 h->json = TAKE_PTR(w);
1006
1007 h->password_change_now = b;
1008
1009 return 0;
1010 }
1011
1012 int user_record_merge_secret(UserRecord *h, UserRecord *secret) {
1013 int r;
1014
1015 assert(h);
1016
1017 /* Merges the secrets from 'secret' into 'h'. */
1018
1019 r = user_record_set_password(h, secret->password, true);
1020 if (r < 0)
1021 return r;
1022
1023 r = user_record_set_pkcs11_pin(h, secret->pkcs11_pin, true);
1024 if (r < 0)
1025 return r;
1026
1027 if (secret->pkcs11_protected_authentication_path_permitted >= 0) {
1028 r = user_record_set_pkcs11_protected_authentication_path_permitted(h, secret->pkcs11_protected_authentication_path_permitted);
1029 if (r < 0)
1030 return r;
1031 }
1032
1033 return 0;
1034 }
1035
1036 int user_record_good_authentication(UserRecord *h) {
1037 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1038 char buf[SD_ID128_STRING_MAX];
1039 uint64_t counter, usec;
1040 sd_id128_t mid;
1041 int r;
1042
1043 assert(h);
1044
1045 switch (h->good_authentication_counter) {
1046 case UINT64_MAX:
1047 counter = 1;
1048 break;
1049 case UINT64_MAX-1:
1050 counter = h->good_authentication_counter; /* saturate */
1051 break;
1052 default:
1053 counter = h->good_authentication_counter + 1;
1054 break;
1055 }
1056
1057 usec = now(CLOCK_REALTIME);
1058
1059 r = sd_id128_get_machine(&mid);
1060 if (r < 0)
1061 return r;
1062
1063 v = json_variant_ref(h->json);
1064 w = json_variant_ref(json_variant_by_key(v, "status"));
1065 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1066
1067 r = json_variant_set_field_unsigned(&z, "goodAuthenticationCounter", counter);
1068 if (r < 0)
1069 return r;
1070
1071 r = json_variant_set_field_unsigned(&z, "lastGoodAuthenticationUSec", usec);
1072 if (r < 0)
1073 return r;
1074
1075 r = json_variant_set_field(&w, buf, z);
1076 if (r < 0)
1077 return r;
1078
1079 r = json_variant_set_field(&v, "status", w);
1080 if (r < 0)
1081 return r;
1082
1083 json_variant_unref(h->json);
1084 h->json = TAKE_PTR(v);
1085
1086 h->good_authentication_counter = counter;
1087 h->last_good_authentication_usec = usec;
1088
1089 h->mask |= USER_RECORD_STATUS;
1090 return 0;
1091 }
1092
1093 int user_record_bad_authentication(UserRecord *h) {
1094 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1095 char buf[SD_ID128_STRING_MAX];
1096 uint64_t counter, usec;
1097 sd_id128_t mid;
1098 int r;
1099
1100 assert(h);
1101
1102 switch (h->bad_authentication_counter) {
1103 case UINT64_MAX:
1104 counter = 1;
1105 break;
1106 case UINT64_MAX-1:
1107 counter = h->bad_authentication_counter; /* saturate */
1108 break;
1109 default:
1110 counter = h->bad_authentication_counter + 1;
1111 break;
1112 }
1113
1114 usec = now(CLOCK_REALTIME);
1115
1116 r = sd_id128_get_machine(&mid);
1117 if (r < 0)
1118 return r;
1119
1120 v = json_variant_ref(h->json);
1121 w = json_variant_ref(json_variant_by_key(v, "status"));
1122 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1123
1124 r = json_variant_set_field_unsigned(&z, "badAuthenticationCounter", counter);
1125 if (r < 0)
1126 return r;
1127
1128 r = json_variant_set_field_unsigned(&z, "lastBadAuthenticationUSec", usec);
1129 if (r < 0)
1130 return r;
1131
1132 r = json_variant_set_field(&w, buf, z);
1133 if (r < 0)
1134 return r;
1135
1136 r = json_variant_set_field(&v, "status", w);
1137 if (r < 0)
1138 return r;
1139
1140 json_variant_unref(h->json);
1141 h->json = TAKE_PTR(v);
1142
1143 h->bad_authentication_counter = counter;
1144 h->last_bad_authentication_usec = usec;
1145
1146 h->mask |= USER_RECORD_STATUS;
1147 return 0;
1148 }
1149
1150 int user_record_ratelimit(UserRecord *h) {
1151 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1152 usec_t usec, new_ratelimit_begin_usec, new_ratelimit_count;
1153 char buf[SD_ID128_STRING_MAX];
1154 sd_id128_t mid;
1155 int r;
1156
1157 assert(h);
1158
1159 usec = now(CLOCK_REALTIME);
1160
1161 if (h->ratelimit_begin_usec != UINT64_MAX && h->ratelimit_begin_usec > usec)
1162 /* Hmm, time is running backwards? Say no! */
1163 return 0;
1164 else if (h->ratelimit_begin_usec == UINT64_MAX ||
1165 usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h)) <= usec) {
1166 /* Fresh start */
1167 new_ratelimit_begin_usec = usec;
1168 new_ratelimit_count = 1;
1169 } else if (h->ratelimit_count < user_record_ratelimit_burst(h)) {
1170 /* Count up */
1171 new_ratelimit_begin_usec = h->ratelimit_begin_usec;
1172 new_ratelimit_count = h->ratelimit_count + 1;
1173 } else
1174 /* Limit hit */
1175 return 0;
1176
1177 r = sd_id128_get_machine(&mid);
1178 if (r < 0)
1179 return r;
1180
1181 v = json_variant_ref(h->json);
1182 w = json_variant_ref(json_variant_by_key(v, "status"));
1183 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1184
1185 r = json_variant_set_field_unsigned(&z, "rateLimitBeginUSec", new_ratelimit_begin_usec);
1186 if (r < 0)
1187 return r;
1188
1189 r = json_variant_set_field_unsigned(&z, "rateLimitCount", new_ratelimit_count);
1190 if (r < 0)
1191 return r;
1192
1193 r = json_variant_set_field(&w, buf, z);
1194 if (r < 0)
1195 return r;
1196
1197 r = json_variant_set_field(&v, "status", w);
1198 if (r < 0)
1199 return r;
1200
1201 json_variant_unref(h->json);
1202 h->json = TAKE_PTR(v);
1203
1204 h->ratelimit_begin_usec = new_ratelimit_begin_usec;
1205 h->ratelimit_count = new_ratelimit_count;
1206
1207 h->mask |= USER_RECORD_STATUS;
1208 return 1;
1209 }
1210
1211 int user_record_is_supported(UserRecord *hr, sd_bus_error *error) {
1212 assert(hr);
1213
1214 if (hr->disposition >= 0 && hr->disposition != USER_REGULAR)
1215 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage anything but regular users.");
1216
1217 if (hr->storage >= 0 && !IN_SET(hr->storage, USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
1218 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has storage type this service cannot manage.");
1219
1220 if (gid_is_valid(hr->gid) && hr->uid != (uid_t) hr->gid)
1221 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has to have matching UID/GID fields.");
1222
1223 if (hr->service && !streq(hr->service, "io.systemd.Home"))
1224 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home.");
1225
1226 return 0;
1227 }