]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/user-record.c
user-record: Add blobDirectory and blobManifest
[thirdparty/systemd.git] / src / shared / user-record.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/mount.h>
4
5 #include "cap-list.h"
6 #include "cgroup-util.h"
7 #include "dns-domain.h"
8 #include "env-util.h"
9 #include "fs-util.h"
10 #include "glyph-util.h"
11 #include "hexdecoct.h"
12 #include "hostname-util.h"
13 #include "locale-util.h"
14 #include "memory-util.h"
15 #include "path-util.h"
16 #include "pkcs11-util.h"
17 #include "rlimit-util.h"
18 #include "sha256.h"
19 #include "string-table.h"
20 #include "strv.h"
21 #include "uid-classification.h"
22 #include "user-record.h"
23 #include "user-util.h"
24 #include "utf8.h"
25
26 #define DEFAULT_RATELIMIT_BURST 30
27 #define DEFAULT_RATELIMIT_INTERVAL_USEC (1*USEC_PER_MINUTE)
28
29 UserRecord* user_record_new(void) {
30 UserRecord *h;
31
32 h = new(UserRecord, 1);
33 if (!h)
34 return NULL;
35
36 *h = (UserRecord) {
37 .n_ref = 1,
38 .disposition = _USER_DISPOSITION_INVALID,
39 .last_change_usec = UINT64_MAX,
40 .last_password_change_usec = UINT64_MAX,
41 .umask = MODE_INVALID,
42 .nice_level = INT_MAX,
43 .not_before_usec = UINT64_MAX,
44 .not_after_usec = UINT64_MAX,
45 .locked = -1,
46 .storage = _USER_STORAGE_INVALID,
47 .access_mode = MODE_INVALID,
48 .disk_size = UINT64_MAX,
49 .disk_size_relative = UINT64_MAX,
50 .tasks_max = UINT64_MAX,
51 .memory_high = UINT64_MAX,
52 .memory_max = UINT64_MAX,
53 .cpu_weight = UINT64_MAX,
54 .io_weight = UINT64_MAX,
55 .uid = UID_INVALID,
56 .gid = GID_INVALID,
57 .nodev = true,
58 .nosuid = true,
59 .luks_discard = -1,
60 .luks_offline_discard = -1,
61 .luks_volume_key_size = UINT64_MAX,
62 .luks_pbkdf_force_iterations = UINT64_MAX,
63 .luks_pbkdf_time_cost_usec = UINT64_MAX,
64 .luks_pbkdf_memory_cost = UINT64_MAX,
65 .luks_pbkdf_parallel_threads = UINT64_MAX,
66 .luks_sector_size = UINT64_MAX,
67 .disk_usage = UINT64_MAX,
68 .disk_free = UINT64_MAX,
69 .disk_ceiling = UINT64_MAX,
70 .disk_floor = UINT64_MAX,
71 .signed_locally = -1,
72 .good_authentication_counter = UINT64_MAX,
73 .bad_authentication_counter = UINT64_MAX,
74 .last_good_authentication_usec = UINT64_MAX,
75 .last_bad_authentication_usec = UINT64_MAX,
76 .ratelimit_begin_usec = UINT64_MAX,
77 .ratelimit_count = UINT64_MAX,
78 .ratelimit_interval_usec = UINT64_MAX,
79 .ratelimit_burst = UINT64_MAX,
80 .removable = -1,
81 .enforce_password_policy = -1,
82 .auto_login = -1,
83 .stop_delay_usec = UINT64_MAX,
84 .kill_processes = -1,
85 .password_change_min_usec = UINT64_MAX,
86 .password_change_max_usec = UINT64_MAX,
87 .password_change_warn_usec = UINT64_MAX,
88 .password_change_inactive_usec = UINT64_MAX,
89 .password_change_now = -1,
90 .pkcs11_protected_authentication_path_permitted = -1,
91 .fido2_user_presence_permitted = -1,
92 .fido2_user_verification_permitted = -1,
93 .drop_caches = -1,
94 .auto_resize_mode = _AUTO_RESIZE_MODE_INVALID,
95 .rebalance_weight = REBALANCE_WEIGHT_UNSET,
96 };
97
98 return h;
99 }
100
101 static void pkcs11_encrypted_key_done(Pkcs11EncryptedKey *k) {
102 if (!k)
103 return;
104
105 free(k->uri);
106 erase_and_free(k->data);
107 erase_and_free(k->hashed_password);
108 }
109
110 static void fido2_hmac_credential_done(Fido2HmacCredential *c) {
111 if (!c)
112 return;
113
114 free(c->id);
115 }
116
117 static void fido2_hmac_salt_done(Fido2HmacSalt *s) {
118 if (!s)
119 return;
120
121 fido2_hmac_credential_done(&s->credential);
122 erase_and_free(s->salt);
123 erase_and_free(s->hashed_password);
124 }
125
126 static void recovery_key_done(RecoveryKey *k) {
127 if (!k)
128 return;
129
130 free(k->type);
131 erase_and_free(k->hashed_password);
132 }
133
134 static UserRecord* user_record_free(UserRecord *h) {
135 if (!h)
136 return NULL;
137
138 free(h->user_name);
139 free(h->realm);
140 free(h->user_name_and_realm_auto);
141 free(h->real_name);
142 free(h->email_address);
143 erase_and_free(h->password_hint);
144 free(h->location);
145 free(h->icon_name);
146
147 free(h->blob_directory);
148 hashmap_free(h->blob_manifest);
149
150 free(h->shell);
151
152 strv_free(h->environment);
153 free(h->time_zone);
154 free(h->preferred_language);
155 strv_free(h->additional_languages);
156 rlimit_free_all(h->rlimits);
157
158 free(h->skeleton_directory);
159
160 strv_free_erase(h->hashed_password);
161 strv_free_erase(h->ssh_authorized_keys);
162 strv_free_erase(h->password);
163 strv_free_erase(h->token_pin);
164
165 free(h->cifs_service);
166 free(h->cifs_user_name);
167 free(h->cifs_domain);
168 free(h->cifs_extra_mount_options);
169
170 free(h->image_path);
171 free(h->image_path_auto);
172 free(h->home_directory);
173 free(h->home_directory_auto);
174
175 free(h->fallback_shell);
176 free(h->fallback_home_directory);
177
178 strv_free(h->member_of);
179 strv_free(h->capability_bounding_set);
180 strv_free(h->capability_ambient_set);
181
182 free(h->file_system_type);
183 free(h->luks_cipher);
184 free(h->luks_cipher_mode);
185 free(h->luks_pbkdf_hash_algorithm);
186 free(h->luks_pbkdf_type);
187 free(h->luks_extra_mount_options);
188
189 free(h->state);
190 free(h->service);
191
192 strv_free(h->pkcs11_token_uri);
193 for (size_t i = 0; i < h->n_pkcs11_encrypted_key; i++)
194 pkcs11_encrypted_key_done(h->pkcs11_encrypted_key + i);
195 free(h->pkcs11_encrypted_key);
196
197 for (size_t i = 0; i < h->n_fido2_hmac_credential; i++)
198 fido2_hmac_credential_done(h->fido2_hmac_credential + i);
199 for (size_t i = 0; i < h->n_fido2_hmac_salt; i++)
200 fido2_hmac_salt_done(h->fido2_hmac_salt + i);
201
202 strv_free(h->recovery_key_type);
203 for (size_t i = 0; i < h->n_recovery_key; i++)
204 recovery_key_done(h->recovery_key + i);
205
206 json_variant_unref(h->json);
207
208 return mfree(h);
209 }
210
211 DEFINE_TRIVIAL_REF_UNREF_FUNC(UserRecord, user_record, user_record_free);
212
213 int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
214 char **s = userdata;
215 const char *n;
216 int r;
217
218 if (json_variant_is_null(variant)) {
219 *s = mfree(*s);
220 return 0;
221 }
222
223 if (!json_variant_is_string(variant))
224 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
225
226 n = json_variant_string(variant);
227 r = dns_name_is_valid(n);
228 if (r < 0)
229 return json_log(variant, flags, r, "Failed to check if JSON field '%s' is a valid DNS domain.", strna(name));
230 if (r == 0)
231 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid DNS domain.", strna(name));
232
233 r = free_and_strdup(s, n);
234 if (r < 0)
235 return json_log(variant, flags, r, "Failed to allocate string: %m");
236
237 return 0;
238 }
239
240 int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
241 char **s = userdata;
242 const char *n;
243
244 if (json_variant_is_null(variant)) {
245 *s = mfree(*s);
246 return 0;
247 }
248
249 if (!json_variant_is_string(variant))
250 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
251
252 n = json_variant_string(variant);
253 if (valid_gecos(n)) {
254 if (free_and_strdup(s, n) < 0)
255 return json_log_oom(variant, flags);
256 } else {
257 _cleanup_free_ char *m = NULL;
258
259 json_log(variant, flags|JSON_DEBUG, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible string, mangling.", strna(name));
260
261 m = mangle_gecos(n);
262 if (!m)
263 return json_log_oom(variant, flags);
264
265 free_and_replace(*s, m);
266 }
267
268 return 0;
269 }
270
271 static int json_dispatch_nice(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
272 int *nl = userdata;
273 int64_t m;
274
275 if (json_variant_is_null(variant)) {
276 *nl = INT_MAX;
277 return 0;
278 }
279
280 if (!json_variant_is_integer(variant))
281 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
282
283 m = json_variant_integer(variant);
284 if (m < PRIO_MIN || m >= PRIO_MAX)
285 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' is not a valid nice level.", strna(name));
286
287 *nl = m;
288 return 0;
289 }
290
291 static int json_dispatch_rlimit_value(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
292 rlim_t *ret = userdata;
293
294 if (json_variant_is_null(variant))
295 *ret = RLIM_INFINITY;
296 else if (json_variant_is_unsigned(variant)) {
297 uint64_t w;
298
299 w = json_variant_unsigned(variant);
300 if (w == RLIM_INFINITY || (uint64_t) w != json_variant_unsigned(variant))
301 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "Resource limit value '%s' is out of range.", name);
302
303 *ret = (rlim_t) w;
304 } else
305 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit value '%s' is not an unsigned integer.", name);
306
307 return 0;
308 }
309
310 static int json_dispatch_rlimits(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
311 struct rlimit** limits = userdata;
312 JsonVariant *value;
313 const char *key;
314 int r;
315
316 assert_se(limits);
317
318 if (json_variant_is_null(variant)) {
319 rlimit_free_all(limits);
320 return 0;
321 }
322
323 if (!json_variant_is_object(variant))
324 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
325
326 JSON_VARIANT_OBJECT_FOREACH(key, value, variant) {
327 JsonVariant *jcur, *jmax;
328 struct rlimit rl;
329 const char *p;
330 int l;
331
332 p = startswith(key, "RLIMIT_");
333 if (!p)
334 l = -SYNTHETIC_ERRNO(EINVAL);
335 else
336 l = rlimit_from_string(p);
337 if (l < 0)
338 return json_log(variant, flags, l, "Resource limit '%s' not known.", key);
339
340 if (!json_variant_is_object(value))
341 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' has invalid value.", key);
342
343 if (json_variant_elements(value) != 4)
344 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' value is does not have two fields as expected.", key);
345
346 jcur = json_variant_by_key(value, "cur");
347 if (!jcur)
348 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' lacks 'cur' field.", key);
349 r = json_dispatch_rlimit_value("cur", jcur, flags, &rl.rlim_cur);
350 if (r < 0)
351 return r;
352
353 jmax = json_variant_by_key(value, "max");
354 if (!jmax)
355 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' lacks 'max' field.", key);
356 r = json_dispatch_rlimit_value("max", jmax, flags, &rl.rlim_max);
357 if (r < 0)
358 return r;
359
360 if (limits[l])
361 *(limits[l]) = rl;
362 else {
363 limits[l] = newdup(struct rlimit, &rl, 1);
364 if (!limits[l])
365 return log_oom();
366 }
367 }
368
369 return 0;
370 }
371
372 static int json_dispatch_filename_or_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
373 char **s = ASSERT_PTR(userdata);
374 const char *n;
375 int r;
376
377 if (json_variant_is_null(variant)) {
378 *s = mfree(*s);
379 return 0;
380 }
381
382 if (!json_variant_is_string(variant))
383 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
384
385 n = json_variant_string(variant);
386 if (!filename_is_valid(n) && !path_is_normalized(n))
387 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid file name or normalized path.", strna(name));
388
389 r = free_and_strdup(s, n);
390 if (r < 0)
391 return json_log(variant, flags, r, "Failed to allocate string: %m");
392
393 return 0;
394 }
395
396 static int json_dispatch_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
397 char **s = userdata;
398 const char *n;
399 int r;
400
401 if (json_variant_is_null(variant)) {
402 *s = mfree(*s);
403 return 0;
404 }
405
406 if (!json_variant_is_string(variant))
407 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
408
409 n = json_variant_string(variant);
410 if (!path_is_normalized(n))
411 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a normalized file system path.", strna(name));
412 if (!path_is_absolute(n))
413 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an absolute file system path.", strna(name));
414
415 r = free_and_strdup(s, n);
416 if (r < 0)
417 return json_log(variant, flags, r, "Failed to allocate string: %m");
418
419 return 0;
420 }
421
422 static int json_dispatch_home_directory(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
423 char **s = userdata;
424 const char *n;
425 int r;
426
427 if (json_variant_is_null(variant)) {
428 *s = mfree(*s);
429 return 0;
430 }
431
432 if (!json_variant_is_string(variant))
433 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
434
435 n = json_variant_string(variant);
436 if (!valid_home(n))
437 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid home directory path.", strna(name));
438
439 r = free_and_strdup(s, n);
440 if (r < 0)
441 return json_log(variant, flags, r, "Failed to allocate string: %m");
442
443 return 0;
444 }
445
446 static int json_dispatch_image_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
447 char **s = userdata;
448 const char *n;
449 int r;
450
451 if (json_variant_is_null(variant)) {
452 *s = mfree(*s);
453 return 0;
454 }
455
456 if (!json_variant_is_string(variant))
457 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
458
459 n = json_variant_string(variant);
460 if (empty_or_root(n) || !path_is_valid(n) || !path_is_absolute(n))
461 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid image path.", strna(name));
462
463 r = free_and_strdup(s, n);
464 if (r < 0)
465 return json_log(variant, flags, r, "Failed to allocate string: %m");
466
467 return 0;
468 }
469
470 static int json_dispatch_umask(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
471 mode_t *m = userdata;
472 uint64_t k;
473
474 if (json_variant_is_null(variant)) {
475 *m = MODE_INVALID;
476 return 0;
477 }
478
479 if (!json_variant_is_unsigned(variant))
480 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
481
482 k = json_variant_unsigned(variant);
483 if (k > 0777)
484 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
485 "JSON field '%s' outside of valid range 0%s0777.",
486 strna(name), special_glyph(SPECIAL_GLYPH_ELLIPSIS));
487
488 *m = (mode_t) k;
489 return 0;
490 }
491
492 static int json_dispatch_access_mode(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
493 mode_t *m = userdata;
494 uint64_t k;
495
496 if (json_variant_is_null(variant)) {
497 *m = MODE_INVALID;
498 return 0;
499 }
500
501 if (!json_variant_is_unsigned(variant))
502 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
503
504 k = json_variant_unsigned(variant);
505 if (k > 07777)
506 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
507 "JSON field '%s' outside of valid range 0%s07777.",
508 strna(name), special_glyph(SPECIAL_GLYPH_ELLIPSIS));
509
510 *m = (mode_t) k;
511 return 0;
512 }
513
514 static int json_dispatch_environment(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
515 _cleanup_strv_free_ char **n = NULL;
516 char ***l = userdata;
517 int r;
518
519 if (json_variant_is_null(variant)) {
520 *l = strv_free(*l);
521 return 0;
522 }
523
524 if (!json_variant_is_array(variant))
525 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
526
527 for (size_t i = 0; i < json_variant_elements(variant); i++) {
528 JsonVariant *e;
529 const char *a;
530
531 e = json_variant_by_index(variant, i);
532 if (!json_variant_is_string(e))
533 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
534
535 assert_se(a = json_variant_string(e));
536
537 if (!env_assignment_is_valid(a))
538 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of environment variables.", strna(name));
539
540 r = strv_env_replace_strdup(&n, a);
541 if (r < 0)
542 return json_log_oom(variant, flags);
543 }
544
545 return strv_free_and_replace(*l, n);
546 }
547
548 static int json_dispatch_locale(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
549 char **s = userdata;
550 const char *n;
551 int r;
552
553 if (json_variant_is_null(variant)) {
554 *s = mfree(*s);
555 return 0;
556 }
557
558 if (!json_variant_is_string(variant))
559 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
560
561 n = json_variant_string(variant);
562
563 if (!locale_is_valid(n))
564 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid locale.", strna(name));
565
566 r = free_and_strdup(s, n);
567 if (r < 0)
568 return json_log(variant, flags, r, "Failed to allocate string: %m");
569
570 return 0;
571 }
572
573 static int json_dispatch_locales(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
574 _cleanup_strv_free_ char **n = NULL;
575 char ***l = userdata;
576 const char *locale;
577 JsonVariant *e;
578 int r;
579
580 if (json_variant_is_null(variant)) {
581 *l = strv_free(*l);
582 return 0;
583 }
584
585 if (!json_variant_is_array(variant))
586 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
587
588 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
589 if (!json_variant_is_string(e))
590 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
591
592 locale = json_variant_string(e);
593 if (!locale_is_valid(locale))
594 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of valid locales.", strna(name));
595
596 r = strv_extend(&n, locale);
597 if (r < 0)
598 return json_log_oom(variant, flags);
599 }
600
601 return strv_free_and_replace(*l, n);
602 }
603
604 JSON_DISPATCH_ENUM_DEFINE(json_dispatch_user_disposition, UserDisposition, user_disposition_from_string);
605 static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_user_storage, UserStorage, user_storage_from_string);
606
607 static int json_dispatch_tasks_or_memory_max(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
608 uint64_t *limit = userdata, k;
609
610 if (json_variant_is_null(variant)) {
611 *limit = UINT64_MAX;
612 return 0;
613 }
614
615 if (!json_variant_is_unsigned(variant))
616 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
617
618 k = json_variant_unsigned(variant);
619 if (k <= 0 || k >= UINT64_MAX)
620 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
621 "JSON field '%s' is not in valid range %" PRIu64 "%s%" PRIu64 ".",
622 strna(name), (uint64_t) 1, special_glyph(SPECIAL_GLYPH_ELLIPSIS), UINT64_MAX-1);
623
624 *limit = k;
625 return 0;
626 }
627
628 static int json_dispatch_weight(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
629 uint64_t *weight = userdata, k;
630
631 if (json_variant_is_null(variant)) {
632 *weight = UINT64_MAX;
633 return 0;
634 }
635
636 if (!json_variant_is_unsigned(variant))
637 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
638
639 k = json_variant_unsigned(variant);
640 if (k <= CGROUP_WEIGHT_MIN || k >= CGROUP_WEIGHT_MAX)
641 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
642 "JSON field '%s' is not in valid range %" PRIu64 "%s%" PRIu64 ".",
643 strna(name), (uint64_t) CGROUP_WEIGHT_MIN,
644 special_glyph(SPECIAL_GLYPH_ELLIPSIS), (uint64_t) CGROUP_WEIGHT_MAX);
645
646 *weight = k;
647 return 0;
648 }
649
650 int json_dispatch_user_group_list(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
651 _cleanup_strv_free_ char **l = NULL;
652 char ***list = userdata;
653 JsonVariant *e;
654 int r;
655
656 if (!json_variant_is_array(variant))
657 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
658
659 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
660
661 if (!json_variant_is_string(e))
662 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
663
664 if (!valid_user_group_name(json_variant_string(e), FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
665 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a valid user/group name: %s", json_variant_string(e));
666
667 r = strv_extend(&l, json_variant_string(e));
668 if (r < 0)
669 return json_log(e, flags, r, "Failed to append array element: %m");
670 }
671
672 r = strv_extend_strv(list, l, true);
673 if (r < 0)
674 return json_log(variant, flags, r, "Failed to merge user/group arrays: %m");
675
676 return 0;
677 }
678
679 static int dispatch_secret(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
680
681 static const JsonDispatch secret_dispatch_table[] = {
682 { "password", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, password), 0 },
683 { "tokenPin", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
684 { "pkcs11Pin", /* legacy alias */ _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
685 { "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 },
686 { "fido2UserPresencePermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_presence_permitted), 0 },
687 { "fido2UserVerificationPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_verification_permitted), 0 },
688 {},
689 };
690
691 return json_dispatch(variant, secret_dispatch_table, flags, userdata);
692 }
693
694 static int dispatch_pkcs11_uri(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
695 char **s = userdata;
696 const char *n;
697 int r;
698
699 if (json_variant_is_null(variant)) {
700 *s = mfree(*s);
701 return 0;
702 }
703
704 if (!json_variant_is_string(variant))
705 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
706
707 n = json_variant_string(variant);
708 if (!pkcs11_uri_valid(n))
709 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
710
711 r = free_and_strdup(s, n);
712 if (r < 0)
713 return json_log(variant, flags, r, "Failed to allocate string: %m");
714
715 return 0;
716 }
717
718 static int dispatch_pkcs11_uri_array(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
719 _cleanup_strv_free_ char **z = NULL;
720 char ***l = userdata;
721 JsonVariant *e;
722 int r;
723
724 if (json_variant_is_null(variant)) {
725 *l = strv_free(*l);
726 return 0;
727 }
728
729 if (json_variant_is_string(variant)) {
730 const char *n;
731
732 n = json_variant_string(variant);
733 if (!pkcs11_uri_valid(n))
734 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
735
736 z = strv_new(n);
737 if (!z)
738 return log_oom();
739
740 } else {
741
742 if (!json_variant_is_array(variant))
743 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string or array of strings.", strna(name));
744
745 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
746 const char *n;
747
748 if (!json_variant_is_string(e))
749 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
750
751 n = json_variant_string(e);
752 if (!pkcs11_uri_valid(n))
753 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element in '%s' is not a valid RFC7512 PKCS#11 URI: %s", strna(name), n);
754
755 r = strv_extend(&z, n);
756 if (r < 0)
757 return log_oom();
758 }
759 }
760
761 strv_free_and_replace(*l, z);
762 return 0;
763 }
764
765 static int dispatch_pkcs11_key_data(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
766 Pkcs11EncryptedKey *k = userdata;
767 size_t l;
768 void *b;
769 int r;
770
771 if (json_variant_is_null(variant)) {
772 k->data = erase_and_free(k->data);
773 k->size = 0;
774 return 0;
775 }
776
777 if (!json_variant_is_string(variant))
778 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
779
780 r = unbase64mem(json_variant_string(variant), &b, &l);
781 if (r < 0)
782 return json_log(variant, flags, r, "Failed to decode encrypted PKCS#11 key: %m");
783
784 erase_and_free(k->data);
785 k->data = b;
786 k->size = l;
787
788 return 0;
789 }
790
791 static int dispatch_pkcs11_key(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
792 UserRecord *h = userdata;
793 JsonVariant *e;
794 int r;
795
796 if (!json_variant_is_array(variant))
797 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
798
799 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
800 Pkcs11EncryptedKey *array, *k;
801
802 static const JsonDispatch pkcs11_key_dispatch_table[] = {
803 { "uri", JSON_VARIANT_STRING, dispatch_pkcs11_uri, offsetof(Pkcs11EncryptedKey, uri), JSON_MANDATORY },
804 { "data", JSON_VARIANT_STRING, dispatch_pkcs11_key_data, 0, JSON_MANDATORY },
805 { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Pkcs11EncryptedKey, hashed_password), JSON_MANDATORY },
806 {},
807 };
808
809 if (!json_variant_is_object(e))
810 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not an object.");
811
812 array = reallocarray(h->pkcs11_encrypted_key, h->n_pkcs11_encrypted_key + 1, sizeof(Pkcs11EncryptedKey));
813 if (!array)
814 return log_oom();
815
816 h->pkcs11_encrypted_key = array;
817 k = h->pkcs11_encrypted_key + h->n_pkcs11_encrypted_key;
818 *k = (Pkcs11EncryptedKey) {};
819
820 r = json_dispatch(e, pkcs11_key_dispatch_table, flags, k);
821 if (r < 0) {
822 pkcs11_encrypted_key_done(k);
823 return r;
824 }
825
826 h->n_pkcs11_encrypted_key++;
827 }
828
829 return 0;
830 }
831
832 static int dispatch_fido2_hmac_credential(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
833 Fido2HmacCredential *k = userdata;
834 size_t l;
835 void *b;
836 int r;
837
838 if (json_variant_is_null(variant)) {
839 k->id = mfree(k->id);
840 k->size = 0;
841 return 0;
842 }
843
844 if (!json_variant_is_string(variant))
845 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
846
847 r = unbase64mem(json_variant_string(variant), &b, &l);
848 if (r < 0)
849 return json_log(variant, flags, r, "Failed to decode FIDO2 credential ID: %m");
850
851 free_and_replace(k->id, b);
852 k->size = l;
853
854 return 0;
855 }
856
857 static int dispatch_fido2_hmac_credential_array(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
858 UserRecord *h = userdata;
859 JsonVariant *e;
860 int r;
861
862 if (!json_variant_is_array(variant))
863 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
864
865 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
866 Fido2HmacCredential *array;
867 size_t l;
868 void *b;
869
870 if (!json_variant_is_string(e))
871 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
872
873 array = reallocarray(h->fido2_hmac_credential, h->n_fido2_hmac_credential + 1, sizeof(Fido2HmacCredential));
874 if (!array)
875 return log_oom();
876
877 r = unbase64mem(json_variant_string(e), &b, &l);
878 if (r < 0)
879 return json_log(variant, flags, r, "Failed to decode FIDO2 credential ID: %m");
880
881 h->fido2_hmac_credential = array;
882
883 h->fido2_hmac_credential[h->n_fido2_hmac_credential++] = (Fido2HmacCredential) {
884 .id = b,
885 .size = l,
886 };
887 }
888
889 return 0;
890 }
891
892 static int dispatch_fido2_hmac_salt_value(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
893 Fido2HmacSalt *k = userdata;
894 size_t l;
895 void *b;
896 int r;
897
898 if (json_variant_is_null(variant)) {
899 k->salt = erase_and_free(k->salt);
900 k->salt_size = 0;
901 return 0;
902 }
903
904 if (!json_variant_is_string(variant))
905 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
906
907 r = unbase64mem(json_variant_string(variant), &b, &l);
908 if (r < 0)
909 return json_log(variant, flags, r, "Failed to decode FIDO2 salt: %m");
910
911 erase_and_free(k->salt);
912 k->salt = b;
913 k->salt_size = l;
914
915 return 0;
916 }
917
918 static int dispatch_fido2_hmac_salt(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
919 UserRecord *h = userdata;
920 JsonVariant *e;
921 int r;
922
923 if (!json_variant_is_array(variant))
924 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
925
926 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
927 Fido2HmacSalt *array, *k;
928
929 static const JsonDispatch fido2_hmac_salt_dispatch_table[] = {
930 { "credential", JSON_VARIANT_STRING, dispatch_fido2_hmac_credential, offsetof(Fido2HmacSalt, credential), JSON_MANDATORY },
931 { "salt", JSON_VARIANT_STRING, dispatch_fido2_hmac_salt_value, 0, JSON_MANDATORY },
932 { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Fido2HmacSalt, hashed_password), JSON_MANDATORY },
933 { "up", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, up), 0 },
934 { "uv", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, uv), 0 },
935 { "clientPin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, client_pin), 0 },
936 {},
937 };
938
939 if (!json_variant_is_object(e))
940 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not an object.");
941
942 array = reallocarray(h->fido2_hmac_salt, h->n_fido2_hmac_salt + 1, sizeof(Fido2HmacSalt));
943 if (!array)
944 return log_oom();
945
946 h->fido2_hmac_salt = array;
947 k = h->fido2_hmac_salt + h->n_fido2_hmac_salt;
948 *k = (Fido2HmacSalt) {
949 .uv = -1,
950 .up = -1,
951 .client_pin = -1,
952 };
953
954 r = json_dispatch(e, fido2_hmac_salt_dispatch_table, flags, k);
955 if (r < 0) {
956 fido2_hmac_salt_done(k);
957 return r;
958 }
959
960 h->n_fido2_hmac_salt++;
961 }
962
963 return 0;
964 }
965
966 static int dispatch_recovery_key(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
967 UserRecord *h = userdata;
968 JsonVariant *e;
969 int r;
970
971 if (!json_variant_is_array(variant))
972 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
973
974 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
975 RecoveryKey *array, *k;
976
977 static const JsonDispatch recovery_key_dispatch_table[] = {
978 { "type", JSON_VARIANT_STRING, json_dispatch_string, 0, JSON_MANDATORY },
979 { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(RecoveryKey, hashed_password), JSON_MANDATORY },
980 {},
981 };
982
983 if (!json_variant_is_object(e))
984 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not an object.");
985
986 array = reallocarray(h->recovery_key, h->n_recovery_key + 1, sizeof(RecoveryKey));
987 if (!array)
988 return log_oom();
989
990 h->recovery_key = array;
991 k = h->recovery_key + h->n_recovery_key;
992 *k = (RecoveryKey) {};
993
994 r = json_dispatch(e, recovery_key_dispatch_table, flags, k);
995 if (r < 0) {
996 recovery_key_done(k);
997 return r;
998 }
999
1000 h->n_recovery_key++;
1001 }
1002
1003 return 0;
1004 }
1005
1006 static int dispatch_auto_resize_mode(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1007 AutoResizeMode *mode = userdata, m;
1008
1009 assert_se(mode);
1010
1011 if (json_variant_is_null(variant)) {
1012 *mode = _AUTO_RESIZE_MODE_INVALID;
1013 return 0;
1014 }
1015
1016 if (json_variant_is_boolean(variant)) {
1017 *mode = json_variant_boolean(variant) ? AUTO_RESIZE_SHRINK_AND_GROW : AUTO_RESIZE_OFF;
1018 return 0;
1019 }
1020
1021 if (!json_variant_is_string(variant))
1022 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string, boolean or null.", strna(name));
1023
1024 m = auto_resize_mode_from_string(json_variant_string(variant));
1025 if (m < 0)
1026 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid automatic resize mode.", strna(name));
1027
1028 *mode = m;
1029 return 0;
1030 }
1031
1032 static int dispatch_rebalance_weight(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1033 uint64_t *rebalance_weight = userdata;
1034 uintmax_t u;
1035
1036 assert_se(rebalance_weight);
1037
1038 if (json_variant_is_null(variant)) {
1039 *rebalance_weight = REBALANCE_WEIGHT_UNSET;
1040 return 0;
1041 }
1042
1043 if (json_variant_is_boolean(variant)) {
1044 *rebalance_weight = json_variant_boolean(variant) ? REBALANCE_WEIGHT_DEFAULT : REBALANCE_WEIGHT_OFF;
1045 return 0;
1046 }
1047
1048 if (!json_variant_is_unsigned(variant))
1049 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer, boolean or null.", strna(name));
1050
1051 u = json_variant_unsigned(variant);
1052 if (u >= REBALANCE_WEIGHT_MIN && u <= REBALANCE_WEIGHT_MAX)
1053 *rebalance_weight = (uint64_t) u;
1054 else if (u == 0)
1055 *rebalance_weight = REBALANCE_WEIGHT_OFF;
1056 else
1057 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
1058 "Rebalance weight is out of valid range %" PRIu64 "%s%" PRIu64 ".",
1059 REBALANCE_WEIGHT_MIN, special_glyph(SPECIAL_GLYPH_ELLIPSIS), REBALANCE_WEIGHT_MAX);
1060
1061 return 0;
1062 }
1063
1064 static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1065
1066 static const JsonDispatch privileged_dispatch_table[] = {
1067 { "passwordHint", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, password_hint), 0 },
1068 { "hashedPassword", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, hashed_password), JSON_SAFE },
1069 { "sshAuthorizedKeys", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, ssh_authorized_keys), 0 },
1070 { "pkcs11EncryptedKey", JSON_VARIANT_ARRAY, dispatch_pkcs11_key, 0, 0 },
1071 { "fido2HmacSalt", JSON_VARIANT_ARRAY, dispatch_fido2_hmac_salt, 0, 0 },
1072 { "recoveryKey", JSON_VARIANT_ARRAY, dispatch_recovery_key, 0, 0 },
1073 {},
1074 };
1075
1076 return json_dispatch(variant, privileged_dispatch_table, flags, userdata);
1077 }
1078
1079 static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1080
1081 static const JsonDispatch binding_dispatch_table[] = {
1082 { "blobDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, blob_directory), 0 },
1083 { "imagePath", JSON_VARIANT_STRING, json_dispatch_image_path, offsetof(UserRecord, image_path), 0 },
1084 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
1085 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1086 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1087 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1088 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1089 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1090 { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 },
1091 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1092 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1093 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1094 { "luksVolumeKeySize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1095 {},
1096 };
1097
1098 JsonVariant *m;
1099 sd_id128_t mid;
1100 int r;
1101
1102 if (!variant)
1103 return 0;
1104
1105 if (!json_variant_is_object(variant))
1106 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
1107
1108 r = sd_id128_get_machine(&mid);
1109 if (r < 0)
1110 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
1111
1112 m = json_variant_by_key(variant, SD_ID128_TO_STRING(mid));
1113 if (!m)
1114 return 0;
1115
1116 return json_dispatch(m, binding_dispatch_table, flags, userdata);
1117 }
1118
1119 static int dispatch_blob_manifest(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1120 _cleanup_hashmap_free_ Hashmap *manifest = NULL;
1121 Hashmap **ret = ASSERT_PTR(userdata);
1122 JsonVariant *value;
1123 const char *key;
1124 int r;
1125
1126 if (!variant)
1127 return 0;
1128
1129 if (!json_variant_is_object(variant))
1130 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
1131
1132 JSON_VARIANT_OBJECT_FOREACH(key, value, variant) {
1133 _cleanup_free_ char *filename = NULL;
1134 _cleanup_free_ uint8_t *hash = NULL;
1135
1136 if (!json_variant_is_string(value))
1137 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Blob entry '%s' has invalid hash.", key);
1138
1139 if (!suitable_blob_filename(key))
1140 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Blob entry '%s' has invalid filename.", key);
1141
1142 filename = strdup(key);
1143 if (!filename)
1144 return json_log_oom(value, flags);
1145
1146 hash = malloc(SHA256_DIGEST_SIZE);
1147 if (!hash)
1148 return json_log_oom(value, flags);
1149
1150 r = parse_sha256(json_variant_string(value), hash);
1151 if (r < 0)
1152 return json_log(value, flags, r, "Blob entry '%s' has invalid hash: %s", filename, json_variant_string(value));
1153
1154 r = hashmap_ensure_put(&manifest, &path_hash_ops_free_free, filename, hash);
1155 if (r < 0)
1156 return json_log(value, flags, r, "Failed to insert blob manifest entry '%s': %m", filename);
1157 TAKE_PTR(filename); /* Ownership transfers to hashmap */
1158 TAKE_PTR(hash);
1159 }
1160
1161 hashmap_free_and_replace(*ret, manifest);
1162 return 0;
1163 }
1164
1165 int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags) {
1166 sd_id128_t mid;
1167 int r;
1168
1169 r = sd_id128_get_machine(&mid);
1170 if (r < 0)
1171 return json_log(ids, flags, r, "Failed to acquire machine ID: %m");
1172
1173 if (json_variant_is_string(ids)) {
1174 sd_id128_t k;
1175
1176 r = sd_id128_from_string(json_variant_string(ids), &k);
1177 if (r < 0) {
1178 json_log(ids, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(ids));
1179 return 0;
1180 }
1181
1182 return sd_id128_equal(mid, k);
1183 }
1184
1185 if (json_variant_is_array(ids)) {
1186 JsonVariant *e;
1187
1188 JSON_VARIANT_ARRAY_FOREACH(e, ids) {
1189 sd_id128_t k;
1190
1191 if (!json_variant_is_string(e)) {
1192 json_log(e, flags, 0, "Machine ID is not a string, ignoring: %m");
1193 continue;
1194 }
1195
1196 r = sd_id128_from_string(json_variant_string(e), &k);
1197 if (r < 0) {
1198 json_log(e, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(e));
1199 continue;
1200 }
1201
1202 if (sd_id128_equal(mid, k))
1203 return true;
1204 }
1205
1206 return false;
1207 }
1208
1209 json_log(ids, flags, 0, "Machine ID is not a string or array of strings, ignoring: %m");
1210 return false;
1211 }
1212
1213 int per_machine_hostname_match(JsonVariant *hns, JsonDispatchFlags flags) {
1214 _cleanup_free_ char *hn = NULL;
1215 int r;
1216
1217 r = gethostname_strict(&hn);
1218 if (r == -ENXIO) {
1219 json_log(hns, flags, r, "No hostname set, not matching perMachine hostname record: %m");
1220 return false;
1221 }
1222 if (r < 0)
1223 return json_log(hns, flags, r, "Failed to acquire hostname: %m");
1224
1225 if (json_variant_is_string(hns))
1226 return streq(json_variant_string(hns), hn);
1227
1228 if (json_variant_is_array(hns)) {
1229 JsonVariant *e;
1230
1231 JSON_VARIANT_ARRAY_FOREACH(e, hns) {
1232
1233 if (!json_variant_is_string(e)) {
1234 json_log(e, flags, 0, "Hostname is not a string, ignoring: %m");
1235 continue;
1236 }
1237
1238 if (streq(json_variant_string(hns), hn))
1239 return true;
1240 }
1241
1242 return false;
1243 }
1244
1245 json_log(hns, flags, 0, "Hostname is not a string or array of strings, ignoring: %m");
1246 return false;
1247 }
1248
1249 int per_machine_match(JsonVariant *entry, JsonDispatchFlags flags) {
1250 JsonVariant *m;
1251 int r;
1252
1253 assert(json_variant_is_object(entry));
1254
1255 m = json_variant_by_key(entry, "matchMachineId");
1256 if (m) {
1257 r = per_machine_id_match(m, flags);
1258 if (r < 0)
1259 return r;
1260 if (r > 0)
1261 return true;
1262 }
1263
1264 m = json_variant_by_key(entry, "matchHostname");
1265 if (m) {
1266 r = per_machine_hostname_match(m, flags);
1267 if (r < 0)
1268 return r;
1269 if (r > 0)
1270 return true;
1271 }
1272
1273 return false;
1274 }
1275
1276 static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1277
1278 static const JsonDispatch per_machine_dispatch_table[] = {
1279 { "matchMachineId", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
1280 { "matchHostname", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
1281 { "blobDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, blob_directory), 0 },
1282 { "blobManifest", JSON_VARIANT_OBJECT, dispatch_blob_manifest, offsetof(UserRecord, blob_manifest), 0 },
1283 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
1284 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
1285 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
1286 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
1287 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
1288 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
1289 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_locale, offsetof(UserRecord, preferred_language), 0 },
1290 { "additionalLanguages", JSON_VARIANT_ARRAY, json_dispatch_locales, offsetof(UserRecord, additional_languages), 0 },
1291 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
1292 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
1293 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
1294 { "notBeforeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
1295 { "notAfterUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
1296 { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 },
1297 { "diskSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
1298 { "diskSizeRelative", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
1299 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
1300 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1301 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
1302 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
1303 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
1304 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
1305 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
1306 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
1307 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
1308 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
1309 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
1310 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
1311 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
1312 { "cifsExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_extra_mount_options), 0 },
1313 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
1314 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1315 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1316 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
1317 { "capabilityBoundingSet", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(UserRecord, capability_bounding_set), JSON_SAFE },
1318 { "capabilityAmbientSet", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(UserRecord, capability_ambient_set), JSON_SAFE },
1319 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1320 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1321 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1322 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1323 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0, },
1324 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0, },
1325 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1326 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1327 { "luksVolumeKeySize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1328 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
1329 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
1330 { "luksPbkdfForceIterations", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_force_iterations), 0 },
1331 { "luksPbkdfTimeCostUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
1332 { "luksPbkdfMemoryCost", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
1333 { "luksPbkdfParallelThreads", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
1334 { "luksSectorSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_sector_size), 0 },
1335 { "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
1336 { "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
1337 { "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
1338 { "rebalanceWeight", _JSON_VARIANT_TYPE_INVALID, dispatch_rebalance_weight, offsetof(UserRecord, rebalance_weight), 0 },
1339 { "rateLimitIntervalUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
1340 { "rateLimitBurst", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
1341 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
1342 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
1343 { "stopDelayUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
1344 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
1345 { "passwordChangeMinUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
1346 { "passwordChangeMaxUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
1347 { "passwordChangeWarnUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
1348 { "passwordChangeInactiveUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
1349 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
1350 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
1351 { "fido2HmacCredential", JSON_VARIANT_ARRAY, dispatch_fido2_hmac_credential_array, 0, 0 },
1352 {},
1353 };
1354
1355 JsonVariant *e;
1356 int r;
1357
1358 if (!variant)
1359 return 0;
1360
1361 if (!json_variant_is_array(variant))
1362 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
1363
1364 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
1365 if (!json_variant_is_object(e))
1366 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
1367
1368 r = per_machine_match(e, flags);
1369 if (r < 0)
1370 return r;
1371 if (r == 0)
1372 continue;
1373
1374 r = json_dispatch(e, per_machine_dispatch_table, flags, userdata);
1375 if (r < 0)
1376 return r;
1377 }
1378
1379 return 0;
1380 }
1381
1382 static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1383
1384 static const JsonDispatch status_dispatch_table[] = {
1385 { "diskUsage", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_usage), 0 },
1386 { "diskFree", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_free), 0 },
1387 { "diskSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
1388 { "diskCeiling", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_ceiling), 0 },
1389 { "diskFloor", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_floor), 0 },
1390 { "state", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, state), JSON_SAFE },
1391 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1392 { "signedLocally", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, signed_locally), 0 },
1393 { "goodAuthenticationCounter", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, good_authentication_counter), 0 },
1394 { "badAuthenticationCounter", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, bad_authentication_counter), 0 },
1395 { "lastGoodAuthenticationUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, last_good_authentication_usec), 0 },
1396 { "lastBadAuthenticationUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, last_bad_authentication_usec), 0 },
1397 { "rateLimitBeginUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
1398 { "rateLimitCount", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
1399 { "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
1400 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1401 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1402 { "fallbackShell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, fallback_shell), 0 },
1403 { "fallbackHomeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, fallback_home_directory), 0 },
1404 { "useFallback", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, use_fallback), 0 },
1405 {},
1406 };
1407
1408 JsonVariant *m;
1409 sd_id128_t mid;
1410 int r;
1411
1412 if (!variant)
1413 return 0;
1414
1415 if (!json_variant_is_object(variant))
1416 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
1417
1418 r = sd_id128_get_machine(&mid);
1419 if (r < 0)
1420 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
1421
1422 m = json_variant_by_key(variant, SD_ID128_TO_STRING(mid));
1423 if (!m)
1424 return 0;
1425
1426 return json_dispatch(m, status_dispatch_table, flags, userdata);
1427 }
1428
1429 int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
1430 const char *suffix;
1431 char *z;
1432
1433 assert(storage >= 0);
1434 assert(user_name_and_realm);
1435 assert(ret);
1436
1437 if (storage == USER_LUKS)
1438 suffix = ".home";
1439 else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
1440 suffix = ".homedir";
1441 else {
1442 *ret = NULL;
1443 return 0;
1444 }
1445
1446 z = strjoin(get_home_root(), "/", user_name_and_realm, suffix);
1447 if (!z)
1448 return -ENOMEM;
1449
1450 *ret = path_simplify(z);
1451 return 1;
1452 }
1453
1454 static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
1455 int r;
1456
1457 assert(h);
1458
1459 if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
1460 return 0;
1461
1462 assert(h->user_name);
1463
1464 if (!h->user_name_and_realm_auto && h->realm) {
1465 h->user_name_and_realm_auto = strjoin(h->user_name, "@", h->realm);
1466 if (!h->user_name_and_realm_auto)
1467 return json_log_oom(h->json, json_flags);
1468 }
1469
1470 /* Let's add in the following automatisms only for regular users, they don't make sense for any others */
1471 if (user_record_disposition(h) != USER_REGULAR)
1472 return 0;
1473
1474 if (!h->home_directory && !h->home_directory_auto) {
1475 h->home_directory_auto = path_join(get_home_root(), h->user_name);
1476 if (!h->home_directory_auto)
1477 return json_log_oom(h->json, json_flags);
1478 }
1479
1480 if (!h->image_path && !h->image_path_auto) {
1481 r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto);
1482 if (r < 0)
1483 return json_log(h->json, json_flags, r, "Failed to determine default image path: %m");
1484 }
1485
1486 return 0;
1487 }
1488
1489 int user_group_record_mangle(
1490 JsonVariant *v,
1491 UserRecordLoadFlags load_flags,
1492 JsonVariant **ret_variant,
1493 UserRecordMask *ret_mask) {
1494
1495 static const struct {
1496 UserRecordMask mask;
1497 const char *name;
1498 } mask_field[] = {
1499 { USER_RECORD_PRIVILEGED, "privileged" },
1500 { USER_RECORD_SECRET, "secret" },
1501 { USER_RECORD_BINDING, "binding" },
1502 { USER_RECORD_PER_MACHINE, "perMachine" },
1503 { USER_RECORD_STATUS, "status" },
1504 { USER_RECORD_SIGNATURE, "signature" },
1505 };
1506
1507 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1508 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
1509 JsonVariant *array[ELEMENTSOF(mask_field) * 2];
1510 size_t n_retain = 0;
1511 UserRecordMask m = 0;
1512 int r;
1513
1514 assert((load_flags & _USER_RECORD_MASK_MAX) == 0); /* detect mistakes when accidentally passing
1515 * UserRecordMask bit masks as UserRecordLoadFlags
1516 * value */
1517
1518 assert(v);
1519 assert(ret_variant);
1520 assert(ret_mask);
1521
1522 /* Note that this function is shared with the group record parser, hence we try to be generic in our
1523 * log message wording here, to cover both cases. */
1524
1525 if (!json_variant_is_object(v))
1526 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is not a JSON object, refusing.");
1527
1528 if (USER_RECORD_ALLOW_MASK(load_flags) == 0) /* allow nothing? */
1529 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Nothing allowed in record, refusing.");
1530
1531 if (USER_RECORD_STRIP_MASK(load_flags) == _USER_RECORD_MASK_MAX) /* strip everything? */
1532 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing.");
1533
1534 /* Check if we have the special sections and if they match our flags set */
1535 for (size_t i = 0; i < ELEMENTSOF(mask_field); i++) {
1536 JsonVariant *e, *k;
1537
1538 if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) {
1539 if (!w)
1540 w = json_variant_ref(v);
1541
1542 r = json_variant_filter(&w, STRV_MAKE(mask_field[i].name));
1543 if (r < 0)
1544 return json_log(w, json_flags, r, "Failed to remove field from variant: %m");
1545
1546 continue;
1547 }
1548
1549 e = json_variant_by_key_full(v, mask_field[i].name, &k);
1550 if (e) {
1551 if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), mask_field[i].mask))
1552 return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", mask_field[i].name);
1553
1554 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1555 array[n_retain++] = k;
1556 array[n_retain++] = e;
1557 }
1558
1559 m |= mask_field[i].mask;
1560 } else {
1561 if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), mask_field[i].mask))
1562 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", mask_field[i].name);
1563 }
1564 }
1565
1566 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1567 /* If we are supposed to strip regular items, then let's instead just allocate a new object
1568 * with just the stuff we need. */
1569
1570 w = json_variant_unref(w);
1571 r = json_variant_new_object(&w, array, n_retain);
1572 if (r < 0)
1573 return json_log(v, json_flags, r, "Failed to allocate new object: %m");
1574 } else
1575 /* And now check if there's anything else in the record */
1576 for (size_t i = 0; i < json_variant_elements(v); i += 2) {
1577 const char *f;
1578 bool special = false;
1579
1580 assert_se(f = json_variant_string(json_variant_by_index(v, i)));
1581
1582 for (size_t j = 0; j < ELEMENTSOF(mask_field); j++)
1583 if (streq(f, mask_field[j].name)) { /* already covered in the loop above */
1584 special = true;
1585 continue;
1586 }
1587
1588 if (!special) {
1589 if ((load_flags & (USER_RECORD_ALLOW_REGULAR|USER_RECORD_REQUIRE_REGULAR)) == 0)
1590 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", f);
1591
1592 m |= USER_RECORD_REGULAR;
1593 break;
1594 }
1595 }
1596
1597 if (FLAGS_SET(load_flags, USER_RECORD_REQUIRE_REGULAR) && !FLAGS_SET(m, USER_RECORD_REGULAR))
1598 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks basic identity fields, which are required.");
1599
1600 if (!FLAGS_SET(load_flags, USER_RECORD_EMPTY_OK) && m == 0)
1601 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is empty.");
1602
1603 if (w)
1604 *ret_variant = TAKE_PTR(w);
1605 else
1606 *ret_variant = json_variant_ref(v);
1607
1608 *ret_mask = m;
1609 return 0;
1610 }
1611
1612 int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
1613
1614 static const JsonDispatch user_dispatch_table[] = {
1615 { "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
1616 { "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
1617 { "blobDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, blob_directory), 0 },
1618 { "blobManifest", JSON_VARIANT_OBJECT, dispatch_blob_manifest, offsetof(UserRecord, blob_manifest), 0 },
1619 { "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
1620 { "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
1621 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
1622 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
1623 { "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(UserRecord, disposition), 0 },
1624 { "lastChangeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, last_change_usec), 0 },
1625 { "lastPasswordChangeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, last_password_change_usec), 0 },
1626 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
1627 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
1628 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
1629 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
1630 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_locale, offsetof(UserRecord, preferred_language), 0 },
1631 { "additionalLanguages", JSON_VARIANT_ARRAY, json_dispatch_locales, offsetof(UserRecord, additional_languages), 0 },
1632 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
1633 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
1634 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
1635 { "notBeforeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
1636 { "notAfterUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
1637 { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 },
1638 { "diskSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
1639 { "diskSizeRelative", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
1640 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
1641 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1642 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
1643 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
1644 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
1645 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
1646 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
1647 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
1648 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
1649 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
1650 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
1651 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
1652 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
1653 { "cifsExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_extra_mount_options), 0 },
1654 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
1655 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
1656 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1657 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1658 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
1659 { "capabilityBoundingSet", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(UserRecord, capability_bounding_set), JSON_SAFE },
1660 { "capabilityAmbientSet", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(UserRecord, capability_ambient_set), JSON_SAFE },
1661 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1662 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1663 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1664 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1665 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0 },
1666 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0 },
1667 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1668 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1669 { "luksVolumeKeySize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1670 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
1671 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
1672 { "luksPbkdfForceIterations", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_force_iterations), 0 },
1673 { "luksPbkdfTimeCostUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
1674 { "luksPbkdfMemoryCost", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
1675 { "luksPbkdfParallelThreads", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
1676 { "luksSectorSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, luks_sector_size), 0 },
1677 { "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
1678 { "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
1679 { "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
1680 { "rebalanceWeight", _JSON_VARIANT_TYPE_INVALID, dispatch_rebalance_weight, offsetof(UserRecord, rebalance_weight), 0 },
1681 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1682 { "rateLimitIntervalUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
1683 { "rateLimitBurst", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
1684 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
1685 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
1686 { "stopDelayUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
1687 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
1688 { "passwordChangeMinUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
1689 { "passwordChangeMaxUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
1690 { "passwordChangeWarnUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
1691 { "passwordChangeInactiveUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
1692 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
1693 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
1694 { "fido2HmacCredential", JSON_VARIANT_ARRAY, dispatch_fido2_hmac_credential_array, 0, 0 },
1695 { "recoveryKeyType", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(UserRecord, recovery_key_type), 0 },
1696
1697 { "secret", JSON_VARIANT_OBJECT, dispatch_secret, 0, 0 },
1698 { "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
1699
1700 /* Ignore the perMachine, binding, status stuff here, and process it later, so that it overrides whatever is set above */
1701 { "perMachine", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1702 { "binding", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1703 { "status", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1704
1705 /* Ignore 'signature', we check it with explicit accessors instead */
1706 { "signature", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1707 {},
1708 };
1709
1710 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1711 int r;
1712
1713 assert(h);
1714 assert(!h->json);
1715
1716 /* Note that this call will leave a half-initialized record around on failure! */
1717
1718 r = user_group_record_mangle(v, load_flags, &h->json, &h->mask);
1719 if (r < 0)
1720 return r;
1721
1722 r = json_dispatch(h->json, user_dispatch_table, json_flags | JSON_ALLOW_EXTENSIONS, h);
1723 if (r < 0)
1724 return r;
1725
1726 /* During the parsing operation above we ignored the 'perMachine', 'binding' and 'status' fields,
1727 * since we want them to override the global options. Let's process them now. */
1728
1729 r = dispatch_per_machine("perMachine", json_variant_by_key(h->json, "perMachine"), json_flags, h);
1730 if (r < 0)
1731 return r;
1732
1733 r = dispatch_binding("binding", json_variant_by_key(h->json, "binding"), json_flags, h);
1734 if (r < 0)
1735 return r;
1736
1737 r = dispatch_status("status", json_variant_by_key(h->json, "status"), json_flags, h);
1738 if (r < 0)
1739 return r;
1740
1741 if (FLAGS_SET(h->mask, USER_RECORD_REGULAR) && !h->user_name)
1742 return json_log(h->json, json_flags, SYNTHETIC_ERRNO(EINVAL), "User name field missing, refusing.");
1743
1744 r = user_record_augment(h, json_flags);
1745 if (r < 0)
1746 return r;
1747
1748 return 0;
1749 }
1750
1751 int user_record_build(UserRecord **ret, ...) {
1752 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1753 _cleanup_(user_record_unrefp) UserRecord *u = NULL;
1754 va_list ap;
1755 int r;
1756
1757 assert(ret);
1758
1759 va_start(ap, ret);
1760 r = json_buildv(&v, ap);
1761 va_end(ap);
1762
1763 if (r < 0)
1764 return r;
1765
1766 u = user_record_new();
1767 if (!u)
1768 return -ENOMEM;
1769
1770 r = user_record_load(u, v, USER_RECORD_LOAD_FULL);
1771 if (r < 0)
1772 return r;
1773
1774 *ret = TAKE_PTR(u);
1775 return 0;
1776 }
1777
1778 const char *user_record_user_name_and_realm(UserRecord *h) {
1779 assert(h);
1780
1781 /* Return the pre-initialized joined string if it is defined */
1782 if (h->user_name_and_realm_auto)
1783 return h->user_name_and_realm_auto;
1784
1785 /* If it's not defined then we cannot have a realm */
1786 assert(!h->realm);
1787 return h->user_name;
1788 }
1789
1790 UserStorage user_record_storage(UserRecord *h) {
1791 assert(h);
1792
1793 if (h->storage >= 0)
1794 return h->storage;
1795
1796 return USER_CLASSIC;
1797 }
1798
1799 const char *user_record_file_system_type(UserRecord *h) {
1800 assert(h);
1801
1802 return h->file_system_type ?: "btrfs";
1803 }
1804
1805 const char *user_record_skeleton_directory(UserRecord *h) {
1806 assert(h);
1807
1808 return h->skeleton_directory ?: "/etc/skel";
1809 }
1810
1811 mode_t user_record_access_mode(UserRecord *h) {
1812 assert(h);
1813
1814 return h->access_mode != MODE_INVALID ? h->access_mode : 0700;
1815 }
1816
1817 static const char *user_record_home_directory_real(UserRecord *h) {
1818 assert(h);
1819
1820 if (h->home_directory)
1821 return h->home_directory;
1822 if (h->home_directory_auto)
1823 return h->home_directory_auto;
1824
1825 /* The root user is special, hence be special about it */
1826 if (streq_ptr(h->user_name, "root"))
1827 return "/root";
1828
1829 return "/";
1830 }
1831
1832 const char* user_record_home_directory(UserRecord *h) {
1833 assert(h);
1834
1835 if (h->use_fallback && h->fallback_home_directory)
1836 return h->fallback_home_directory;
1837
1838 return user_record_home_directory_real(h);
1839 }
1840
1841 const char *user_record_image_path(UserRecord *h) {
1842 assert(h);
1843
1844 if (h->image_path)
1845 return h->image_path;
1846 if (h->image_path_auto)
1847 return h->image_path_auto;
1848
1849 /* For some storage types the image is the home directory itself. (But let's ignore the fallback logic for it) */
1850 return IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT) ?
1851 user_record_home_directory_real(h) : NULL;
1852 }
1853
1854 const char *user_record_cifs_user_name(UserRecord *h) {
1855 assert(h);
1856
1857 return h->cifs_user_name ?: h->user_name;
1858 }
1859
1860 unsigned long user_record_mount_flags(UserRecord *h) {
1861 assert(h);
1862
1863 return (h->nosuid ? MS_NOSUID : 0) |
1864 (h->noexec ? MS_NOEXEC : 0) |
1865 (h->nodev ? MS_NODEV : 0);
1866 }
1867
1868 static const char *user_record_shell_real(UserRecord *h) {
1869 assert(h);
1870
1871 if (h->shell)
1872 return h->shell;
1873
1874 if (streq_ptr(h->user_name, "root"))
1875 return "/bin/sh";
1876
1877 if (user_record_disposition(h) == USER_REGULAR)
1878 return DEFAULT_USER_SHELL;
1879
1880 return NOLOGIN;
1881 }
1882
1883 const char *user_record_shell(UserRecord *h) {
1884 const char *shell;
1885
1886 assert(h);
1887
1888 shell = user_record_shell_real(h);
1889
1890 /* Return fallback shall if we are told so — except if the primary shell is already a nologin shell,
1891 * then let's not risk anything. */
1892 if (h->use_fallback && h->fallback_shell)
1893 return is_nologin_shell(shell) ? NOLOGIN : h->fallback_shell;
1894
1895 return shell;
1896 }
1897
1898 const char *user_record_real_name(UserRecord *h) {
1899 assert(h);
1900
1901 return h->real_name ?: h->user_name;
1902 }
1903
1904 bool user_record_luks_discard(UserRecord *h) {
1905 const char *ip;
1906
1907 assert(h);
1908
1909 if (h->luks_discard >= 0)
1910 return h->luks_discard;
1911
1912 ip = user_record_image_path(h);
1913 if (!ip)
1914 return false;
1915
1916 /* Use discard by default if we are referring to a real block device, but not when operating on a
1917 * loopback device. We want to optimize for SSD and flash storage after all, but we should be careful
1918 * when storing stuff on top of regular file systems in loopback files as doing discard then would
1919 * mean thin provisioning and we should not do that willy-nilly since it means we'll risk EIO later
1920 * on should the disk space to back our file systems not be available. */
1921
1922 return path_startswith(ip, "/dev/");
1923 }
1924
1925 bool user_record_luks_offline_discard(UserRecord *h) {
1926 const char *ip;
1927
1928 assert(h);
1929
1930 if (h->luks_offline_discard >= 0)
1931 return h->luks_offline_discard;
1932
1933 /* Discard while we are logged out should generally be a good idea, except when operating directly on
1934 * physical media, where we should just bind it to the online discard mode. */
1935
1936 ip = user_record_image_path(h);
1937 if (!ip)
1938 return false;
1939
1940 if (path_startswith(ip, "/dev/"))
1941 return user_record_luks_discard(h);
1942
1943 return true;
1944 }
1945
1946 const char *user_record_luks_cipher(UserRecord *h) {
1947 assert(h);
1948
1949 return h->luks_cipher ?: "aes";
1950 }
1951
1952 const char *user_record_luks_cipher_mode(UserRecord *h) {
1953 assert(h);
1954
1955 return h->luks_cipher_mode ?: "xts-plain64";
1956 }
1957
1958 uint64_t user_record_luks_volume_key_size(UserRecord *h) {
1959 assert(h);
1960
1961 /* We return a value here that can be cast without loss into size_t which is what libcrypsetup expects */
1962
1963 if (h->luks_volume_key_size == UINT64_MAX)
1964 return 256 / 8;
1965
1966 return MIN(h->luks_volume_key_size, SIZE_MAX);
1967 }
1968
1969 const char* user_record_luks_pbkdf_type(UserRecord *h) {
1970 assert(h);
1971
1972 return h->luks_pbkdf_type ?: "argon2id";
1973 }
1974
1975 uint64_t user_record_luks_pbkdf_force_iterations(UserRecord *h) {
1976 assert(h);
1977
1978 /* propagate default "benchmark" mode as itself */
1979 if (h->luks_pbkdf_force_iterations == UINT64_MAX)
1980 return UINT64_MAX;
1981
1982 /* clamp everything else to actually accepted number of iterations of libcryptsetup */
1983 return CLAMP(h->luks_pbkdf_force_iterations, 1U, UINT32_MAX);
1984 }
1985
1986 uint64_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h) {
1987 assert(h);
1988
1989 /* Returns a value with ms granularity, since that's what libcryptsetup expects */
1990
1991 if (h->luks_pbkdf_time_cost_usec == UINT64_MAX)
1992 return 500 * USEC_PER_MSEC; /* We default to 500ms, in contrast to libcryptsetup's 2s, which is just awfully slow on every login */
1993
1994 return MIN(DIV_ROUND_UP(h->luks_pbkdf_time_cost_usec, USEC_PER_MSEC), UINT32_MAX) * USEC_PER_MSEC;
1995 }
1996
1997 uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) {
1998 assert(h);
1999
2000 /* Returns a value with kb granularity, since that's what libcryptsetup expects */
2001 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
2002 return streq(user_record_luks_pbkdf_type(h), "pbkdf2") ? 0 : /* doesn't apply for simple pbkdf2 */
2003 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */
2004
2005 return MIN(DIV_ROUND_UP(h->luks_pbkdf_memory_cost, 1024), UINT32_MAX) * 1024;
2006 }
2007
2008 uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) {
2009 assert(h);
2010
2011 if (h->luks_pbkdf_parallel_threads == UINT64_MAX)
2012 return streq(user_record_luks_pbkdf_type(h), "pbkdf2") ? 0 : /* doesn't apply for simple pbkdf2 */
2013 1; /* We default to 1, since this should work on smaller systems too */
2014
2015 return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX);
2016 }
2017
2018 uint64_t user_record_luks_sector_size(UserRecord *h) {
2019 assert(h);
2020
2021 if (h->luks_sector_size == UINT64_MAX)
2022 return 512;
2023
2024 /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
2025 return CLAMP(UINT64_C(1) << (63 - __builtin_clzl(h->luks_sector_size)), 512U, 4096U);
2026 }
2027
2028 const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h) {
2029 assert(h);
2030
2031 return h->luks_pbkdf_hash_algorithm ?: "sha512";
2032 }
2033
2034 gid_t user_record_gid(UserRecord *h) {
2035 assert(h);
2036
2037 if (gid_is_valid(h->gid))
2038 return h->gid;
2039
2040 return (gid_t) h->uid;
2041 }
2042
2043 UserDisposition user_record_disposition(UserRecord *h) {
2044 assert(h);
2045
2046 if (h->disposition >= 0)
2047 return h->disposition;
2048
2049 /* If not declared, derive from UID */
2050
2051 if (!uid_is_valid(h->uid))
2052 return _USER_DISPOSITION_INVALID;
2053
2054 if (h->uid == 0 || h->uid == UID_NOBODY)
2055 return USER_INTRINSIC;
2056
2057 if (uid_is_system(h->uid))
2058 return USER_SYSTEM;
2059
2060 if (uid_is_dynamic(h->uid))
2061 return USER_DYNAMIC;
2062
2063 if (uid_is_container(h->uid))
2064 return USER_CONTAINER;
2065
2066 if (h->uid > INT32_MAX)
2067 return USER_RESERVED;
2068
2069 return USER_REGULAR;
2070 }
2071
2072 int user_record_removable(UserRecord *h) {
2073 UserStorage storage;
2074 assert(h);
2075
2076 if (h->removable >= 0)
2077 return h->removable;
2078
2079 /* Refuse to decide for classic records */
2080 storage = user_record_storage(h);
2081 if (h->storage < 0 || h->storage == USER_CLASSIC)
2082 return -1;
2083
2084 /* For now consider only LUKS home directories with a reference by path as removable */
2085 return storage == USER_LUKS && path_startswith(user_record_image_path(h), "/dev/");
2086 }
2087
2088 uint64_t user_record_ratelimit_interval_usec(UserRecord *h) {
2089 assert(h);
2090
2091 if (h->ratelimit_interval_usec == UINT64_MAX)
2092 return DEFAULT_RATELIMIT_INTERVAL_USEC;
2093
2094 return h->ratelimit_interval_usec;
2095 }
2096
2097 uint64_t user_record_ratelimit_burst(UserRecord *h) {
2098 assert(h);
2099
2100 if (h->ratelimit_burst == UINT64_MAX)
2101 return DEFAULT_RATELIMIT_BURST;
2102
2103 return h->ratelimit_burst;
2104 }
2105
2106 bool user_record_can_authenticate(UserRecord *h) {
2107 assert(h);
2108
2109 /* Returns true if there's some form of property configured that the user can authenticate against */
2110
2111 if (h->n_pkcs11_encrypted_key > 0)
2112 return true;
2113
2114 if (h->n_fido2_hmac_salt > 0)
2115 return true;
2116
2117 return !strv_isempty(h->hashed_password);
2118 }
2119
2120 bool user_record_drop_caches(UserRecord *h) {
2121 assert(h);
2122
2123 if (h->drop_caches >= 0)
2124 return h->drop_caches;
2125
2126 /* By default drop caches on fscrypt, not otherwise. */
2127 return user_record_storage(h) == USER_FSCRYPT;
2128 }
2129
2130 AutoResizeMode user_record_auto_resize_mode(UserRecord *h) {
2131 assert(h);
2132
2133 if (h->auto_resize_mode >= 0)
2134 return h->auto_resize_mode;
2135
2136 return user_record_storage(h) == USER_LUKS ? AUTO_RESIZE_SHRINK_AND_GROW : AUTO_RESIZE_OFF;
2137 }
2138
2139 uint64_t user_record_rebalance_weight(UserRecord *h) {
2140 assert(h);
2141
2142 if (h->rebalance_weight == REBALANCE_WEIGHT_UNSET)
2143 return REBALANCE_WEIGHT_DEFAULT;
2144
2145 return h->rebalance_weight;
2146 }
2147
2148 static uint64_t parse_caps_strv(char **l) {
2149 uint64_t c = 0;
2150 int r;
2151
2152 STRV_FOREACH(i, l) {
2153 r = capability_from_name(*i);
2154 if (r < 0)
2155 log_debug_errno(r, "Don't know capability '%s', ignoring: %m", *i);
2156 else
2157 c |= UINT64_C(1) << r;
2158 }
2159
2160 return c;
2161 }
2162
2163 uint64_t user_record_capability_bounding_set(UserRecord *h) {
2164 assert(h);
2165
2166 /* Returns UINT64_MAX if no bounding set is configured (!) */
2167
2168 if (!h->capability_bounding_set)
2169 return UINT64_MAX;
2170
2171 return parse_caps_strv(h->capability_bounding_set);
2172 }
2173
2174 uint64_t user_record_capability_ambient_set(UserRecord *h) {
2175 assert(h);
2176
2177 /* Returns UINT64_MAX if no ambient set is configured (!) */
2178
2179 if (!h->capability_ambient_set)
2180 return UINT64_MAX;
2181
2182 return parse_caps_strv(h->capability_ambient_set) & user_record_capability_bounding_set(h);
2183 }
2184
2185 int user_record_languages(UserRecord *h, char ***ret) {
2186 _cleanup_strv_free_ char **l = NULL;
2187 int r;
2188
2189 assert(h);
2190 assert(ret);
2191
2192 if (h->preferred_language) {
2193 l = strv_new(h->preferred_language);
2194 if (!l)
2195 return -ENOMEM;
2196 }
2197
2198 r = strv_extend_strv(&l, h->additional_languages, /* filter_duplicates= */ true);
2199 if (r < 0)
2200 return r;
2201
2202 *ret = TAKE_PTR(l);
2203 return 0;
2204 }
2205
2206 uint64_t user_record_ratelimit_next_try(UserRecord *h) {
2207 assert(h);
2208
2209 /* Calculates when the it's possible to login next. Returns:
2210 *
2211 * UINT64_MAX → Nothing known
2212 * 0 → Right away
2213 * Any other → Next time in CLOCK_REALTIME in usec (which could be in the past)
2214 */
2215
2216 if (h->ratelimit_begin_usec == UINT64_MAX ||
2217 h->ratelimit_count == UINT64_MAX)
2218 return UINT64_MAX;
2219
2220 if (h->ratelimit_begin_usec > now(CLOCK_REALTIME)) /* If the ratelimit time is in the future, then
2221 * the local clock is probably incorrect. Let's
2222 * not refuse login then. */
2223 return UINT64_MAX;
2224
2225 if (h->ratelimit_count < user_record_ratelimit_burst(h))
2226 return 0;
2227
2228 return usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h));
2229 }
2230
2231 bool user_record_equal(UserRecord *a, UserRecord *b) {
2232 assert(a);
2233 assert(b);
2234
2235 /* We assume that when a record is modified its JSON data is updated at the same time, hence it's
2236 * sufficient to compare the JSON data. */
2237
2238 return json_variant_equal(a->json, b->json);
2239 }
2240
2241 bool user_record_compatible(UserRecord *a, UserRecord *b) {
2242 assert(a);
2243 assert(b);
2244
2245 /* If either lacks the regular section, we can't really decide, let's hence say they are
2246 * incompatible. */
2247 if (!(a->mask & b->mask & USER_RECORD_REGULAR))
2248 return false;
2249
2250 return streq_ptr(a->user_name, b->user_name) &&
2251 streq_ptr(a->realm, b->realm);
2252 }
2253
2254 int user_record_compare_last_change(UserRecord *a, UserRecord *b) {
2255 assert(a);
2256 assert(b);
2257
2258 if (a->last_change_usec == b->last_change_usec)
2259 return 0;
2260
2261 /* Always consider a record with a timestamp newer than one without */
2262 if (a->last_change_usec == UINT64_MAX)
2263 return -1;
2264 if (b->last_change_usec == UINT64_MAX)
2265 return 1;
2266
2267 return CMP(a->last_change_usec, b->last_change_usec);
2268 }
2269
2270 int user_record_clone(UserRecord *h, UserRecordLoadFlags flags, UserRecord **ret) {
2271 _cleanup_(user_record_unrefp) UserRecord *c = NULL;
2272 int r;
2273
2274 assert(h);
2275 assert(ret);
2276
2277 c = user_record_new();
2278 if (!c)
2279 return -ENOMEM;
2280
2281 r = user_record_load(c, h->json, flags);
2282 if (r < 0)
2283 return r;
2284
2285 *ret = TAKE_PTR(c);
2286 return 0;
2287 }
2288
2289 int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask) {
2290 _cleanup_(user_record_unrefp) UserRecord *x = NULL, *y = NULL;
2291 int r;
2292
2293 assert(a);
2294 assert(b);
2295
2296 /* Compares the two records, but ignores anything not listed in the specified mask */
2297
2298 if ((a->mask & ~mask) != 0) {
2299 r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &x);
2300 if (r < 0)
2301 return r;
2302
2303 a = x;
2304 }
2305
2306 if ((b->mask & ~mask) != 0) {
2307 r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &y);
2308 if (r < 0)
2309 return r;
2310
2311 b = y;
2312 }
2313
2314 return user_record_equal(a, b);
2315 }
2316
2317 int user_record_test_blocked(UserRecord *h) {
2318 usec_t n;
2319
2320 /* Checks whether access to the specified user shall be allowed at the moment. Returns:
2321 *
2322 * -ESTALE: Record is from the future
2323 * -ENOLCK: Record is blocked
2324 * -EL2HLT: Record is not valid yet
2325 * -EL3HLT: Record is not valid anymore
2326 *
2327 */
2328
2329 assert(h);
2330
2331 if (h->locked > 0)
2332 return -ENOLCK;
2333
2334 n = now(CLOCK_REALTIME);
2335
2336 if (h->not_before_usec != UINT64_MAX && n < h->not_before_usec)
2337 return -EL2HLT;
2338 if (h->not_after_usec != UINT64_MAX && n > h->not_after_usec)
2339 return -EL3HLT;
2340
2341 if (h->last_change_usec != UINT64_MAX &&
2342 h->last_change_usec > n) /* Complain during log-ins when the record is from the future */
2343 return -ESTALE;
2344
2345 return 0;
2346 }
2347
2348 int user_record_test_password_change_required(UserRecord *h) {
2349 bool change_permitted;
2350 usec_t n;
2351
2352 assert(h);
2353
2354 /* Checks whether the user must change the password when logging in
2355
2356 -EKEYREVOKED: Change password now because admin said so
2357 -EOWNERDEAD: Change password now because it expired
2358 -EKEYREJECTED: Password is expired, no changing is allowed
2359 -EKEYEXPIRED: Password is about to expire, warn user
2360 -ENETDOWN: Record has expiration info but no password change timestamp
2361 -EROFS: No password change required nor permitted
2362 -ESTALE: RTC likely incorrect, last password change is in the future
2363 0: No password change required, but permitted
2364 */
2365
2366 /* If a password change request has been set explicitly, it overrides everything */
2367 if (h->password_change_now > 0)
2368 return -EKEYREVOKED;
2369
2370 n = now(CLOCK_REALTIME);
2371
2372 /* Password change in the future? Then our RTC is likely incorrect */
2373 if (h->last_password_change_usec != UINT64_MAX &&
2374 h->last_password_change_usec > n &&
2375 (h->password_change_min_usec != UINT64_MAX ||
2376 h->password_change_max_usec != UINT64_MAX ||
2377 h->password_change_inactive_usec != UINT64_MAX))
2378 return -ESTALE;
2379
2380 /* Then, let's check if password changing is currently allowed at all */
2381 if (h->password_change_min_usec != UINT64_MAX) {
2382
2383 /* Expiry configured but no password change timestamp known? */
2384 if (h->last_password_change_usec == UINT64_MAX)
2385 return -ENETDOWN;
2386
2387 if (h->password_change_min_usec >= UINT64_MAX - h->last_password_change_usec)
2388 change_permitted = false;
2389 else
2390 change_permitted = n >= h->last_password_change_usec + h->password_change_min_usec;
2391
2392 } else
2393 change_permitted = true;
2394
2395 /* Let's check whether the password has expired. */
2396 if (!(h->password_change_max_usec == UINT64_MAX ||
2397 h->password_change_max_usec >= UINT64_MAX - h->last_password_change_usec)) {
2398
2399 uint64_t change_before;
2400
2401 /* Expiry configured but no password change timestamp known? */
2402 if (h->last_password_change_usec == UINT64_MAX)
2403 return -ENETDOWN;
2404
2405 /* Password is in inactive phase? */
2406 if (h->password_change_inactive_usec != UINT64_MAX &&
2407 h->password_change_inactive_usec < UINT64_MAX - h->password_change_max_usec) {
2408 usec_t added;
2409
2410 added = h->password_change_inactive_usec + h->password_change_max_usec;
2411 if (added < UINT64_MAX - h->last_password_change_usec &&
2412 n >= h->last_password_change_usec + added)
2413 return -EKEYREJECTED;
2414 }
2415
2416 /* Password needs to be changed now? */
2417 change_before = h->last_password_change_usec + h->password_change_max_usec;
2418 if (n >= change_before)
2419 return change_permitted ? -EOWNERDEAD : -EKEYREJECTED;
2420
2421 /* Warn user? */
2422 if (h->password_change_warn_usec != UINT64_MAX &&
2423 (change_before < h->password_change_warn_usec ||
2424 n >= change_before - h->password_change_warn_usec))
2425 return change_permitted ? -EKEYEXPIRED : -EROFS;
2426 }
2427
2428 /* No password changing necessary */
2429 return change_permitted ? 0 : -EROFS;
2430 }
2431
2432 int suitable_blob_filename(const char *name) {
2433 /* Enforces filename requirements as described in docs/USER_RECORD_BULK_DIRS.md */
2434 return filename_is_valid(name) &&
2435 in_charset(name, URI_UNRESERVED) &&
2436 name[0] != '.';
2437 }
2438
2439 static const char* const user_storage_table[_USER_STORAGE_MAX] = {
2440 [USER_CLASSIC] = "classic",
2441 [USER_LUKS] = "luks",
2442 [USER_DIRECTORY] = "directory",
2443 [USER_SUBVOLUME] = "subvolume",
2444 [USER_FSCRYPT] = "fscrypt",
2445 [USER_CIFS] = "cifs",
2446 };
2447
2448 DEFINE_STRING_TABLE_LOOKUP(user_storage, UserStorage);
2449
2450 static const char* const user_disposition_table[_USER_DISPOSITION_MAX] = {
2451 [USER_INTRINSIC] = "intrinsic",
2452 [USER_SYSTEM] = "system",
2453 [USER_DYNAMIC] = "dynamic",
2454 [USER_REGULAR] = "regular",
2455 [USER_CONTAINER] = "container",
2456 [USER_RESERVED] = "reserved",
2457 };
2458
2459 DEFINE_STRING_TABLE_LOOKUP(user_disposition, UserDisposition);
2460
2461 static const char* const auto_resize_mode_table[_AUTO_RESIZE_MODE_MAX] = {
2462 [AUTO_RESIZE_OFF] = "off",
2463 [AUTO_RESIZE_GROW] = "grow",
2464 [AUTO_RESIZE_SHRINK_AND_GROW] = "shrink-and-grow",
2465 };
2466
2467 DEFINE_STRING_TABLE_LOOKUP(auto_resize_mode, AutoResizeMode);