]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/user-record.c
user-record: rename JSON field "pkcs11Pin" to "tokenPin"
[thirdparty/systemd.git] / src / shared / user-record.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <sys/mount.h>
4
5 #include "cgroup-util.h"
6 #include "dns-domain.h"
7 #include "env-util.h"
8 #include "fs-util.h"
9 #include "hexdecoct.h"
10 #include "hostname-util.h"
11 #include "memory-util.h"
12 #include "path-util.h"
13 #include "pkcs11-util.h"
14 #include "rlimit-util.h"
15 #include "stat-util.h"
16 #include "string-table.h"
17 #include "strv.h"
18 #include "user-record.h"
19 #include "user-util.h"
20
21 #define DEFAULT_RATELIMIT_BURST 30
22 #define DEFAULT_RATELIMIT_INTERVAL_USEC (1*USEC_PER_MINUTE)
23
24 UserRecord* user_record_new(void) {
25 UserRecord *h;
26
27 h = new(UserRecord, 1);
28 if (!h)
29 return NULL;
30
31 *h = (UserRecord) {
32 .n_ref = 1,
33 .disposition = _USER_DISPOSITION_INVALID,
34 .last_change_usec = UINT64_MAX,
35 .last_password_change_usec = UINT64_MAX,
36 .umask = MODE_INVALID,
37 .nice_level = INT_MAX,
38 .not_before_usec = UINT64_MAX,
39 .not_after_usec = UINT64_MAX,
40 .locked = -1,
41 .storage = _USER_STORAGE_INVALID,
42 .access_mode = MODE_INVALID,
43 .disk_size = UINT64_MAX,
44 .disk_size_relative = UINT64_MAX,
45 .tasks_max = UINT64_MAX,
46 .memory_high = UINT64_MAX,
47 .memory_max = UINT64_MAX,
48 .cpu_weight = UINT64_MAX,
49 .io_weight = UINT64_MAX,
50 .uid = UID_INVALID,
51 .gid = GID_INVALID,
52 .nodev = true,
53 .nosuid = true,
54 .luks_discard = -1,
55 .luks_offline_discard = -1,
56 .luks_volume_key_size = UINT64_MAX,
57 .luks_pbkdf_time_cost_usec = UINT64_MAX,
58 .luks_pbkdf_memory_cost = UINT64_MAX,
59 .luks_pbkdf_parallel_threads = UINT64_MAX,
60 .disk_usage = UINT64_MAX,
61 .disk_free = UINT64_MAX,
62 .disk_ceiling = UINT64_MAX,
63 .disk_floor = UINT64_MAX,
64 .signed_locally = -1,
65 .good_authentication_counter = UINT64_MAX,
66 .bad_authentication_counter = UINT64_MAX,
67 .last_good_authentication_usec = UINT64_MAX,
68 .last_bad_authentication_usec = UINT64_MAX,
69 .ratelimit_begin_usec = UINT64_MAX,
70 .ratelimit_count = UINT64_MAX,
71 .ratelimit_interval_usec = UINT64_MAX,
72 .ratelimit_burst = UINT64_MAX,
73 .removable = -1,
74 .enforce_password_policy = -1,
75 .auto_login = -1,
76 .stop_delay_usec = UINT64_MAX,
77 .kill_processes = -1,
78 .password_change_min_usec = UINT64_MAX,
79 .password_change_max_usec = UINT64_MAX,
80 .password_change_warn_usec = UINT64_MAX,
81 .password_change_inactive_usec = UINT64_MAX,
82 .password_change_now = -1,
83 .pkcs11_protected_authentication_path_permitted = -1,
84 };
85
86 return h;
87 }
88
89 static void pkcs11_encrypted_key_done(Pkcs11EncryptedKey *k) {
90 if (!k)
91 return;
92
93 free(k->uri);
94 erase_and_free(k->data);
95 erase_and_free(k->hashed_password);
96 }
97
98 static UserRecord* user_record_free(UserRecord *h) {
99 if (!h)
100 return NULL;
101
102 free(h->user_name);
103 free(h->realm);
104 free(h->user_name_and_realm_auto);
105 free(h->real_name);
106 free(h->email_address);
107 erase_and_free(h->password_hint);
108 free(h->location);
109 free(h->icon_name);
110
111 free(h->shell);
112
113 strv_free(h->environment);
114 free(h->time_zone);
115 free(h->preferred_language);
116 rlimit_free_all(h->rlimits);
117
118 free(h->skeleton_directory);
119
120 strv_free_erase(h->hashed_password);
121 strv_free_erase(h->ssh_authorized_keys);
122 strv_free_erase(h->password);
123 strv_free_erase(h->token_pin);
124
125 free(h->cifs_service);
126 free(h->cifs_user_name);
127 free(h->cifs_domain);
128
129 free(h->image_path);
130 free(h->image_path_auto);
131 free(h->home_directory);
132 free(h->home_directory_auto);
133
134 strv_free(h->member_of);
135
136 free(h->file_system_type);
137 free(h->luks_cipher);
138 free(h->luks_cipher_mode);
139 free(h->luks_pbkdf_hash_algorithm);
140 free(h->luks_pbkdf_type);
141
142 free(h->state);
143 free(h->service);
144
145 strv_free(h->pkcs11_token_uri);
146 for (size_t i = 0; i < h->n_pkcs11_encrypted_key; i++)
147 pkcs11_encrypted_key_done(h->pkcs11_encrypted_key + i);
148 free(h->pkcs11_encrypted_key);
149
150 json_variant_unref(h->json);
151
152 return mfree(h);
153 }
154
155 DEFINE_TRIVIAL_REF_UNREF_FUNC(UserRecord, user_record, user_record_free);
156
157 int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
158 char **s = userdata;
159 const char *n;
160 int r;
161
162 if (json_variant_is_null(variant)) {
163 *s = mfree(*s);
164 return 0;
165 }
166
167 if (!json_variant_is_string(variant))
168 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
169
170 n = json_variant_string(variant);
171 r = dns_name_is_valid(n);
172 if (r < 0)
173 return json_log(variant, flags, r, "Failed to check if JSON field '%s' is a valid DNS domain.", strna(name));
174 if (r == 0)
175 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid DNS domain.", strna(name));
176
177 r = free_and_strdup(s, n);
178 if (r < 0)
179 return json_log(variant, flags, r, "Failed to allocate string: %m");
180
181 return 0;
182 }
183
184 static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
185 char **s = userdata;
186 const char *n;
187 int r;
188
189 if (json_variant_is_null(variant)) {
190 *s = mfree(*s);
191 return 0;
192 }
193
194 if (!json_variant_is_string(variant))
195 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
196
197 n = json_variant_string(variant);
198 if (!valid_gecos(n))
199 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible real name.", strna(name));
200
201 r = free_and_strdup(s, n);
202 if (r < 0)
203 return json_log(variant, flags, r, "Failed to allocate string: %m");
204
205 return 0;
206 }
207
208 static int json_dispatch_nice(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
209 int *nl = userdata;
210 intmax_t m;
211
212 if (json_variant_is_null(variant)) {
213 *nl = INT_MAX;
214 return 0;
215 }
216
217 if (!json_variant_is_integer(variant))
218 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
219
220 m = json_variant_integer(variant);
221 if (m < PRIO_MIN || m >= PRIO_MAX)
222 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' is not a valid nice level.", strna(name));
223
224 *nl = m;
225 return 0;
226 }
227
228 static int json_dispatch_rlimit_value(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
229 rlim_t *ret = userdata;
230
231 if (json_variant_is_null(variant))
232 *ret = RLIM_INFINITY;
233 else if (json_variant_is_unsigned(variant)) {
234 uintmax_t w;
235
236 w = json_variant_unsigned(variant);
237 if (w == RLIM_INFINITY || (uintmax_t) w != json_variant_unsigned(variant))
238 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "Resource limit value '%s' is out of range.", name);
239
240 *ret = (rlim_t) w;
241 } else
242 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit value '%s' is not an unsigned integer.", name);
243
244 return 0;
245 }
246
247 static int json_dispatch_rlimits(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
248 struct rlimit** limits = userdata;
249 JsonVariant *value;
250 const char *key;
251 int r;
252
253 assert_se(limits);
254
255 if (json_variant_is_null(variant)) {
256 rlimit_free_all(limits);
257 return 0;
258 }
259
260 if (!json_variant_is_object(variant))
261 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
262
263 JSON_VARIANT_OBJECT_FOREACH(key, value, variant) {
264 JsonVariant *jcur, *jmax;
265 struct rlimit rl;
266 const char *p;
267 int l;
268
269 p = startswith(key, "RLIMIT_");
270 if (!p)
271 l = -1;
272 else
273 l = rlimit_from_string(p);
274 if (l < 0)
275 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' not known.", key);
276
277 if (!json_variant_is_object(value))
278 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' has invalid value.", key);
279
280 if (json_variant_elements(value) != 4)
281 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' value is does not have two fields as expected.", key);
282
283 jcur = json_variant_by_key(value, "cur");
284 if (!jcur)
285 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' lacks 'cur' field.", key);
286 r = json_dispatch_rlimit_value("cur", jcur, flags, &rl.rlim_cur);
287 if (r < 0)
288 return r;
289
290 jmax = json_variant_by_key(value, "max");
291 if (!jmax)
292 return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' lacks 'max' field.", key);
293 r = json_dispatch_rlimit_value("max", jmax, flags, &rl.rlim_max);
294 if (r < 0)
295 return r;
296
297 if (limits[l])
298 *(limits[l]) = rl;
299 else {
300 limits[l] = newdup(struct rlimit, &rl, 1);
301 if (!limits[l])
302 return log_oom();
303 }
304 }
305
306 return 0;
307 }
308
309 static int json_dispatch_filename_or_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
310 char **s = userdata;
311 const char *n;
312 int r;
313
314 assert(s);
315
316 if (json_variant_is_null(variant)) {
317 *s = mfree(*s);
318 return 0;
319 }
320
321 if (!json_variant_is_string(variant))
322 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
323
324 n = json_variant_string(variant);
325 if (!filename_is_valid(n) && !path_is_normalized(n))
326 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid file name or normalized path.", strna(name));
327
328 r = free_and_strdup(s, n);
329 if (r < 0)
330 return json_log(variant, flags, r, "Failed to allocate string: %m");
331
332 return 0;
333 }
334
335 static int json_dispatch_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
336 char **s = userdata;
337 const char *n;
338 int r;
339
340 if (json_variant_is_null(variant)) {
341 *s = mfree(*s);
342 return 0;
343 }
344
345 if (!json_variant_is_string(variant))
346 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
347
348 n = json_variant_string(variant);
349 if (!path_is_normalized(n))
350 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a normalized file system path.", strna(name));
351 if (!path_is_absolute(n))
352 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an absolute file system path.", strna(name));
353
354 r = free_and_strdup(s, n);
355 if (r < 0)
356 return json_log(variant, flags, r, "Failed to allocate string: %m");
357
358 return 0;
359 }
360
361 static int json_dispatch_home_directory(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
362 char **s = userdata;
363 const char *n;
364 int r;
365
366 if (json_variant_is_null(variant)) {
367 *s = mfree(*s);
368 return 0;
369 }
370
371 if (!json_variant_is_string(variant))
372 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
373
374 n = json_variant_string(variant);
375 if (!valid_home(n))
376 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid home directory path.", strna(name));
377
378 r = free_and_strdup(s, n);
379 if (r < 0)
380 return json_log(variant, flags, r, "Failed to allocate string: %m");
381
382 return 0;
383 }
384
385 static int json_dispatch_image_path(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
386 char **s = userdata;
387 const char *n;
388 int r;
389
390 if (json_variant_is_null(variant)) {
391 *s = mfree(*s);
392 return 0;
393 }
394
395 if (!json_variant_is_string(variant))
396 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
397
398 n = json_variant_string(variant);
399 if (empty_or_root(n) || !path_is_valid(n) || !path_is_absolute(n))
400 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid image path.", strna(name));
401
402 r = free_and_strdup(s, n);
403 if (r < 0)
404 return json_log(variant, flags, r, "Failed to allocate string: %m");
405
406 return 0;
407 }
408
409 static int json_dispatch_umask(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
410 mode_t *m = userdata;
411 uintmax_t k;
412
413 if (json_variant_is_null(variant)) {
414 *m = (mode_t) -1;
415 return 0;
416 }
417
418 if (!json_variant_is_unsigned(variant))
419 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
420
421 k = json_variant_unsigned(variant);
422 if (k > 0777)
423 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' outside of valid range 0…0777.", strna(name));
424
425 *m = (mode_t) k;
426 return 0;
427 }
428
429 static int json_dispatch_access_mode(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
430 mode_t *m = userdata;
431 uintmax_t k;
432
433 if (json_variant_is_null(variant)) {
434 *m = (mode_t) -1;
435 return 0;
436 }
437
438 if (!json_variant_is_unsigned(variant))
439 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
440
441 k = json_variant_unsigned(variant);
442 if (k > 07777)
443 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' outside of valid range 0…07777.", strna(name));
444
445 *m = (mode_t) k;
446 return 0;
447 }
448
449 static int json_dispatch_environment(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
450 _cleanup_strv_free_ char **n = NULL;
451 char ***l = userdata;
452 size_t i;
453 int r;
454
455 if (json_variant_is_null(variant)) {
456 *l = strv_free(*l);
457 return 0;
458 }
459
460 if (!json_variant_is_array(variant))
461 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
462
463 for (i = 0; i < json_variant_elements(variant); i++) {
464 _cleanup_free_ char *c = NULL;
465 JsonVariant *e;
466 const char *a;
467
468 e = json_variant_by_index(variant, i);
469 if (!json_variant_is_string(e))
470 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
471
472 assert_se(a = json_variant_string(e));
473
474 if (!env_assignment_is_valid(a))
475 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of environment variables.", strna(name));
476
477 c = strdup(a);
478 if (!c)
479 return json_log_oom(variant, flags);
480
481 r = strv_env_replace(&n, c);
482 if (r < 0)
483 return json_log_oom(variant, flags);
484
485 c = NULL;
486 }
487
488 strv_free_and_replace(*l, n);
489 return 0;
490 }
491
492 int json_dispatch_user_disposition(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
493 UserDisposition *disposition = userdata, k;
494
495 if (json_variant_is_null(variant)) {
496 *disposition = _USER_DISPOSITION_INVALID;
497 return 0;
498 }
499
500 if (!json_variant_is_string(variant))
501 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
502
503 k = user_disposition_from_string(json_variant_string(variant));
504 if (k < 0)
505 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Disposition type '%s' not known.", json_variant_string(variant));
506
507 *disposition = k;
508 return 0;
509 }
510
511 static int json_dispatch_storage(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
512 UserStorage *storage = userdata, k;
513
514 if (json_variant_is_null(variant)) {
515 *storage = _USER_STORAGE_INVALID;
516 return 0;
517 }
518
519 if (!json_variant_is_string(variant))
520 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
521
522 k = user_storage_from_string(json_variant_string(variant));
523 if (k < 0)
524 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Storage type '%s' not known.", json_variant_string(variant));
525
526 *storage = k;
527 return 0;
528 }
529
530 static int json_dispatch_disk_size(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
531 uint64_t *size = userdata;
532 uintmax_t k;
533
534 if (json_variant_is_null(variant)) {
535 *size = UINT64_MAX;
536 return 0;
537 }
538
539 if (!json_variant_is_unsigned(variant))
540 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
541
542 k = json_variant_unsigned(variant);
543 if (k < USER_DISK_SIZE_MIN || k > USER_DISK_SIZE_MAX)
544 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' is not in valid range %" PRIu64 "…%" PRIu64 ".", strna(name), USER_DISK_SIZE_MIN, USER_DISK_SIZE_MAX);
545
546 *size = k;
547 return 0;
548 }
549
550 static int json_dispatch_tasks_or_memory_max(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
551 uint64_t *limit = userdata;
552 uintmax_t k;
553
554 if (json_variant_is_null(variant)) {
555 *limit = UINT64_MAX;
556 return 0;
557 }
558
559 if (!json_variant_is_unsigned(variant))
560 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a integer.", strna(name));
561
562 k = json_variant_unsigned(variant);
563 if (k <= 0 || k >= UINT64_MAX)
564 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' is not in valid range %" PRIu64 "…%" PRIu64 ".", strna(name), (uint64_t) 1, UINT64_MAX-1);
565
566 *limit = k;
567 return 0;
568 }
569
570 static int json_dispatch_weight(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
571 uint64_t *weight = userdata;
572 uintmax_t k;
573
574 if (json_variant_is_null(variant)) {
575 *weight = UINT64_MAX;
576 return 0;
577 }
578
579 if (!json_variant_is_unsigned(variant))
580 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a integer.", strna(name));
581
582 k = json_variant_unsigned(variant);
583 if (k <= CGROUP_WEIGHT_MIN || k >= CGROUP_WEIGHT_MAX)
584 return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' is not in valid range %" PRIu64 "…%" PRIu64 ".", strna(name), (uint64_t) CGROUP_WEIGHT_MIN, (uint64_t) CGROUP_WEIGHT_MAX);
585
586 *weight = k;
587 return 0;
588 }
589
590 int json_dispatch_user_group_list(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
591 _cleanup_strv_free_ char **l = NULL;
592 char ***list = userdata;
593 JsonVariant *e;
594 int r;
595
596 if (!json_variant_is_array(variant))
597 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
598
599 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
600
601 if (!json_variant_is_string(e))
602 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
603
604 if (!valid_user_group_name(json_variant_string(e), FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
605 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a valid user/group name: %s", json_variant_string(e));
606
607 r = strv_extend(&l, json_variant_string(e));
608 if (r < 0)
609 return json_log(e, flags, r, "Failed to append array element: %m");
610 }
611
612 r = strv_extend_strv(list, l, true);
613 if (r < 0)
614 return json_log(variant, flags, r, "Failed to merge user/group arrays: %m");
615
616 return 0;
617 }
618
619 static int dispatch_secret(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
620
621 static const JsonDispatch secret_dispatch_table[] = {
622 { "password", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, password), 0 },
623 { "tokenPin", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
624 { "pkcs11Pin", /* legacy alias */ _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
625 { "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 },
626 {},
627 };
628
629 return json_dispatch(variant, secret_dispatch_table, NULL, flags, userdata);
630 }
631
632 static int dispatch_pkcs11_uri(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
633 char **s = userdata;
634 const char *n;
635 int r;
636
637 if (json_variant_is_null(variant)) {
638 *s = mfree(*s);
639 return 0;
640 }
641
642 if (!json_variant_is_string(variant))
643 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
644
645 n = json_variant_string(variant);
646 if (!pkcs11_uri_valid(n))
647 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
648
649 r = free_and_strdup(s, n);
650 if (r < 0)
651 return json_log(variant, flags, r, "Failed to allocate string: %m");
652
653 return 0;
654 }
655
656 static int dispatch_pkcs11_uri_array(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
657 _cleanup_strv_free_ char **z = NULL;
658 char ***l = userdata;
659 JsonVariant *e;
660 int r;
661
662 if (json_variant_is_null(variant)) {
663 *l = strv_free(*l);
664 return 0;
665 }
666
667 if (json_variant_is_string(variant)) {
668 const char *n;
669
670 n = json_variant_string(variant);
671 if (!pkcs11_uri_valid(n))
672 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
673
674 z = strv_new(n);
675 if (!z)
676 return log_oom();
677
678 } else {
679
680 if (!json_variant_is_array(variant))
681 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string or array of strings.", strna(name));
682
683 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
684 const char *n;
685
686 if (!json_variant_is_string(e))
687 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
688
689 n = json_variant_string(e);
690 if (!pkcs11_uri_valid(n))
691 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);
692
693 r = strv_extend(&z, n);
694 if (r < 0)
695 return log_oom();
696 }
697 }
698
699 strv_free_and_replace(*l, z);
700 return 0;
701 }
702
703 static int dispatch_pkcs11_key_data(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
704 Pkcs11EncryptedKey *k = userdata;
705 size_t l;
706 void *b;
707 int r;
708
709 if (json_variant_is_null(variant)) {
710 k->data = erase_and_free(k->data);
711 k->size = 0;
712 return 0;
713 }
714
715 if (!json_variant_is_string(variant))
716 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
717
718 r = unbase64mem(json_variant_string(variant), (size_t) -1, &b, &l);
719 if (r < 0)
720 return json_log(variant, flags, r, "Failed to decode encrypted PKCS#11 key: %m");
721
722 erase_and_free(k->data);
723 k->data = b;
724 k->size = l;
725
726 return 0;
727 }
728
729 static int dispatch_pkcs11_key(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
730 UserRecord *h = userdata;
731 JsonVariant *e;
732 int r;
733
734 if (!json_variant_is_array(variant))
735 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
736
737 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
738 Pkcs11EncryptedKey *array, *k;
739
740 static const JsonDispatch pkcs11_key_dispatch_table[] = {
741 { "uri", JSON_VARIANT_STRING, dispatch_pkcs11_uri, offsetof(Pkcs11EncryptedKey, uri), JSON_MANDATORY },
742 { "data", JSON_VARIANT_STRING, dispatch_pkcs11_key_data, 0, JSON_MANDATORY },
743 { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Pkcs11EncryptedKey, hashed_password), JSON_MANDATORY },
744 {},
745 };
746
747 if (!json_variant_is_object(e))
748 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not an object.");
749
750 array = reallocarray(h->pkcs11_encrypted_key, h->n_pkcs11_encrypted_key + 1, sizeof(Pkcs11EncryptedKey));
751 if (!array)
752 return log_oom();
753
754 h->pkcs11_encrypted_key = array;
755 k = h->pkcs11_encrypted_key + h->n_pkcs11_encrypted_key;
756 *k = (Pkcs11EncryptedKey) {};
757
758 r = json_dispatch(e, pkcs11_key_dispatch_table, NULL, flags, k);
759 if (r < 0) {
760 pkcs11_encrypted_key_done(k);
761 return r;
762 }
763
764 h->n_pkcs11_encrypted_key++;
765 }
766
767 return 0;
768 }
769
770 static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
771
772 static const JsonDispatch privileged_dispatch_table[] = {
773 { "passwordHint", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, password_hint), 0 },
774 { "hashedPassword", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, hashed_password), JSON_SAFE },
775 { "sshAuthorizedKeys", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, ssh_authorized_keys), 0 },
776 { "pkcs11EncryptedKey", JSON_VARIANT_ARRAY, dispatch_pkcs11_key, 0, 0 },
777 {},
778 };
779
780 return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
781 }
782
783 static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
784
785 static const JsonDispatch binding_dispatch_table[] = {
786 { "imagePath", JSON_VARIANT_STRING, json_dispatch_image_path, offsetof(UserRecord, image_path), 0 },
787 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
788 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
789 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
790 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
791 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
792 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
793 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
794 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
795 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
796 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
797 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
798 {},
799 };
800
801 char smid[SD_ID128_STRING_MAX];
802 JsonVariant *m;
803 sd_id128_t mid;
804 int r;
805
806 if (!variant)
807 return 0;
808
809 if (!json_variant_is_object(variant))
810 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
811
812 r = sd_id128_get_machine(&mid);
813 if (r < 0)
814 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
815
816 m = json_variant_by_key(variant, sd_id128_to_string(mid, smid));
817 if (!m)
818 return 0;
819
820 return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
821 }
822
823 int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags) {
824 sd_id128_t mid;
825 int r;
826
827 r = sd_id128_get_machine(&mid);
828 if (r < 0)
829 return json_log(ids, flags, r, "Failed to acquire machine ID: %m");
830
831 if (json_variant_is_string(ids)) {
832 sd_id128_t k;
833
834 r = sd_id128_from_string(json_variant_string(ids), &k);
835 if (r < 0) {
836 json_log(ids, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(ids));
837 return 0;
838 }
839
840 return sd_id128_equal(mid, k);
841 }
842
843 if (json_variant_is_array(ids)) {
844 JsonVariant *e;
845
846 JSON_VARIANT_ARRAY_FOREACH(e, ids) {
847 sd_id128_t k;
848
849 if (!json_variant_is_string(e)) {
850 json_log(e, flags, 0, "Machine ID is not a string, ignoring: %m");
851 continue;
852 }
853
854 r = sd_id128_from_string(json_variant_string(e), &k);
855 if (r < 0) {
856 json_log(e, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(e));
857 continue;
858 }
859
860 if (sd_id128_equal(mid, k))
861 return true;
862 }
863
864 return false;
865 }
866
867 json_log(ids, flags, 0, "Machine ID is not a string or array of strings, ignoring: %m");
868 return false;
869 }
870
871 int per_machine_hostname_match(JsonVariant *hns, JsonDispatchFlags flags) {
872 _cleanup_free_ char *hn = NULL;
873 int r;
874
875 r = gethostname_strict(&hn);
876 if (r == -ENXIO) {
877 json_log(hns, flags, r, "No hostname set, not matching perMachine hostname record: %m");
878 return false;
879 }
880 if (r < 0)
881 return json_log(hns, flags, r, "Failed to acquire hostname: %m");
882
883 if (json_variant_is_string(hns))
884 return streq(json_variant_string(hns), hn);
885
886 if (json_variant_is_array(hns)) {
887 JsonVariant *e;
888
889 JSON_VARIANT_ARRAY_FOREACH(e, hns) {
890
891 if (!json_variant_is_string(e)) {
892 json_log(e, flags, 0, "Hostname is not a string, ignoring: %m");
893 continue;
894 }
895
896 if (streq(json_variant_string(hns), hn))
897 return true;
898 }
899
900 return false;
901 }
902
903 json_log(hns, flags, 0, "Hostname is not a string or array of strings, ignoring: %m");
904 return false;
905 }
906
907 static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
908
909 static const JsonDispatch per_machine_dispatch_table[] = {
910 { "matchMachineId", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
911 { "matchHostname", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
912 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
913 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
914 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
915 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
916 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
917 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
918 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, preferred_language), JSON_SAFE },
919 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
920 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
921 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
922 { "notBeforeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
923 { "notAfterUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
924 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
925 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_disk_size, offsetof(UserRecord, disk_size), 0 },
926 { "diskSizeRelative", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
927 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
928 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
929 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
930 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
931 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
932 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
933 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
934 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
935 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
936 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
937 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
938 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
939 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
940 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
941 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
942 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
943 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
944 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
945 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
946 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
947 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
948 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0, },
949 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0, },
950 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
951 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
952 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
953 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
954 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
955 { "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
956 { "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
957 { "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
958 { "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
959 { "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
960 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
961 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
962 { "stopDelayUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
963 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
964 { "passwordChangeMinUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
965 { "passwordChangeMaxUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
966 { "passwordChangeWarnUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
967 { "passwordChangeInactiveUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
968 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
969 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
970 {},
971 };
972
973 JsonVariant *e;
974 int r;
975
976 if (!variant)
977 return 0;
978
979 if (!json_variant_is_array(variant))
980 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
981
982 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
983 bool matching = false;
984 JsonVariant *m;
985
986 if (!json_variant_is_object(e))
987 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
988
989 m = json_variant_by_key(e, "matchMachineId");
990 if (m) {
991 r = per_machine_id_match(m, flags);
992 if (r < 0)
993 return r;
994
995 matching = r > 0;
996 }
997
998 if (!matching) {
999 m = json_variant_by_key(e, "matchHostname");
1000 if (m) {
1001 r = per_machine_hostname_match(m, flags);
1002 if (r < 0)
1003 return r;
1004
1005 matching = r > 0;
1006 }
1007 }
1008
1009 if (!matching)
1010 continue;
1011
1012 r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
1013 if (r < 0)
1014 return r;
1015 }
1016
1017 return 0;
1018 }
1019
1020 static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1021
1022 static const JsonDispatch status_dispatch_table[] = {
1023 { "diskUsage", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_usage), 0 },
1024 { "diskFree", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_free), 0 },
1025 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
1026 { "diskCeiling", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_ceiling), 0 },
1027 { "diskFloor", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_floor), 0 },
1028 { "state", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, state), JSON_SAFE },
1029 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1030 { "signedLocally", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, signed_locally), 0 },
1031 { "goodAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, good_authentication_counter), 0 },
1032 { "badAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, bad_authentication_counter), 0 },
1033 { "lastGoodAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_good_authentication_usec), 0 },
1034 { "lastBadAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_bad_authentication_usec), 0 },
1035 { "rateLimitBeginUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
1036 { "rateLimitCount", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
1037 { "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
1038 {},
1039 };
1040
1041 char smid[SD_ID128_STRING_MAX];
1042 JsonVariant *m;
1043 sd_id128_t mid;
1044 int r;
1045
1046 if (!variant)
1047 return 0;
1048
1049 if (!json_variant_is_object(variant))
1050 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
1051
1052 r = sd_id128_get_machine(&mid);
1053 if (r < 0)
1054 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
1055
1056 m = json_variant_by_key(variant, sd_id128_to_string(mid, smid));
1057 if (!m)
1058 return 0;
1059
1060 return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
1061 }
1062
1063 int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
1064 const char *suffix;
1065 char *z;
1066
1067 assert(storage >= 0);
1068 assert(user_name_and_realm);
1069 assert(ret);
1070
1071 if (storage == USER_LUKS)
1072 suffix = ".home";
1073 else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
1074 suffix = ".homedir";
1075 else {
1076 *ret = NULL;
1077 return 0;
1078 }
1079
1080 z = strjoin("/home/", user_name_and_realm, suffix);
1081 if (!z)
1082 return -ENOMEM;
1083
1084 *ret = z;
1085 return 1;
1086 }
1087
1088 static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
1089 int r;
1090
1091 assert(h);
1092
1093 if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
1094 return 0;
1095
1096 assert(h->user_name);
1097
1098 if (!h->user_name_and_realm_auto && h->realm) {
1099 h->user_name_and_realm_auto = strjoin(h->user_name, "@", h->realm);
1100 if (!h->user_name_and_realm_auto)
1101 return json_log_oom(h->json, json_flags);
1102 }
1103
1104 /* Let's add in the following automatisms only for regular users, they don't make sense for any others */
1105 if (user_record_disposition(h) != USER_REGULAR)
1106 return 0;
1107
1108 if (!h->home_directory && !h->home_directory_auto) {
1109 h->home_directory_auto = path_join("/home/", h->user_name);
1110 if (!h->home_directory_auto)
1111 return json_log_oom(h->json, json_flags);
1112 }
1113
1114 if (!h->image_path && !h->image_path_auto) {
1115 r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto);
1116 if (r < 0)
1117 return json_log(h->json, json_flags, r, "Failed to determine default image path: %m");
1118 }
1119
1120 return 0;
1121 }
1122
1123 int user_group_record_mangle(
1124 JsonVariant *v,
1125 UserRecordLoadFlags load_flags,
1126 JsonVariant **ret_variant,
1127 UserRecordMask *ret_mask) {
1128
1129 static const struct {
1130 UserRecordMask mask;
1131 const char *name;
1132 } mask_field[] = {
1133 { USER_RECORD_PRIVILEGED, "privileged" },
1134 { USER_RECORD_SECRET, "secret" },
1135 { USER_RECORD_BINDING, "binding" },
1136 { USER_RECORD_PER_MACHINE, "perMachine" },
1137 { USER_RECORD_STATUS, "status" },
1138 { USER_RECORD_SIGNATURE, "signature" },
1139 };
1140
1141 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1142 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
1143 JsonVariant *array[ELEMENTSOF(mask_field) * 2];
1144 size_t n_retain = 0, i;
1145 UserRecordMask m = 0;
1146 int r;
1147
1148 assert((load_flags & _USER_RECORD_MASK_MAX) == 0); /* detect mistakes when accidentally passing
1149 * UserRecordMask bit masks as UserRecordLoadFlags
1150 * value */
1151
1152 assert(v);
1153 assert(ret_variant);
1154 assert(ret_mask);
1155
1156 /* Note that this function is shared with the group record parser, hence we try to be generic in our
1157 * log message wording here, to cover both cases. */
1158
1159 if (!json_variant_is_object(v))
1160 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is not a JSON object, refusing.");
1161
1162 if (USER_RECORD_ALLOW_MASK(load_flags) == 0) /* allow nothing? */
1163 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Nothing allowed in record, refusing.");
1164
1165 if (USER_RECORD_STRIP_MASK(load_flags) == _USER_RECORD_MASK_MAX) /* strip everything? */
1166 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing.");
1167
1168 /* Check if we have the special sections and if they match our flags set */
1169 for (i = 0; i < ELEMENTSOF(mask_field); i++) {
1170 JsonVariant *e, *k;
1171
1172 if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) {
1173 if (!w)
1174 w = json_variant_ref(v);
1175
1176 r = json_variant_filter(&w, STRV_MAKE(mask_field[i].name));
1177 if (r < 0)
1178 return json_log(w, json_flags, r, "Failed to remove field from variant: %m");
1179
1180 continue;
1181 }
1182
1183 e = json_variant_by_key_full(v, mask_field[i].name, &k);
1184 if (e) {
1185 if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), mask_field[i].mask))
1186 return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", mask_field[i].name);
1187
1188 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1189 array[n_retain++] = k;
1190 array[n_retain++] = e;
1191 }
1192
1193 m |= mask_field[i].mask;
1194 } else {
1195 if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), mask_field[i].mask))
1196 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", mask_field[i].name);
1197 }
1198 }
1199
1200 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1201 /* If we are supposed to strip regular items, then let's instead just allocate a new object
1202 * with just the stuff we need. */
1203
1204 w = json_variant_unref(w);
1205 r = json_variant_new_object(&w, array, n_retain);
1206 if (r < 0)
1207 return json_log(v, json_flags, r, "Failed to allocate new object: %m");
1208 } else {
1209 /* And now check if there's anything else in the record */
1210 for (i = 0; i < json_variant_elements(v); i += 2) {
1211 const char *f;
1212 bool special = false;
1213 size_t j;
1214
1215 assert_se(f = json_variant_string(json_variant_by_index(v, i)));
1216
1217 for (j = 0; j < ELEMENTSOF(mask_field); j++)
1218 if (streq(f, mask_field[j].name)) { /* already covered in the loop above */
1219 special = true;
1220 continue;
1221 }
1222
1223 if (!special) {
1224 if ((load_flags & (USER_RECORD_ALLOW_REGULAR|USER_RECORD_REQUIRE_REGULAR)) == 0)
1225 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", f);
1226
1227 m |= USER_RECORD_REGULAR;
1228 break;
1229 }
1230 }
1231 }
1232
1233 if (FLAGS_SET(load_flags, USER_RECORD_REQUIRE_REGULAR) && !FLAGS_SET(m, USER_RECORD_REGULAR))
1234 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks basic identity fields, which are required.");
1235
1236 if (m == 0)
1237 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is empty.");
1238
1239 if (w)
1240 *ret_variant = TAKE_PTR(w);
1241 else
1242 *ret_variant = json_variant_ref(v);
1243
1244 *ret_mask = m;
1245 return 0;
1246 }
1247
1248 int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
1249
1250 static const JsonDispatch user_dispatch_table[] = {
1251 { "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
1252 { "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
1253 { "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
1254 { "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
1255 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
1256 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
1257 { "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(UserRecord, disposition), 0 },
1258 { "lastChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_change_usec), 0 },
1259 { "lastPasswordChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_password_change_usec), 0 },
1260 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
1261 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
1262 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
1263 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
1264 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, preferred_language), JSON_SAFE },
1265 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
1266 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
1267 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
1268 { "notBeforeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
1269 { "notAfterUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
1270 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
1271 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_disk_size, offsetof(UserRecord, disk_size), 0 },
1272 { "diskSizeRelative", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
1273 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
1274 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1275 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
1276 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
1277 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
1278 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
1279 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
1280 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
1281 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
1282 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
1283 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
1284 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
1285 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
1286 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
1287 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
1288 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1289 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1290 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
1291 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1292 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1293 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1294 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1295 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0 },
1296 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0 },
1297 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1298 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1299 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1300 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
1301 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
1302 { "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
1303 { "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
1304 { "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
1305 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1306 { "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
1307 { "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
1308 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
1309 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
1310 { "stopDelayUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
1311 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
1312 { "passwordChangeMinUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
1313 { "passwordChangeMaxUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
1314 { "passwordChangeWarnUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
1315 { "passwordChangeInactiveUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
1316 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
1317 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
1318
1319 { "secret", JSON_VARIANT_OBJECT, dispatch_secret, 0, 0 },
1320 { "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
1321
1322 /* Ignore the perMachine, binding, status stuff here, and process it later, so that it overrides whatever is set above */
1323 { "perMachine", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1324 { "binding", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1325 { "status", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1326
1327 /* Ignore 'signature', we check it with explicit accessors instead */
1328 { "signature", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1329 {},
1330 };
1331
1332 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1333 int r;
1334
1335 assert(h);
1336 assert(!h->json);
1337
1338 /* Note that this call will leave a half-initialized record around on failure! */
1339
1340 r = user_group_record_mangle(v, load_flags, &h->json, &h->mask);
1341 if (r < 0)
1342 return r;
1343
1344 r = json_dispatch(h->json, user_dispatch_table, NULL, json_flags, h);
1345 if (r < 0)
1346 return r;
1347
1348 /* During the parsing operation above we ignored the 'perMachine', 'binding' and 'status' fields,
1349 * since we want them to override the global options. Let's process them now. */
1350
1351 r = dispatch_per_machine("perMachine", json_variant_by_key(h->json, "perMachine"), json_flags, h);
1352 if (r < 0)
1353 return r;
1354
1355 r = dispatch_binding("binding", json_variant_by_key(h->json, "binding"), json_flags, h);
1356 if (r < 0)
1357 return r;
1358
1359 r = dispatch_status("status", json_variant_by_key(h->json, "status"), json_flags, h);
1360 if (r < 0)
1361 return r;
1362
1363 if (FLAGS_SET(h->mask, USER_RECORD_REGULAR) && !h->user_name)
1364 return json_log(h->json, json_flags, SYNTHETIC_ERRNO(EINVAL), "User name field missing, refusing.");
1365
1366 r = user_record_augment(h, json_flags);
1367 if (r < 0)
1368 return r;
1369
1370 return 0;
1371 }
1372
1373 int user_record_build(UserRecord **ret, ...) {
1374 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1375 _cleanup_(user_record_unrefp) UserRecord *u = NULL;
1376 va_list ap;
1377 int r;
1378
1379 assert(ret);
1380
1381 va_start(ap, ret);
1382 r = json_buildv(&v, ap);
1383 va_end(ap);
1384
1385 if (r < 0)
1386 return r;
1387
1388 u = user_record_new();
1389 if (!u)
1390 return -ENOMEM;
1391
1392 r = user_record_load(u, v, USER_RECORD_LOAD_FULL);
1393 if (r < 0)
1394 return r;
1395
1396 *ret = TAKE_PTR(u);
1397 return 0;
1398 }
1399
1400 const char *user_record_user_name_and_realm(UserRecord *h) {
1401 assert(h);
1402
1403 /* Return the pre-initialized joined string if it is defined */
1404 if (h->user_name_and_realm_auto)
1405 return h->user_name_and_realm_auto;
1406
1407 /* If it's not defined then we cannot have a realm */
1408 assert(!h->realm);
1409 return h->user_name;
1410 }
1411
1412 UserStorage user_record_storage(UserRecord *h) {
1413 assert(h);
1414
1415 if (h->storage >= 0)
1416 return h->storage;
1417
1418 return USER_CLASSIC;
1419 }
1420
1421 const char *user_record_file_system_type(UserRecord *h) {
1422 assert(h);
1423
1424 return h->file_system_type ?: "ext4";
1425 }
1426
1427 const char *user_record_skeleton_directory(UserRecord *h) {
1428 assert(h);
1429
1430 return h->skeleton_directory ?: "/etc/skel";
1431 }
1432
1433 mode_t user_record_access_mode(UserRecord *h) {
1434 assert(h);
1435
1436 return h->access_mode != (mode_t) -1 ? h->access_mode : 0700;
1437 }
1438
1439 const char* user_record_home_directory(UserRecord *h) {
1440 assert(h);
1441
1442 if (h->home_directory)
1443 return h->home_directory;
1444 if (h->home_directory_auto)
1445 return h->home_directory_auto;
1446
1447 /* The root user is special, hence be special about it */
1448 if (streq_ptr(h->user_name, "root"))
1449 return "/root";
1450
1451 return "/";
1452 }
1453
1454 const char *user_record_image_path(UserRecord *h) {
1455 assert(h);
1456
1457 if (h->image_path)
1458 return h->image_path;
1459 if (h->image_path_auto)
1460 return h->image_path_auto;
1461
1462 return IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT) ? user_record_home_directory(h) : NULL;
1463 }
1464
1465 const char *user_record_cifs_user_name(UserRecord *h) {
1466 assert(h);
1467
1468 return h->cifs_user_name ?: h->user_name;
1469 }
1470
1471 unsigned long user_record_mount_flags(UserRecord *h) {
1472 assert(h);
1473
1474 return (h->nosuid ? MS_NOSUID : 0) |
1475 (h->noexec ? MS_NOEXEC : 0) |
1476 (h->nodev ? MS_NODEV : 0);
1477 }
1478
1479 const char *user_record_shell(UserRecord *h) {
1480 assert(h);
1481
1482 if (h->shell)
1483 return h->shell;
1484
1485 if (streq_ptr(h->user_name, "root"))
1486 return "/bin/sh";
1487
1488 if (user_record_disposition(h) == USER_REGULAR)
1489 return "/bin/bash";
1490
1491 return NOLOGIN;
1492 }
1493
1494 const char *user_record_real_name(UserRecord *h) {
1495 assert(h);
1496
1497 return h->real_name ?: h->user_name;
1498 }
1499
1500 bool user_record_luks_discard(UserRecord *h) {
1501 const char *ip;
1502
1503 assert(h);
1504
1505 if (h->luks_discard >= 0)
1506 return h->luks_discard;
1507
1508 ip = user_record_image_path(h);
1509 if (!ip)
1510 return false;
1511
1512 /* Use discard by default if we are referring to a real block device, but not when operating on a
1513 * loopback device. We want to optimize for SSD and flash storage after all, but we should be careful
1514 * when storing stuff on top of regular file systems in loopback files as doing discard then would
1515 * mean thin provisioning and we should not do that willy-nilly since it means we'll risk EIO later
1516 * on should the disk space to back our file systems not be available. */
1517
1518 return path_startswith(ip, "/dev/");
1519 }
1520
1521 bool user_record_luks_offline_discard(UserRecord *h) {
1522 const char *ip;
1523
1524 assert(h);
1525
1526 if (h->luks_offline_discard >= 0)
1527 return h->luks_offline_discard;
1528
1529 /* Discard while we are logged out should generally be a good idea, except when operating directly on
1530 * physical media, where we should just bind it to the online discard mode. */
1531
1532 ip = user_record_image_path(h);
1533 if (!ip)
1534 return false;
1535
1536 if (path_startswith(ip, "/dev/"))
1537 return user_record_luks_discard(h);
1538
1539 return true;
1540 }
1541
1542 const char *user_record_luks_cipher(UserRecord *h) {
1543 assert(h);
1544
1545 return h->luks_cipher ?: "aes";
1546 }
1547
1548 const char *user_record_luks_cipher_mode(UserRecord *h) {
1549 assert(h);
1550
1551 return h->luks_cipher_mode ?: "xts-plain64";
1552 }
1553
1554 uint64_t user_record_luks_volume_key_size(UserRecord *h) {
1555 assert(h);
1556
1557 /* We return a value here that can be cast without loss into size_t which is what libcrypsetup expects */
1558
1559 if (h->luks_volume_key_size == UINT64_MAX)
1560 return 256 / 8;
1561
1562 return MIN(h->luks_volume_key_size, SIZE_MAX);
1563 }
1564
1565 const char* user_record_luks_pbkdf_type(UserRecord *h) {
1566 assert(h);
1567
1568 return h->luks_pbkdf_type ?: "argon2i";
1569 }
1570
1571 uint64_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h) {
1572 assert(h);
1573
1574 /* Returns a value with ms granularity, since that's what libcryptsetup expects */
1575
1576 if (h->luks_pbkdf_time_cost_usec == UINT64_MAX)
1577 return 500 * USEC_PER_MSEC; /* We default to 500ms, in contrast to libcryptsetup's 2s, which is just awfully slow on every login */
1578
1579 return MIN(DIV_ROUND_UP(h->luks_pbkdf_time_cost_usec, USEC_PER_MSEC), UINT32_MAX) * USEC_PER_MSEC;
1580 }
1581
1582 uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) {
1583 assert(h);
1584
1585 /* Returns a value with kb granularity, since that's what libcryptsetup expects */
1586
1587 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1588 return 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */
1589
1590 return MIN(DIV_ROUND_UP(h->luks_pbkdf_memory_cost, 1024), UINT32_MAX) * 1024;
1591 }
1592
1593 uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) {
1594 assert(h);
1595
1596 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1597 return 1; /* We default to 1, since this should work on smaller systems too */
1598
1599 return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX);
1600 }
1601
1602 const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h) {
1603 assert(h);
1604
1605 return h->luks_pbkdf_hash_algorithm ?: "sha512";
1606 }
1607
1608 gid_t user_record_gid(UserRecord *h) {
1609 assert(h);
1610
1611 if (gid_is_valid(h->gid))
1612 return h->gid;
1613
1614 return (gid_t) h->uid;
1615 }
1616
1617 UserDisposition user_record_disposition(UserRecord *h) {
1618 assert(h);
1619
1620 if (h->disposition >= 0)
1621 return h->disposition;
1622
1623 /* If not declared, derive from UID */
1624
1625 if (!uid_is_valid(h->uid))
1626 return _USER_DISPOSITION_INVALID;
1627
1628 if (h->uid == 0 || h->uid == UID_NOBODY)
1629 return USER_INTRINSIC;
1630
1631 if (uid_is_system(h->uid))
1632 return USER_SYSTEM;
1633
1634 if (uid_is_dynamic(h->uid))
1635 return USER_DYNAMIC;
1636
1637 if (uid_is_container(h->uid))
1638 return USER_CONTAINER;
1639
1640 if (h->uid > INT32_MAX)
1641 return USER_RESERVED;
1642
1643 return USER_REGULAR;
1644 }
1645
1646 int user_record_removable(UserRecord *h) {
1647 UserStorage storage;
1648 assert(h);
1649
1650 if (h->removable >= 0)
1651 return h->removable;
1652
1653 /* Refuse to decide for classic records */
1654 storage = user_record_storage(h);
1655 if (h->storage < 0 || h->storage == USER_CLASSIC)
1656 return -1;
1657
1658 /* For now consider only LUKS home directories with a reference by path as removable */
1659 return storage == USER_LUKS && path_startswith(user_record_image_path(h), "/dev/");
1660 }
1661
1662 uint64_t user_record_ratelimit_interval_usec(UserRecord *h) {
1663 assert(h);
1664
1665 if (h->ratelimit_interval_usec == UINT64_MAX)
1666 return DEFAULT_RATELIMIT_INTERVAL_USEC;
1667
1668 return h->ratelimit_interval_usec;
1669 }
1670
1671 uint64_t user_record_ratelimit_burst(UserRecord *h) {
1672 assert(h);
1673
1674 if (h->ratelimit_burst == UINT64_MAX)
1675 return DEFAULT_RATELIMIT_BURST;
1676
1677 return h->ratelimit_burst;
1678 }
1679
1680 bool user_record_can_authenticate(UserRecord *h) {
1681 assert(h);
1682
1683 /* Returns true if there's some form of property configured that the user can authenticate against */
1684
1685 if (h->n_pkcs11_encrypted_key > 0)
1686 return true;
1687
1688 return !strv_isempty(h->hashed_password);
1689 }
1690
1691 uint64_t user_record_ratelimit_next_try(UserRecord *h) {
1692 assert(h);
1693
1694 /* Calculates when the it's possible to login next. Returns:
1695 *
1696 * UINT64_MAX → Nothing known
1697 * 0 → Right away
1698 * Any other → Next time in CLOCK_REALTIME in usec (which could be in the past)
1699 */
1700
1701 if (h->ratelimit_begin_usec == UINT64_MAX ||
1702 h->ratelimit_count == UINT64_MAX)
1703 return UINT64_MAX;
1704
1705 if (h->ratelimit_count < user_record_ratelimit_burst(h))
1706 return 0;
1707
1708 return usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h));
1709 }
1710
1711 bool user_record_equal(UserRecord *a, UserRecord *b) {
1712 assert(a);
1713 assert(b);
1714
1715 /* We assume that when a record is modified its JSON data is updated at the same time, hence it's
1716 * sufficient to compare the JSON data. */
1717
1718 return json_variant_equal(a->json, b->json);
1719 }
1720
1721 bool user_record_compatible(UserRecord *a, UserRecord *b) {
1722 assert(a);
1723 assert(b);
1724
1725 /* If either lacks a the regular section, we can't really decide, let's hence say they are
1726 * incompatible. */
1727 if (!(a->mask & b->mask & USER_RECORD_REGULAR))
1728 return false;
1729
1730 return streq_ptr(a->user_name, b->user_name) &&
1731 streq_ptr(a->realm, b->realm);
1732 }
1733
1734 int user_record_compare_last_change(UserRecord *a, UserRecord *b) {
1735 assert(a);
1736 assert(b);
1737
1738 if (a->last_change_usec == b->last_change_usec)
1739 return 0;
1740
1741 /* Always consider a record with a timestamp newer than one without */
1742 if (a->last_change_usec == UINT64_MAX)
1743 return -1;
1744 if (b->last_change_usec == UINT64_MAX)
1745 return 1;
1746
1747 return CMP(a->last_change_usec, b->last_change_usec);
1748 }
1749
1750 int user_record_clone(UserRecord *h, UserRecordLoadFlags flags, UserRecord **ret) {
1751 _cleanup_(user_record_unrefp) UserRecord *c = NULL;
1752 int r;
1753
1754 assert(h);
1755 assert(ret);
1756
1757 c = user_record_new();
1758 if (!c)
1759 return -ENOMEM;
1760
1761 r = user_record_load(c, h->json, flags);
1762 if (r < 0)
1763 return r;
1764
1765 *ret = TAKE_PTR(c);
1766 return 0;
1767 }
1768
1769 int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask) {
1770 _cleanup_(user_record_unrefp) UserRecord *x = NULL, *y = NULL;
1771 int r;
1772
1773 assert(a);
1774 assert(b);
1775
1776 /* Compares the two records, but ignores anything not listed in the specified mask */
1777
1778 if ((a->mask & ~mask) != 0) {
1779 r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &x);
1780 if (r < 0)
1781 return r;
1782
1783 a = x;
1784 }
1785
1786 if ((b->mask & ~mask) != 0) {
1787 r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &y);
1788 if (r < 0)
1789 return r;
1790
1791 b = y;
1792 }
1793
1794 return user_record_equal(a, b);
1795 }
1796
1797 int user_record_test_blocked(UserRecord *h) {
1798 usec_t n;
1799
1800 /* Checks whether access to the specified user shall be allowed at the moment. Returns:
1801 *
1802 * -ESTALE: Record is from the future
1803 * -ENOLCK: Record is blocked
1804 * -EL2HLT: Record is not valid yet
1805 * -EL3HLT: Record is not valid anymore
1806 *
1807 */
1808
1809 assert(h);
1810
1811 n = now(CLOCK_REALTIME);
1812 if (h->last_change_usec != UINT64_MAX &&
1813 h->last_change_usec > n) /* Don't allow log ins when the record is from the future */
1814 return -ESTALE;
1815
1816 if (h->locked > 0)
1817 return -ENOLCK;
1818
1819 if (h->not_before_usec != UINT64_MAX && n < h->not_before_usec)
1820 return -EL2HLT;
1821 if (h->not_after_usec != UINT64_MAX && n > h->not_after_usec)
1822 return -EL3HLT;
1823
1824 return 0;
1825 }
1826
1827 int user_record_test_password_change_required(UserRecord *h) {
1828 bool change_permitted;
1829 usec_t n;
1830
1831 assert(h);
1832
1833 /* Checks whether the user must change the password when logging in
1834
1835 -EKEYREVOKED: Change password now because admin said so
1836 -EOWNERDEAD: Change password now because it expired
1837 -EKEYREJECTED: Password is expired, no changing is allowed
1838 -EKEYEXPIRED: Password is about to expire, warn user
1839 -ENETDOWN: Record has expiration info but no password change timestamp
1840 -EROFS: No password change required nor permitted
1841 0: No password change required, but permitted
1842 */
1843
1844 /* If a password change request has been set explicitly, it overrides everything */
1845 if (h->password_change_now > 0)
1846 return -EKEYREVOKED;
1847
1848 n = now(CLOCK_REALTIME);
1849
1850 /* Then, let's check if password changing is currently allowed at all */
1851 if (h->password_change_min_usec != UINT64_MAX) {
1852
1853 /* Expiry configured but no password change timestamp known? */
1854 if (h->last_password_change_usec == UINT64_MAX)
1855 return -ENETDOWN;
1856
1857 if (h->password_change_min_usec >= UINT64_MAX - h->last_password_change_usec)
1858 change_permitted = false;
1859 else
1860 change_permitted = n >= h->last_password_change_usec + h->password_change_min_usec;
1861
1862 } else
1863 change_permitted = true;
1864
1865 /* Let's check whether the password has expired. */
1866 if (!(h->password_change_max_usec == UINT64_MAX ||
1867 h->password_change_max_usec >= UINT64_MAX - h->last_password_change_usec)) {
1868
1869 uint64_t change_before;
1870
1871 /* Expiry configured but no password change timestamp known? */
1872 if (h->last_password_change_usec == UINT64_MAX)
1873 return -ENETDOWN;
1874
1875 /* Password is in inactive phase? */
1876 if (h->password_change_inactive_usec != UINT64_MAX &&
1877 h->password_change_inactive_usec < UINT64_MAX - h->password_change_max_usec) {
1878 usec_t added;
1879
1880 added = h->password_change_inactive_usec + h->password_change_max_usec;
1881 if (added < UINT64_MAX - h->last_password_change_usec &&
1882 n >= h->last_password_change_usec + added)
1883 return -EKEYREJECTED;
1884 }
1885
1886 /* Password needs to be changed now? */
1887 change_before = h->last_password_change_usec + h->password_change_max_usec;
1888 if (n >= change_before)
1889 return change_permitted ? -EOWNERDEAD : -EKEYREJECTED;
1890
1891 /* Warn user? */
1892 if (h->password_change_warn_usec != UINT64_MAX &&
1893 (change_before < h->password_change_warn_usec ||
1894 n >= change_before - h->password_change_warn_usec))
1895 return change_permitted ? -EKEYEXPIRED : -EROFS;
1896 }
1897
1898 /* No password changing necessary */
1899 return change_permitted ? 0 : -EROFS;
1900 }
1901
1902 static const char* const user_storage_table[_USER_STORAGE_MAX] = {
1903 [USER_CLASSIC] = "classic",
1904 [USER_LUKS] = "luks",
1905 [USER_DIRECTORY] = "directory",
1906 [USER_SUBVOLUME] = "subvolume",
1907 [USER_FSCRYPT] = "fscrypt",
1908 [USER_CIFS] = "cifs",
1909 };
1910
1911 DEFINE_STRING_TABLE_LOOKUP(user_storage, UserStorage);
1912
1913 static const char* const user_disposition_table[_USER_DISPOSITION_MAX] = {
1914 [USER_INTRINSIC] = "intrinsic",
1915 [USER_SYSTEM] = "system",
1916 [USER_DYNAMIC] = "dynamic",
1917 [USER_REGULAR] = "regular",
1918 [USER_CONTAINER] = "container",
1919 [USER_RESERVED] = "reserved",
1920 };
1921
1922 DEFINE_STRING_TABLE_LOOKUP(user_disposition, UserDisposition);