]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/user-record.c
Merge pull request #15745 from keszybz/one-more-specifier
[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->pkcs11_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 { "pkcs11Pin", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, pkcs11_pin), 0 },
624 { "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 },
625 {},
626 };
627
628 return json_dispatch(variant, secret_dispatch_table, NULL, flags, userdata);
629 }
630
631 static int dispatch_pkcs11_uri(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
632 char **s = userdata;
633 const char *n;
634 int r;
635
636 if (json_variant_is_null(variant)) {
637 *s = mfree(*s);
638 return 0;
639 }
640
641 if (!json_variant_is_string(variant))
642 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
643
644 n = json_variant_string(variant);
645 if (!pkcs11_uri_valid(n))
646 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
647
648 r = free_and_strdup(s, n);
649 if (r < 0)
650 return json_log(variant, flags, r, "Failed to allocate string: %m");
651
652 return 0;
653 }
654
655 static int dispatch_pkcs11_uri_array(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
656 _cleanup_strv_free_ char **z = NULL;
657 char ***l = userdata;
658 JsonVariant *e;
659 int r;
660
661 if (json_variant_is_null(variant)) {
662 *l = strv_free(*l);
663 return 0;
664 }
665
666 if (json_variant_is_string(variant)) {
667 const char *n;
668
669 n = json_variant_string(variant);
670 if (!pkcs11_uri_valid(n))
671 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid RFC7512 PKCS#11 URI.", strna(name));
672
673 z = strv_new(n);
674 if (!z)
675 return log_oom();
676
677 } else {
678
679 if (!json_variant_is_array(variant))
680 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string or array of strings.", strna(name));
681
682 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
683 const char *n;
684
685 if (!json_variant_is_string(e))
686 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
687
688 n = json_variant_string(e);
689 if (!pkcs11_uri_valid(n))
690 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);
691
692 r = strv_extend(&z, n);
693 if (r < 0)
694 return log_oom();
695 }
696 }
697
698 strv_free_and_replace(*l, z);
699 return 0;
700 }
701
702 static int dispatch_pkcs11_key_data(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
703 Pkcs11EncryptedKey *k = userdata;
704 size_t l;
705 void *b;
706 int r;
707
708 if (json_variant_is_null(variant)) {
709 k->data = mfree(k->data);
710 k->size = 0;
711 return 0;
712 }
713
714 if (!json_variant_is_string(variant))
715 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
716
717 r = unbase64mem(json_variant_string(variant), (size_t) -1, &b, &l);
718 if (r < 0)
719 return json_log(variant, flags, r, "Failed to decode encrypted PKCS#11 key: %m");
720
721 erase_and_free(k->data);
722 k->data = b;
723 k->size = l;
724
725 return 0;
726 }
727
728 static int dispatch_pkcs11_key(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
729 UserRecord *h = userdata;
730 JsonVariant *e;
731 int r;
732
733 if (!json_variant_is_array(variant))
734 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
735
736 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
737 Pkcs11EncryptedKey *array, *k;
738
739 static const JsonDispatch pkcs11_key_dispatch_table[] = {
740 { "uri", JSON_VARIANT_STRING, dispatch_pkcs11_uri, offsetof(Pkcs11EncryptedKey, uri), JSON_MANDATORY },
741 { "data", JSON_VARIANT_STRING, dispatch_pkcs11_key_data, 0, JSON_MANDATORY },
742 { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Pkcs11EncryptedKey, hashed_password), JSON_MANDATORY },
743 {},
744 };
745
746 if (!json_variant_is_object(e))
747 return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not an object.");
748
749 array = reallocarray(h->pkcs11_encrypted_key, h->n_pkcs11_encrypted_key + 1, sizeof(Pkcs11EncryptedKey));
750 if (!array)
751 return log_oom();
752
753 h->pkcs11_encrypted_key = array;
754 k = h->pkcs11_encrypted_key + h->n_pkcs11_encrypted_key;
755 *k = (Pkcs11EncryptedKey) {};
756
757 r = json_dispatch(e, pkcs11_key_dispatch_table, NULL, flags, k);
758 if (r < 0) {
759 pkcs11_encrypted_key_done(k);
760 return r;
761 }
762
763 h->n_pkcs11_encrypted_key++;
764 }
765
766 return 0;
767 }
768
769 static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
770
771 static const JsonDispatch privileged_dispatch_table[] = {
772 { "passwordHint", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, password_hint), 0 },
773 { "hashedPassword", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, hashed_password), JSON_SAFE },
774 { "sshAuthorizedKeys", _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, ssh_authorized_keys), 0 },
775 { "pkcs11EncryptedKey", JSON_VARIANT_ARRAY, dispatch_pkcs11_key, 0, 0 },
776 {},
777 };
778
779 return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
780 }
781
782 static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
783
784 static const JsonDispatch binding_dispatch_table[] = {
785 { "imagePath", JSON_VARIANT_STRING, json_dispatch_image_path, offsetof(UserRecord, image_path), 0 },
786 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
787 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
788 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
789 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
790 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
791 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
792 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
793 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
794 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
795 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
796 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
797 {},
798 };
799
800 char smid[SD_ID128_STRING_MAX];
801 JsonVariant *m;
802 sd_id128_t mid;
803 int r;
804
805 if (!variant)
806 return 0;
807
808 if (!json_variant_is_object(variant))
809 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
810
811 r = sd_id128_get_machine(&mid);
812 if (r < 0)
813 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
814
815 m = json_variant_by_key(variant, sd_id128_to_string(mid, smid));
816 if (!m)
817 return 0;
818
819 return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
820 }
821
822 int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags) {
823 sd_id128_t mid;
824 int r;
825
826 r = sd_id128_get_machine(&mid);
827 if (r < 0)
828 return json_log(ids, flags, r, "Failed to acquire machine ID: %m");
829
830 if (json_variant_is_string(ids)) {
831 sd_id128_t k;
832
833 r = sd_id128_from_string(json_variant_string(ids), &k);
834 if (r < 0) {
835 json_log(ids, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(ids));
836 return 0;
837 }
838
839 return sd_id128_equal(mid, k);
840 }
841
842 if (json_variant_is_array(ids)) {
843 JsonVariant *e;
844
845 JSON_VARIANT_ARRAY_FOREACH(e, ids) {
846 sd_id128_t k;
847
848 if (!json_variant_is_string(e)) {
849 json_log(e, flags, 0, "Machine ID is not a string, ignoring: %m");
850 continue;
851 }
852
853 r = sd_id128_from_string(json_variant_string(e), &k);
854 if (r < 0) {
855 json_log(e, flags, r, "%s is not a valid machine ID, ignoring: %m", json_variant_string(e));
856 continue;
857 }
858
859 if (sd_id128_equal(mid, k))
860 return true;
861 }
862
863 return false;
864 }
865
866 json_log(ids, flags, 0, "Machine ID is not a string or array of strings, ignoring: %m");
867 return false;
868 }
869
870 int per_machine_hostname_match(JsonVariant *hns, JsonDispatchFlags flags) {
871 _cleanup_free_ char *hn = NULL;
872 int r;
873
874 r = gethostname_strict(&hn);
875 if (r == -ENXIO) {
876 json_log(hns, flags, r, "No hostname set, not matching perMachine hostname record: %m");
877 return false;
878 }
879 if (r < 0)
880 return json_log(hns, flags, r, "Failed to acquire hostname: %m");
881
882 if (json_variant_is_string(hns))
883 return streq(json_variant_string(hns), hn);
884
885 if (json_variant_is_array(hns)) {
886 JsonVariant *e;
887
888 JSON_VARIANT_ARRAY_FOREACH(e, hns) {
889
890 if (!json_variant_is_string(e)) {
891 json_log(e, flags, 0, "Hostname is not a string, ignoring: %m");
892 continue;
893 }
894
895 if (streq(json_variant_string(hns), hn))
896 return true;
897 }
898
899 return false;
900 }
901
902 json_log(hns, flags, 0, "Hostname is not a string or array of strings, ignoring: %m");
903 return false;
904 }
905
906 static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
907
908 static const JsonDispatch per_machine_dispatch_table[] = {
909 { "matchMachineId", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
910 { "matchHostname", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
911 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
912 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
913 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
914 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
915 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
916 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
917 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, preferred_language), JSON_SAFE },
918 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
919 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
920 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
921 { "notBeforeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
922 { "notAfterUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
923 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
924 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_disk_size, offsetof(UserRecord, disk_size), 0 },
925 { "diskSizeRelative", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
926 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
927 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
928 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
929 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
930 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
931 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
932 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
933 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
934 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
935 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
936 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
937 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
938 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
939 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
940 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
941 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
942 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
943 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
944 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
945 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
946 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
947 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0, },
948 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0, },
949 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
950 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
951 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
952 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
953 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
954 { "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
955 { "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
956 { "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
957 { "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
958 { "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
959 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
960 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
961 { "stopDelayUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
962 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
963 { "passwordChangeMinUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
964 { "passwordChangeMaxUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
965 { "passwordChangeWarnUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
966 { "passwordChangeInactiveUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
967 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
968 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
969 {},
970 };
971
972 JsonVariant *e;
973 int r;
974
975 if (!variant)
976 return 0;
977
978 if (!json_variant_is_array(variant))
979 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
980
981 JSON_VARIANT_ARRAY_FOREACH(e, variant) {
982 bool matching = false;
983 JsonVariant *m;
984
985 if (!json_variant_is_object(e))
986 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of objects.", strna(name));
987
988 m = json_variant_by_key(e, "matchMachineId");
989 if (m) {
990 r = per_machine_id_match(m, flags);
991 if (r < 0)
992 return r;
993
994 matching = r > 0;
995 }
996
997 if (!matching) {
998 m = json_variant_by_key(e, "matchHostname");
999 if (m) {
1000 r = per_machine_hostname_match(m, flags);
1001 if (r < 0)
1002 return r;
1003
1004 matching = r > 0;
1005 }
1006 }
1007
1008 if (!matching)
1009 continue;
1010
1011 r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
1012 if (r < 0)
1013 return r;
1014 }
1015
1016 return 0;
1017 }
1018
1019 static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
1020
1021 static const JsonDispatch status_dispatch_table[] = {
1022 { "diskUsage", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_usage), 0 },
1023 { "diskFree", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_free), 0 },
1024 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
1025 { "diskCeiling", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_ceiling), 0 },
1026 { "diskFloor", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_floor), 0 },
1027 { "state", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, state), JSON_SAFE },
1028 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1029 { "signedLocally", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, signed_locally), 0 },
1030 { "goodAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, good_authentication_counter), 0 },
1031 { "badAuthenticationCounter", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, bad_authentication_counter), 0 },
1032 { "lastGoodAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_good_authentication_usec), 0 },
1033 { "lastBadAuthenticationUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_bad_authentication_usec), 0 },
1034 { "rateLimitBeginUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
1035 { "rateLimitCount", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
1036 { "removable", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, removable), 0 },
1037 {},
1038 };
1039
1040 char smid[SD_ID128_STRING_MAX];
1041 JsonVariant *m;
1042 sd_id128_t mid;
1043 int r;
1044
1045 if (!variant)
1046 return 0;
1047
1048 if (!json_variant_is_object(variant))
1049 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an object.", strna(name));
1050
1051 r = sd_id128_get_machine(&mid);
1052 if (r < 0)
1053 return json_log(variant, flags, r, "Failed to determine machine ID: %m");
1054
1055 m = json_variant_by_key(variant, sd_id128_to_string(mid, smid));
1056 if (!m)
1057 return 0;
1058
1059 return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
1060 }
1061
1062 static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
1063 assert(h);
1064
1065 if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
1066 return 0;
1067
1068 assert(h->user_name);
1069
1070 if (!h->user_name_and_realm_auto && h->realm) {
1071 h->user_name_and_realm_auto = strjoin(h->user_name, "@", h->realm);
1072 if (!h->user_name_and_realm_auto)
1073 return json_log_oom(h->json, json_flags);
1074 }
1075
1076 /* Let's add in the following automatisms only for regular users, they don't make sense for any others */
1077 if (user_record_disposition(h) != USER_REGULAR)
1078 return 0;
1079
1080 if (!h->home_directory && !h->home_directory_auto) {
1081 h->home_directory_auto = path_join("/home/", h->user_name);
1082 if (!h->home_directory_auto)
1083 return json_log_oom(h->json, json_flags);
1084 }
1085
1086 if (!h->image_path && !h->image_path_auto) {
1087 const char *suffix;
1088 UserStorage storage;
1089
1090 storage = user_record_storage(h);
1091 if (storage == USER_LUKS)
1092 suffix = ".home";
1093 else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
1094 suffix = ".homedir";
1095 else
1096 suffix = NULL;
1097
1098 if (suffix) {
1099 h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), suffix);
1100 if (!h->image_path_auto)
1101 return json_log_oom(h->json, json_flags);
1102 }
1103 }
1104
1105 return 0;
1106 }
1107
1108 int user_group_record_mangle(
1109 JsonVariant *v,
1110 UserRecordLoadFlags load_flags,
1111 JsonVariant **ret_variant,
1112 UserRecordMask *ret_mask) {
1113
1114 static const struct {
1115 UserRecordMask mask;
1116 const char *name;
1117 } mask_field[] = {
1118 { USER_RECORD_PRIVILEGED, "privileged" },
1119 { USER_RECORD_SECRET, "secret" },
1120 { USER_RECORD_BINDING, "binding" },
1121 { USER_RECORD_PER_MACHINE, "perMachine" },
1122 { USER_RECORD_STATUS, "status" },
1123 { USER_RECORD_SIGNATURE, "signature" },
1124 };
1125
1126 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1127 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
1128 JsonVariant *array[ELEMENTSOF(mask_field) * 2];
1129 size_t n_retain = 0, i;
1130 UserRecordMask m = 0;
1131 int r;
1132
1133 assert((load_flags & _USER_RECORD_MASK_MAX) == 0); /* detect mistakes when accidentally passing
1134 * UserRecordMask bit masks as UserRecordLoadFlags
1135 * value */
1136
1137 assert(v);
1138 assert(ret_variant);
1139 assert(ret_mask);
1140
1141 /* Note that this function is shared with the group record parser, hence we try to be generic in our
1142 * log message wording here, to cover both cases. */
1143
1144 if (!json_variant_is_object(v))
1145 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is not a JSON object, refusing.");
1146
1147 if (USER_RECORD_ALLOW_MASK(load_flags) == 0) /* allow nothing? */
1148 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Nothing allowed in record, refusing.");
1149
1150 if (USER_RECORD_STRIP_MASK(load_flags) == _USER_RECORD_MASK_MAX) /* strip everything? */
1151 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing.");
1152
1153 /* Check if we have the special sections and if they match our flags set */
1154 for (i = 0; i < ELEMENTSOF(mask_field); i++) {
1155 JsonVariant *e, *k;
1156
1157 if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) {
1158 if (!w)
1159 w = json_variant_ref(v);
1160
1161 r = json_variant_filter(&w, STRV_MAKE(mask_field[i].name));
1162 if (r < 0)
1163 return json_log(w, json_flags, r, "Failed to remove field from variant: %m");
1164
1165 continue;
1166 }
1167
1168 e = json_variant_by_key_full(v, mask_field[i].name, &k);
1169 if (e) {
1170 if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), mask_field[i].mask))
1171 return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", mask_field[i].name);
1172
1173 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1174 array[n_retain++] = k;
1175 array[n_retain++] = e;
1176 }
1177
1178 m |= mask_field[i].mask;
1179 } else {
1180 if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), mask_field[i].mask))
1181 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", mask_field[i].name);
1182 }
1183 }
1184
1185 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1186 /* If we are supposed to strip regular items, then let's instead just allocate a new object
1187 * with just the stuff we need. */
1188
1189 w = json_variant_unref(w);
1190 r = json_variant_new_object(&w, array, n_retain);
1191 if (r < 0)
1192 return json_log(v, json_flags, r, "Failed to allocate new object: %m");
1193 } else {
1194 /* And now check if there's anything else in the record */
1195 for (i = 0; i < json_variant_elements(v); i += 2) {
1196 const char *f;
1197 bool special = false;
1198 size_t j;
1199
1200 assert_se(f = json_variant_string(json_variant_by_index(v, i)));
1201
1202 for (j = 0; j < ELEMENTSOF(mask_field); j++)
1203 if (streq(f, mask_field[j].name)) { /* already covered in the loop above */
1204 special = true;
1205 continue;
1206 }
1207
1208 if (!special) {
1209 if ((load_flags & (USER_RECORD_ALLOW_REGULAR|USER_RECORD_REQUIRE_REGULAR)) == 0)
1210 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", f);
1211
1212 m |= USER_RECORD_REGULAR;
1213 break;
1214 }
1215 }
1216 }
1217
1218 if (FLAGS_SET(load_flags, USER_RECORD_REQUIRE_REGULAR) && !FLAGS_SET(m, USER_RECORD_REGULAR))
1219 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks basic identity fields, which are required.");
1220
1221 if (m == 0)
1222 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is empty.");
1223
1224 if (w)
1225 *ret_variant = TAKE_PTR(w);
1226 else
1227 *ret_variant = json_variant_ref(v);
1228
1229 *ret_mask = m;
1230 return 0;
1231 }
1232
1233 int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
1234
1235 static const JsonDispatch user_dispatch_table[] = {
1236 { "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
1237 { "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
1238 { "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
1239 { "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
1240 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
1241 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
1242 { "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(UserRecord, disposition), 0 },
1243 { "lastChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_change_usec), 0 },
1244 { "lastPasswordChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_password_change_usec), 0 },
1245 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
1246 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
1247 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
1248 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
1249 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, preferred_language), JSON_SAFE },
1250 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
1251 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
1252 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
1253 { "notBeforeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
1254 { "notAfterUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
1255 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
1256 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_disk_size, offsetof(UserRecord, disk_size), 0 },
1257 { "diskSizeRelative", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
1258 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
1259 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1260 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
1261 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
1262 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
1263 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
1264 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
1265 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
1266 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
1267 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
1268 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
1269 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
1270 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
1271 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
1272 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
1273 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1274 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1275 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
1276 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1277 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1278 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1279 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1280 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0 },
1281 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0 },
1282 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1283 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1284 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1285 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
1286 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
1287 { "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
1288 { "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
1289 { "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
1290 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1291 { "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
1292 { "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
1293 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
1294 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
1295 { "stopDelayUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
1296 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
1297 { "passwordChangeMinUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
1298 { "passwordChangeMaxUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
1299 { "passwordChangeWarnUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
1300 { "passwordChangeInactiveUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
1301 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
1302 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
1303
1304 { "secret", JSON_VARIANT_OBJECT, dispatch_secret, 0, 0 },
1305 { "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
1306
1307 /* Ignore the perMachine, binding, status stuff here, and process it later, so that it overrides whatever is set above */
1308 { "perMachine", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1309 { "binding", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1310 { "status", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1311
1312 /* Ignore 'signature', we check it with explicit accessors instead */
1313 { "signature", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1314 {},
1315 };
1316
1317 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1318 int r;
1319
1320 assert(h);
1321 assert(!h->json);
1322
1323 /* Note that this call will leave a half-initialized record around on failure! */
1324
1325 r = user_group_record_mangle(v, load_flags, &h->json, &h->mask);
1326 if (r < 0)
1327 return r;
1328
1329 r = json_dispatch(h->json, user_dispatch_table, NULL, json_flags, h);
1330 if (r < 0)
1331 return r;
1332
1333 /* During the parsing operation above we ignored the 'perMachine', 'binding' and 'status' fields,
1334 * since we want them to override the global options. Let's process them now. */
1335
1336 r = dispatch_per_machine("perMachine", json_variant_by_key(h->json, "perMachine"), json_flags, h);
1337 if (r < 0)
1338 return r;
1339
1340 r = dispatch_binding("binding", json_variant_by_key(h->json, "binding"), json_flags, h);
1341 if (r < 0)
1342 return r;
1343
1344 r = dispatch_status("status", json_variant_by_key(h->json, "status"), json_flags, h);
1345 if (r < 0)
1346 return r;
1347
1348 if (FLAGS_SET(h->mask, USER_RECORD_REGULAR) && !h->user_name)
1349 return json_log(h->json, json_flags, SYNTHETIC_ERRNO(EINVAL), "User name field missing, refusing.");
1350
1351 r = user_record_augment(h, json_flags);
1352 if (r < 0)
1353 return r;
1354
1355 return 0;
1356 }
1357
1358 int user_record_build(UserRecord **ret, ...) {
1359 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1360 _cleanup_(user_record_unrefp) UserRecord *u = NULL;
1361 va_list ap;
1362 int r;
1363
1364 assert(ret);
1365
1366 va_start(ap, ret);
1367 r = json_buildv(&v, ap);
1368 va_end(ap);
1369
1370 if (r < 0)
1371 return r;
1372
1373 u = user_record_new();
1374 if (!u)
1375 return -ENOMEM;
1376
1377 r = user_record_load(u, v, USER_RECORD_LOAD_FULL);
1378 if (r < 0)
1379 return r;
1380
1381 *ret = TAKE_PTR(u);
1382 return 0;
1383 }
1384
1385 const char *user_record_user_name_and_realm(UserRecord *h) {
1386 assert(h);
1387
1388 /* Return the pre-initialized joined string if it is defined */
1389 if (h->user_name_and_realm_auto)
1390 return h->user_name_and_realm_auto;
1391
1392 /* If it's not defined then we cannot have a realm */
1393 assert(!h->realm);
1394 return h->user_name;
1395 }
1396
1397 UserStorage user_record_storage(UserRecord *h) {
1398 assert(h);
1399
1400 if (h->storage >= 0)
1401 return h->storage;
1402
1403 return USER_CLASSIC;
1404 }
1405
1406 const char *user_record_file_system_type(UserRecord *h) {
1407 assert(h);
1408
1409 return h->file_system_type ?: "ext4";
1410 }
1411
1412 const char *user_record_skeleton_directory(UserRecord *h) {
1413 assert(h);
1414
1415 return h->skeleton_directory ?: "/etc/skel";
1416 }
1417
1418 mode_t user_record_access_mode(UserRecord *h) {
1419 assert(h);
1420
1421 return h->access_mode != (mode_t) -1 ? h->access_mode : 0700;
1422 }
1423
1424 const char* user_record_home_directory(UserRecord *h) {
1425 assert(h);
1426
1427 if (h->home_directory)
1428 return h->home_directory;
1429 if (h->home_directory_auto)
1430 return h->home_directory_auto;
1431
1432 /* The root user is special, hence be special about it */
1433 if (streq_ptr(h->user_name, "root"))
1434 return "/root";
1435
1436 return "/";
1437 }
1438
1439 const char *user_record_image_path(UserRecord *h) {
1440 assert(h);
1441
1442 if (h->image_path)
1443 return h->image_path;
1444 if (h->image_path_auto)
1445 return h->image_path_auto;
1446
1447 return IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT) ? user_record_home_directory(h) : NULL;
1448 }
1449
1450 const char *user_record_cifs_user_name(UserRecord *h) {
1451 assert(h);
1452
1453 return h->cifs_user_name ?: h->user_name;
1454 }
1455
1456 unsigned long user_record_mount_flags(UserRecord *h) {
1457 assert(h);
1458
1459 return (h->nosuid ? MS_NOSUID : 0) |
1460 (h->noexec ? MS_NOEXEC : 0) |
1461 (h->nodev ? MS_NODEV : 0);
1462 }
1463
1464 const char *user_record_shell(UserRecord *h) {
1465 assert(h);
1466
1467 if (h->shell)
1468 return h->shell;
1469
1470 if (streq_ptr(h->user_name, "root"))
1471 return "/bin/sh";
1472
1473 if (user_record_disposition(h) == USER_REGULAR)
1474 return "/bin/bash";
1475
1476 return NOLOGIN;
1477 }
1478
1479 const char *user_record_real_name(UserRecord *h) {
1480 assert(h);
1481
1482 return h->real_name ?: h->user_name;
1483 }
1484
1485 bool user_record_luks_discard(UserRecord *h) {
1486 const char *ip;
1487
1488 assert(h);
1489
1490 if (h->luks_discard >= 0)
1491 return h->luks_discard;
1492
1493 ip = user_record_image_path(h);
1494 if (!ip)
1495 return false;
1496
1497 /* Use discard by default if we are referring to a real block device, but not when operating on a
1498 * loopback device. We want to optimize for SSD and flash storage after all, but we should be careful
1499 * when storing stuff on top of regular file systems in loopback files as doing discard then would
1500 * mean thin provisioning and we should not do that willy-nilly since it means we'll risk EIO later
1501 * on should the disk space to back our file systems not be available. */
1502
1503 return path_startswith(ip, "/dev/");
1504 }
1505
1506 bool user_record_luks_offline_discard(UserRecord *h) {
1507 const char *ip;
1508
1509 assert(h);
1510
1511 if (h->luks_offline_discard >= 0)
1512 return h->luks_offline_discard;
1513
1514 /* Discard while we are logged out should generally be a good idea, except when operating directly on
1515 * physical media, where we should just bind it to the online discard mode. */
1516
1517 ip = user_record_image_path(h);
1518 if (!ip)
1519 return false;
1520
1521 if (path_startswith(ip, "/dev/"))
1522 return user_record_luks_discard(h);
1523
1524 return true;
1525 }
1526
1527 const char *user_record_luks_cipher(UserRecord *h) {
1528 assert(h);
1529
1530 return h->luks_cipher ?: "aes";
1531 }
1532
1533 const char *user_record_luks_cipher_mode(UserRecord *h) {
1534 assert(h);
1535
1536 return h->luks_cipher_mode ?: "xts-plain64";
1537 }
1538
1539 uint64_t user_record_luks_volume_key_size(UserRecord *h) {
1540 assert(h);
1541
1542 /* We return a value here that can be cast without loss into size_t which is what libcrypsetup expects */
1543
1544 if (h->luks_volume_key_size == UINT64_MAX)
1545 return 256 / 8;
1546
1547 return MIN(h->luks_volume_key_size, SIZE_MAX);
1548 }
1549
1550 const char* user_record_luks_pbkdf_type(UserRecord *h) {
1551 assert(h);
1552
1553 return h->luks_pbkdf_type ?: "argon2i";
1554 }
1555
1556 uint64_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h) {
1557 assert(h);
1558
1559 /* Returns a value with ms granularity, since that's what libcryptsetup expects */
1560
1561 if (h->luks_pbkdf_time_cost_usec == UINT64_MAX)
1562 return 500 * USEC_PER_MSEC; /* We default to 500ms, in contrast to libcryptsetup's 2s, which is just awfully slow on every login */
1563
1564 return MIN(DIV_ROUND_UP(h->luks_pbkdf_time_cost_usec, USEC_PER_MSEC), UINT32_MAX) * USEC_PER_MSEC;
1565 }
1566
1567 uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) {
1568 assert(h);
1569
1570 /* Returns a value with kb granularity, since that's what libcryptsetup expects */
1571
1572 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1573 return 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */
1574
1575 return MIN(DIV_ROUND_UP(h->luks_pbkdf_memory_cost, 1024), UINT32_MAX) * 1024;
1576 }
1577
1578 uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) {
1579 assert(h);
1580
1581 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1582 return 1; /* We default to 1, since this should work on smaller systems too */
1583
1584 return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX);
1585 }
1586
1587 const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h) {
1588 assert(h);
1589
1590 return h->luks_pbkdf_hash_algorithm ?: "sha512";
1591 }
1592
1593 gid_t user_record_gid(UserRecord *h) {
1594 assert(h);
1595
1596 if (gid_is_valid(h->gid))
1597 return h->gid;
1598
1599 return (gid_t) h->uid;
1600 }
1601
1602 UserDisposition user_record_disposition(UserRecord *h) {
1603 assert(h);
1604
1605 if (h->disposition >= 0)
1606 return h->disposition;
1607
1608 /* If not declared, derive from UID */
1609
1610 if (!uid_is_valid(h->uid))
1611 return _USER_DISPOSITION_INVALID;
1612
1613 if (h->uid == 0 || h->uid == UID_NOBODY)
1614 return USER_INTRINSIC;
1615
1616 if (uid_is_system(h->uid))
1617 return USER_SYSTEM;
1618
1619 if (uid_is_dynamic(h->uid))
1620 return USER_DYNAMIC;
1621
1622 if (uid_is_container(h->uid))
1623 return USER_CONTAINER;
1624
1625 if (h->uid > INT32_MAX)
1626 return USER_RESERVED;
1627
1628 return USER_REGULAR;
1629 }
1630
1631 int user_record_removable(UserRecord *h) {
1632 UserStorage storage;
1633 assert(h);
1634
1635 if (h->removable >= 0)
1636 return h->removable;
1637
1638 /* Refuse to decide for classic records */
1639 storage = user_record_storage(h);
1640 if (h->storage < 0 || h->storage == USER_CLASSIC)
1641 return -1;
1642
1643 /* For now consider only LUKS home directories with a reference by path as removable */
1644 return storage == USER_LUKS && path_startswith(user_record_image_path(h), "/dev/");
1645 }
1646
1647 uint64_t user_record_ratelimit_interval_usec(UserRecord *h) {
1648 assert(h);
1649
1650 if (h->ratelimit_interval_usec == UINT64_MAX)
1651 return DEFAULT_RATELIMIT_INTERVAL_USEC;
1652
1653 return h->ratelimit_interval_usec;
1654 }
1655
1656 uint64_t user_record_ratelimit_burst(UserRecord *h) {
1657 assert(h);
1658
1659 if (h->ratelimit_burst == UINT64_MAX)
1660 return DEFAULT_RATELIMIT_BURST;
1661
1662 return h->ratelimit_burst;
1663 }
1664
1665 bool user_record_can_authenticate(UserRecord *h) {
1666 assert(h);
1667
1668 /* Returns true if there's some form of property configured that the user can authenticate against */
1669
1670 if (h->n_pkcs11_encrypted_key > 0)
1671 return true;
1672
1673 return !strv_isempty(h->hashed_password);
1674 }
1675
1676 uint64_t user_record_ratelimit_next_try(UserRecord *h) {
1677 assert(h);
1678
1679 /* Calculates when the it's possible to login next. Returns:
1680 *
1681 * UINT64_MAX → Nothing known
1682 * 0 → Right away
1683 * Any other → Next time in CLOCK_REALTIME in usec (which could be in the past)
1684 */
1685
1686 if (h->ratelimit_begin_usec == UINT64_MAX ||
1687 h->ratelimit_count == UINT64_MAX)
1688 return UINT64_MAX;
1689
1690 if (h->ratelimit_count < user_record_ratelimit_burst(h))
1691 return 0;
1692
1693 return usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h));
1694 }
1695
1696 bool user_record_equal(UserRecord *a, UserRecord *b) {
1697 assert(a);
1698 assert(b);
1699
1700 /* We assume that when a record is modified its JSON data is updated at the same time, hence it's
1701 * sufficient to compare the JSON data. */
1702
1703 return json_variant_equal(a->json, b->json);
1704 }
1705
1706 bool user_record_compatible(UserRecord *a, UserRecord *b) {
1707 assert(a);
1708 assert(b);
1709
1710 /* If either lacks a the regular section, we can't really decide, let's hence say they are
1711 * incompatible. */
1712 if (!(a->mask & b->mask & USER_RECORD_REGULAR))
1713 return false;
1714
1715 return streq_ptr(a->user_name, b->user_name) &&
1716 streq_ptr(a->realm, b->realm);
1717 }
1718
1719 int user_record_compare_last_change(UserRecord *a, UserRecord *b) {
1720 assert(a);
1721 assert(b);
1722
1723 if (a->last_change_usec == b->last_change_usec)
1724 return 0;
1725
1726 /* Always consider a record with a timestamp newer than one without */
1727 if (a->last_change_usec == UINT64_MAX)
1728 return -1;
1729 if (b->last_change_usec == UINT64_MAX)
1730 return 1;
1731
1732 return CMP(a->last_change_usec, b->last_change_usec);
1733 }
1734
1735 int user_record_clone(UserRecord *h, UserRecordLoadFlags flags, UserRecord **ret) {
1736 _cleanup_(user_record_unrefp) UserRecord *c = NULL;
1737 int r;
1738
1739 assert(h);
1740 assert(ret);
1741
1742 c = user_record_new();
1743 if (!c)
1744 return -ENOMEM;
1745
1746 r = user_record_load(c, h->json, flags);
1747 if (r < 0)
1748 return r;
1749
1750 *ret = TAKE_PTR(c);
1751 return 0;
1752 }
1753
1754 int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask) {
1755 _cleanup_(user_record_unrefp) UserRecord *x = NULL, *y = NULL;
1756 int r;
1757
1758 assert(a);
1759 assert(b);
1760
1761 /* Compares the two records, but ignores anything not listed in the specified mask */
1762
1763 if ((a->mask & ~mask) != 0) {
1764 r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &x);
1765 if (r < 0)
1766 return r;
1767
1768 a = x;
1769 }
1770
1771 if ((b->mask & ~mask) != 0) {
1772 r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &y);
1773 if (r < 0)
1774 return r;
1775
1776 b = y;
1777 }
1778
1779 return user_record_equal(a, b);
1780 }
1781
1782 int user_record_test_blocked(UserRecord *h) {
1783 usec_t n;
1784
1785 /* Checks whether access to the specified user shall be allowed at the moment. Returns:
1786 *
1787 * -ESTALE: Record is from the future
1788 * -ENOLCK: Record is blocked
1789 * -EL2HLT: Record is not valid yet
1790 * -EL3HLT: Record is not valid anymore
1791 *
1792 */
1793
1794 assert(h);
1795
1796 n = now(CLOCK_REALTIME);
1797 if (h->last_change_usec != UINT64_MAX &&
1798 h->last_change_usec > n) /* Don't allow log ins when the record is from the future */
1799 return -ESTALE;
1800
1801 if (h->locked > 0)
1802 return -ENOLCK;
1803
1804 if (h->not_before_usec != UINT64_MAX && n < h->not_before_usec)
1805 return -EL2HLT;
1806 if (h->not_after_usec != UINT64_MAX && n > h->not_after_usec)
1807 return -EL3HLT;
1808
1809 return 0;
1810 }
1811
1812 int user_record_test_password_change_required(UserRecord *h) {
1813 bool change_permitted;
1814 usec_t n;
1815
1816 assert(h);
1817
1818 /* Checks whether the user must change the password when logging in
1819
1820 -EKEYREVOKED: Change password now because admin said so
1821 -EOWNERDEAD: Change password now because it expired
1822 -EKEYREJECTED: Password is expired, no changing is allowed
1823 -EKEYEXPIRED: Password is about to expire, warn user
1824 -ENETDOWN: Record has expiration info but no password change timestamp
1825 -EROFS: No password change required nor permitted
1826 0: No password change required, but permitted
1827 */
1828
1829 /* If a password change request has been set explicitly, it overrides everything */
1830 if (h->password_change_now > 0)
1831 return -EKEYREVOKED;
1832
1833 n = now(CLOCK_REALTIME);
1834
1835 /* Then, let's check if password changing is currently allowed at all */
1836 if (h->password_change_min_usec != UINT64_MAX) {
1837
1838 /* Expiry configured but no password change timestamp known? */
1839 if (h->last_password_change_usec == UINT64_MAX)
1840 return -ENETDOWN;
1841
1842 if (h->password_change_min_usec >= UINT64_MAX - h->last_password_change_usec)
1843 change_permitted = false;
1844 else
1845 change_permitted = n >= h->last_password_change_usec + h->password_change_min_usec;
1846
1847 } else
1848 change_permitted = true;
1849
1850 /* Let's check whether the password has expired. */
1851 if (!(h->password_change_max_usec == UINT64_MAX ||
1852 h->password_change_max_usec >= UINT64_MAX - h->last_password_change_usec)) {
1853
1854 uint64_t change_before;
1855
1856 /* Expiry configured but no password change timestamp known? */
1857 if (h->last_password_change_usec == UINT64_MAX)
1858 return -ENETDOWN;
1859
1860 /* Password is in inactive phase? */
1861 if (h->password_change_inactive_usec != UINT64_MAX &&
1862 h->password_change_inactive_usec < UINT64_MAX - h->password_change_max_usec) {
1863 usec_t added;
1864
1865 added = h->password_change_inactive_usec + h->password_change_max_usec;
1866 if (added < UINT64_MAX - h->last_password_change_usec &&
1867 n >= h->last_password_change_usec + added)
1868 return -EKEYREJECTED;
1869 }
1870
1871 /* Password needs to be changed now? */
1872 change_before = h->last_password_change_usec + h->password_change_max_usec;
1873 if (n >= change_before)
1874 return change_permitted ? -EOWNERDEAD : -EKEYREJECTED;
1875
1876 /* Warn user? */
1877 if (h->password_change_warn_usec != UINT64_MAX &&
1878 (change_before < h->password_change_warn_usec ||
1879 n >= change_before - h->password_change_warn_usec))
1880 return change_permitted ? -EKEYEXPIRED : -EROFS;
1881 }
1882
1883 /* No password changing necessary */
1884 return change_permitted ? 0 : -EROFS;
1885 }
1886
1887 static const char* const user_storage_table[_USER_STORAGE_MAX] = {
1888 [USER_CLASSIC] = "classic",
1889 [USER_LUKS] = "luks",
1890 [USER_DIRECTORY] = "directory",
1891 [USER_SUBVOLUME] = "subvolume",
1892 [USER_FSCRYPT] = "fscrypt",
1893 [USER_CIFS] = "cifs",
1894 };
1895
1896 DEFINE_STRING_TABLE_LOOKUP(user_storage, UserStorage);
1897
1898 static const char* const user_disposition_table[_USER_DISPOSITION_MAX] = {
1899 [USER_INTRINSIC] = "intrinsic",
1900 [USER_SYSTEM] = "system",
1901 [USER_DYNAMIC] = "dynamic",
1902 [USER_REGULAR] = "regular",
1903 [USER_CONTAINER] = "container",
1904 [USER_RESERVED] = "reserved",
1905 };
1906
1907 DEFINE_STRING_TABLE_LOOKUP(user_disposition, UserDisposition);