]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/user-record-util.c
Merge pull request #15473 from keszybz/bus-introspection
[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 ambiguous 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 json_variant_sensitive(w);
844
845 r = json_variant_set_field(&h->json, "secret", w);
846 if (r < 0)
847 return r;
848
849 strv_free_and_replace(h->password, e);
850
851 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
852 return 0;
853 }
854
855 int user_record_set_pkcs11_pin(UserRecord *h, char **pin, bool prepend) {
856 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
857 _cleanup_(strv_free_erasep) char **e = NULL;
858 int r;
859
860 assert(h);
861
862 if (prepend) {
863 e = strv_copy(pin);
864 if (!e)
865 return -ENOMEM;
866
867 r = strv_extend_strv(&e, h->pkcs11_pin, true);
868 if (r < 0)
869 return r;
870
871 strv_uniq(e);
872
873 if (strv_equal(h->pkcs11_pin, e))
874 return 0;
875
876 } else {
877 if (strv_equal(h->pkcs11_pin, pin))
878 return 0;
879
880 e = strv_copy(pin);
881 if (!e)
882 return -ENOMEM;
883
884 strv_uniq(e);
885 }
886
887 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
888
889 if (strv_isempty(e))
890 r = json_variant_filter(&w, STRV_MAKE("pkcs11Pin"));
891 else {
892 _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
893
894 r = json_variant_new_array_strv(&l, e);
895 if (r < 0)
896 return r;
897
898 json_variant_sensitive(l);
899
900 r = json_variant_set_field(&w, "pkcs11Pin", l);
901 }
902 if (r < 0)
903 return r;
904
905 json_variant_sensitive(w);
906
907 r = json_variant_set_field(&h->json, "secret", w);
908 if (r < 0)
909 return r;
910
911 strv_free_and_replace(h->pkcs11_pin, e);
912
913 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
914 return 0;
915 }
916
917 int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b) {
918 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
919 int r;
920
921 assert(h);
922
923 w = json_variant_ref(json_variant_by_key(h->json, "secret"));
924
925 if (b < 0)
926 r = json_variant_filter(&w, STRV_MAKE("pkcs11ProtectedAuthenticationPathPermitted"));
927 else
928 r = json_variant_set_field_boolean(&w, "pkcs11ProtectedAuthenticationPathPermitted", b);
929 if (r < 0)
930 return r;
931
932 if (json_variant_is_blank_object(w))
933 r = json_variant_filter(&h->json, STRV_MAKE("secret"));
934 else {
935 json_variant_sensitive(w);
936
937 r = json_variant_set_field(&h->json, "secret", w);
938 }
939 if (r < 0)
940 return r;
941
942 h->pkcs11_protected_authentication_path_permitted = b;
943
944 SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
945 return 0;
946 }
947
948 static bool per_machine_entry_empty(JsonVariant *v) {
949 const char *k;
950 _unused_ JsonVariant *e;
951
952 JSON_VARIANT_OBJECT_FOREACH(k, e, v)
953 if (!STR_IN_SET(k, "matchMachineId", "matchHostname"))
954 return false;
955
956 return true;
957 }
958
959 int user_record_set_password_change_now(UserRecord *h, int b) {
960 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
961 JsonVariant *per_machine;
962 int r;
963
964 assert(h);
965
966 w = json_variant_ref(h->json);
967
968 if (b < 0)
969 r = json_variant_filter(&w, STRV_MAKE("passwordChangeNow"));
970 else
971 r = json_variant_set_field_boolean(&w, "passwordChangeNow", b);
972 if (r < 0)
973 return r;
974
975 /* Also drop the field from all perMachine entries */
976 per_machine = json_variant_by_key(w, "perMachine");
977 if (per_machine) {
978 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
979 JsonVariant *e;
980
981 JSON_VARIANT_ARRAY_FOREACH(e, per_machine) {
982 _cleanup_(json_variant_unrefp) JsonVariant *z = NULL;
983
984 if (!json_variant_is_object(e))
985 return -EINVAL;
986
987 z = json_variant_ref(e);
988
989 r = json_variant_filter(&z, STRV_MAKE("passwordChangeNow"));
990 if (r < 0)
991 return r;
992
993 if (per_machine_entry_empty(z))
994 continue;
995
996 r = json_variant_append_array(&array, z);
997 if (r < 0)
998 return r;
999 }
1000
1001 if (json_variant_is_blank_array(array))
1002 r = json_variant_filter(&w, STRV_MAKE("perMachine"));
1003 else
1004 r = json_variant_set_field(&w, "perMachine", array);
1005 if (r < 0)
1006 return r;
1007
1008 SET_FLAG(h->mask, USER_RECORD_PER_MACHINE, !json_variant_is_blank_array(array));
1009 }
1010
1011 json_variant_unref(h->json);
1012 h->json = TAKE_PTR(w);
1013
1014 h->password_change_now = b;
1015
1016 return 0;
1017 }
1018
1019 int user_record_merge_secret(UserRecord *h, UserRecord *secret) {
1020 int r;
1021
1022 assert(h);
1023
1024 /* Merges the secrets from 'secret' into 'h'. */
1025
1026 r = user_record_set_password(h, secret->password, true);
1027 if (r < 0)
1028 return r;
1029
1030 r = user_record_set_pkcs11_pin(h, secret->pkcs11_pin, true);
1031 if (r < 0)
1032 return r;
1033
1034 if (secret->pkcs11_protected_authentication_path_permitted >= 0) {
1035 r = user_record_set_pkcs11_protected_authentication_path_permitted(h, secret->pkcs11_protected_authentication_path_permitted);
1036 if (r < 0)
1037 return r;
1038 }
1039
1040 return 0;
1041 }
1042
1043 int user_record_good_authentication(UserRecord *h) {
1044 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1045 char buf[SD_ID128_STRING_MAX];
1046 uint64_t counter, usec;
1047 sd_id128_t mid;
1048 int r;
1049
1050 assert(h);
1051
1052 switch (h->good_authentication_counter) {
1053 case UINT64_MAX:
1054 counter = 1;
1055 break;
1056 case UINT64_MAX-1:
1057 counter = h->good_authentication_counter; /* saturate */
1058 break;
1059 default:
1060 counter = h->good_authentication_counter + 1;
1061 break;
1062 }
1063
1064 usec = now(CLOCK_REALTIME);
1065
1066 r = sd_id128_get_machine(&mid);
1067 if (r < 0)
1068 return r;
1069
1070 v = json_variant_ref(h->json);
1071 w = json_variant_ref(json_variant_by_key(v, "status"));
1072 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1073
1074 r = json_variant_set_field_unsigned(&z, "goodAuthenticationCounter", counter);
1075 if (r < 0)
1076 return r;
1077
1078 r = json_variant_set_field_unsigned(&z, "lastGoodAuthenticationUSec", usec);
1079 if (r < 0)
1080 return r;
1081
1082 r = json_variant_set_field(&w, buf, z);
1083 if (r < 0)
1084 return r;
1085
1086 r = json_variant_set_field(&v, "status", w);
1087 if (r < 0)
1088 return r;
1089
1090 json_variant_unref(h->json);
1091 h->json = TAKE_PTR(v);
1092
1093 h->good_authentication_counter = counter;
1094 h->last_good_authentication_usec = usec;
1095
1096 h->mask |= USER_RECORD_STATUS;
1097 return 0;
1098 }
1099
1100 int user_record_bad_authentication(UserRecord *h) {
1101 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1102 char buf[SD_ID128_STRING_MAX];
1103 uint64_t counter, usec;
1104 sd_id128_t mid;
1105 int r;
1106
1107 assert(h);
1108
1109 switch (h->bad_authentication_counter) {
1110 case UINT64_MAX:
1111 counter = 1;
1112 break;
1113 case UINT64_MAX-1:
1114 counter = h->bad_authentication_counter; /* saturate */
1115 break;
1116 default:
1117 counter = h->bad_authentication_counter + 1;
1118 break;
1119 }
1120
1121 usec = now(CLOCK_REALTIME);
1122
1123 r = sd_id128_get_machine(&mid);
1124 if (r < 0)
1125 return r;
1126
1127 v = json_variant_ref(h->json);
1128 w = json_variant_ref(json_variant_by_key(v, "status"));
1129 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1130
1131 r = json_variant_set_field_unsigned(&z, "badAuthenticationCounter", counter);
1132 if (r < 0)
1133 return r;
1134
1135 r = json_variant_set_field_unsigned(&z, "lastBadAuthenticationUSec", usec);
1136 if (r < 0)
1137 return r;
1138
1139 r = json_variant_set_field(&w, buf, z);
1140 if (r < 0)
1141 return r;
1142
1143 r = json_variant_set_field(&v, "status", w);
1144 if (r < 0)
1145 return r;
1146
1147 json_variant_unref(h->json);
1148 h->json = TAKE_PTR(v);
1149
1150 h->bad_authentication_counter = counter;
1151 h->last_bad_authentication_usec = usec;
1152
1153 h->mask |= USER_RECORD_STATUS;
1154 return 0;
1155 }
1156
1157 int user_record_ratelimit(UserRecord *h) {
1158 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL, *z = NULL;
1159 usec_t usec, new_ratelimit_begin_usec, new_ratelimit_count;
1160 char buf[SD_ID128_STRING_MAX];
1161 sd_id128_t mid;
1162 int r;
1163
1164 assert(h);
1165
1166 usec = now(CLOCK_REALTIME);
1167
1168 if (h->ratelimit_begin_usec != UINT64_MAX && h->ratelimit_begin_usec > usec)
1169 /* Hmm, time is running backwards? Say no! */
1170 return 0;
1171 else if (h->ratelimit_begin_usec == UINT64_MAX ||
1172 usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h)) <= usec) {
1173 /* Fresh start */
1174 new_ratelimit_begin_usec = usec;
1175 new_ratelimit_count = 1;
1176 } else if (h->ratelimit_count < user_record_ratelimit_burst(h)) {
1177 /* Count up */
1178 new_ratelimit_begin_usec = h->ratelimit_begin_usec;
1179 new_ratelimit_count = h->ratelimit_count + 1;
1180 } else
1181 /* Limit hit */
1182 return 0;
1183
1184 r = sd_id128_get_machine(&mid);
1185 if (r < 0)
1186 return r;
1187
1188 v = json_variant_ref(h->json);
1189 w = json_variant_ref(json_variant_by_key(v, "status"));
1190 z = json_variant_ref(json_variant_by_key(w, sd_id128_to_string(mid, buf)));
1191
1192 r = json_variant_set_field_unsigned(&z, "rateLimitBeginUSec", new_ratelimit_begin_usec);
1193 if (r < 0)
1194 return r;
1195
1196 r = json_variant_set_field_unsigned(&z, "rateLimitCount", new_ratelimit_count);
1197 if (r < 0)
1198 return r;
1199
1200 r = json_variant_set_field(&w, buf, z);
1201 if (r < 0)
1202 return r;
1203
1204 r = json_variant_set_field(&v, "status", w);
1205 if (r < 0)
1206 return r;
1207
1208 json_variant_unref(h->json);
1209 h->json = TAKE_PTR(v);
1210
1211 h->ratelimit_begin_usec = new_ratelimit_begin_usec;
1212 h->ratelimit_count = new_ratelimit_count;
1213
1214 h->mask |= USER_RECORD_STATUS;
1215 return 1;
1216 }
1217
1218 int user_record_is_supported(UserRecord *hr, sd_bus_error *error) {
1219 assert(hr);
1220
1221 if (hr->disposition >= 0 && hr->disposition != USER_REGULAR)
1222 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot manage anything but regular users.");
1223
1224 if (hr->storage >= 0 && !IN_SET(hr->storage, USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
1225 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has storage type this service cannot manage.");
1226
1227 if (gid_is_valid(hr->gid) && hr->uid != (uid_t) hr->gid)
1228 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User record has to have matching UID/GID fields.");
1229
1230 if (hr->service && !streq(hr->service, "io.systemd.Home"))
1231 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not accepted with service not matching io.systemd.Home.");
1232
1233 return 0;
1234 }