]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/user-record.c
Merge pull request #15697 from OhNoMoreGit/fix-path-units
[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 int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
1063 const char *suffix;
1064 char *z;
1065
1066 assert(storage >= 0);
1067 assert(user_name_and_realm);
1068 assert(ret);
1069
1070 if (storage == USER_LUKS)
1071 suffix = ".home";
1072 else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
1073 suffix = ".homedir";
1074 else {
1075 *ret = NULL;
1076 return 0;
1077 }
1078
1079 z = strjoin("/home/", user_name_and_realm, suffix);
1080 if (!z)
1081 return -ENOMEM;
1082
1083 *ret = z;
1084 return 1;
1085 }
1086
1087 static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
1088 int r;
1089
1090 assert(h);
1091
1092 if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
1093 return 0;
1094
1095 assert(h->user_name);
1096
1097 if (!h->user_name_and_realm_auto && h->realm) {
1098 h->user_name_and_realm_auto = strjoin(h->user_name, "@", h->realm);
1099 if (!h->user_name_and_realm_auto)
1100 return json_log_oom(h->json, json_flags);
1101 }
1102
1103 /* Let's add in the following automatisms only for regular users, they don't make sense for any others */
1104 if (user_record_disposition(h) != USER_REGULAR)
1105 return 0;
1106
1107 if (!h->home_directory && !h->home_directory_auto) {
1108 h->home_directory_auto = path_join("/home/", h->user_name);
1109 if (!h->home_directory_auto)
1110 return json_log_oom(h->json, json_flags);
1111 }
1112
1113 if (!h->image_path && !h->image_path_auto) {
1114 r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto);
1115 if (r < 0)
1116 return json_log(h->json, json_flags, r, "Failed to determine default image path: %m");
1117 }
1118
1119 return 0;
1120 }
1121
1122 int user_group_record_mangle(
1123 JsonVariant *v,
1124 UserRecordLoadFlags load_flags,
1125 JsonVariant **ret_variant,
1126 UserRecordMask *ret_mask) {
1127
1128 static const struct {
1129 UserRecordMask mask;
1130 const char *name;
1131 } mask_field[] = {
1132 { USER_RECORD_PRIVILEGED, "privileged" },
1133 { USER_RECORD_SECRET, "secret" },
1134 { USER_RECORD_BINDING, "binding" },
1135 { USER_RECORD_PER_MACHINE, "perMachine" },
1136 { USER_RECORD_STATUS, "status" },
1137 { USER_RECORD_SIGNATURE, "signature" },
1138 };
1139
1140 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1141 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
1142 JsonVariant *array[ELEMENTSOF(mask_field) * 2];
1143 size_t n_retain = 0, i;
1144 UserRecordMask m = 0;
1145 int r;
1146
1147 assert((load_flags & _USER_RECORD_MASK_MAX) == 0); /* detect mistakes when accidentally passing
1148 * UserRecordMask bit masks as UserRecordLoadFlags
1149 * value */
1150
1151 assert(v);
1152 assert(ret_variant);
1153 assert(ret_mask);
1154
1155 /* Note that this function is shared with the group record parser, hence we try to be generic in our
1156 * log message wording here, to cover both cases. */
1157
1158 if (!json_variant_is_object(v))
1159 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is not a JSON object, refusing.");
1160
1161 if (USER_RECORD_ALLOW_MASK(load_flags) == 0) /* allow nothing? */
1162 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Nothing allowed in record, refusing.");
1163
1164 if (USER_RECORD_STRIP_MASK(load_flags) == _USER_RECORD_MASK_MAX) /* strip everything? */
1165 return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing.");
1166
1167 /* Check if we have the special sections and if they match our flags set */
1168 for (i = 0; i < ELEMENTSOF(mask_field); i++) {
1169 JsonVariant *e, *k;
1170
1171 if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) {
1172 if (!w)
1173 w = json_variant_ref(v);
1174
1175 r = json_variant_filter(&w, STRV_MAKE(mask_field[i].name));
1176 if (r < 0)
1177 return json_log(w, json_flags, r, "Failed to remove field from variant: %m");
1178
1179 continue;
1180 }
1181
1182 e = json_variant_by_key_full(v, mask_field[i].name, &k);
1183 if (e) {
1184 if (!FLAGS_SET(USER_RECORD_ALLOW_MASK(load_flags), mask_field[i].mask))
1185 return json_log(e, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", mask_field[i].name);
1186
1187 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1188 array[n_retain++] = k;
1189 array[n_retain++] = e;
1190 }
1191
1192 m |= mask_field[i].mask;
1193 } else {
1194 if (FLAGS_SET(USER_RECORD_REQUIRE_MASK(load_flags), mask_field[i].mask))
1195 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks '%s' field, which is required.", mask_field[i].name);
1196 }
1197 }
1198
1199 if (FLAGS_SET(load_flags, USER_RECORD_STRIP_REGULAR)) {
1200 /* If we are supposed to strip regular items, then let's instead just allocate a new object
1201 * with just the stuff we need. */
1202
1203 w = json_variant_unref(w);
1204 r = json_variant_new_object(&w, array, n_retain);
1205 if (r < 0)
1206 return json_log(v, json_flags, r, "Failed to allocate new object: %m");
1207 } else {
1208 /* And now check if there's anything else in the record */
1209 for (i = 0; i < json_variant_elements(v); i += 2) {
1210 const char *f;
1211 bool special = false;
1212 size_t j;
1213
1214 assert_se(f = json_variant_string(json_variant_by_index(v, i)));
1215
1216 for (j = 0; j < ELEMENTSOF(mask_field); j++)
1217 if (streq(f, mask_field[j].name)) { /* already covered in the loop above */
1218 special = true;
1219 continue;
1220 }
1221
1222 if (!special) {
1223 if ((load_flags & (USER_RECORD_ALLOW_REGULAR|USER_RECORD_REQUIRE_REGULAR)) == 0)
1224 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record contains '%s' field, which is not allowed.", f);
1225
1226 m |= USER_RECORD_REGULAR;
1227 break;
1228 }
1229 }
1230 }
1231
1232 if (FLAGS_SET(load_flags, USER_RECORD_REQUIRE_REGULAR) && !FLAGS_SET(m, USER_RECORD_REGULAR))
1233 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks basic identity fields, which are required.");
1234
1235 if (m == 0)
1236 return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record is empty.");
1237
1238 if (w)
1239 *ret_variant = TAKE_PTR(w);
1240 else
1241 *ret_variant = json_variant_ref(v);
1242
1243 *ret_mask = m;
1244 return 0;
1245 }
1246
1247 int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
1248
1249 static const JsonDispatch user_dispatch_table[] = {
1250 { "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
1251 { "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
1252 { "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
1253 { "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
1254 { "iconName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, icon_name), JSON_SAFE },
1255 { "location", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, location), 0 },
1256 { "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(UserRecord, disposition), 0 },
1257 { "lastChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_change_usec), 0 },
1258 { "lastPasswordChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, last_password_change_usec), 0 },
1259 { "shell", JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
1260 { "umask", JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
1261 { "environment", JSON_VARIANT_ARRAY, json_dispatch_environment, offsetof(UserRecord, environment), 0 },
1262 { "timeZone", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, time_zone), JSON_SAFE },
1263 { "preferredLanguage", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, preferred_language), JSON_SAFE },
1264 { "niceLevel", _JSON_VARIANT_TYPE_INVALID, json_dispatch_nice, offsetof(UserRecord, nice_level), 0 },
1265 { "resourceLimits", _JSON_VARIANT_TYPE_INVALID, json_dispatch_rlimits, offsetof(UserRecord, rlimits), 0 },
1266 { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 },
1267 { "notBeforeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 },
1268 { "notAfterUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 },
1269 { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 },
1270 { "diskSize", JSON_VARIANT_UNSIGNED, json_dispatch_disk_size, offsetof(UserRecord, disk_size), 0 },
1271 { "diskSizeRelative", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
1272 { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 },
1273 { "accessMode", JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
1274 { "tasksMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
1275 { "memoryHigh", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
1276 { "memoryMax", JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
1277 { "cpuWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, cpu_weight), 0 },
1278 { "ioWeight", JSON_VARIANT_UNSIGNED, json_dispatch_weight, offsetof(UserRecord, io_weight), 0 },
1279 { "mountNoDevices", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nodev), 0 },
1280 { "mountNoSuid", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, nosuid), 0 },
1281 { "mountNoExecute", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(UserRecord, noexec), 0 },
1282 { "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
1283 { "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
1284 { "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
1285 { "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
1286 { "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
1287 { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
1288 { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
1289 { "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
1290 { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
1291 { "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
1292 { "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
1293 { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
1294 { "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0 },
1295 { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0 },
1296 { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
1297 { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
1298 { "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
1299 { "luksPbkdfHashAlgorithm", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_hash_algorithm), JSON_SAFE },
1300 { "luksPbkdfType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_pbkdf_type), JSON_SAFE },
1301 { "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
1302 { "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
1303 { "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
1304 { "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, service), JSON_SAFE },
1305 { "rateLimitIntervalUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_interval_usec), 0 },
1306 { "rateLimitBurst", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, ratelimit_burst), 0 },
1307 { "enforcePasswordPolicy", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, enforce_password_policy), 0 },
1308 { "autoLogin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, auto_login), 0 },
1309 { "stopDelayUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, stop_delay_usec), 0 },
1310 { "killProcesses", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, kill_processes), 0 },
1311 { "passwordChangeMinUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_min_usec), 0 },
1312 { "passwordChangeMaxUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_max_usec), 0 },
1313 { "passwordChangeWarnUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_warn_usec), 0 },
1314 { "passwordChangeInactiveUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, password_change_inactive_usec), 0 },
1315 { "passwordChangeNow", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, password_change_now), 0 },
1316 { "pkcs11TokenUri", JSON_VARIANT_ARRAY, dispatch_pkcs11_uri_array, offsetof(UserRecord, pkcs11_token_uri), 0 },
1317
1318 { "secret", JSON_VARIANT_OBJECT, dispatch_secret, 0, 0 },
1319 { "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
1320
1321 /* Ignore the perMachine, binding, status stuff here, and process it later, so that it overrides whatever is set above */
1322 { "perMachine", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1323 { "binding", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1324 { "status", JSON_VARIANT_OBJECT, NULL, 0, 0 },
1325
1326 /* Ignore 'signature', we check it with explicit accessors instead */
1327 { "signature", JSON_VARIANT_ARRAY, NULL, 0, 0 },
1328 {},
1329 };
1330
1331 JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags);
1332 int r;
1333
1334 assert(h);
1335 assert(!h->json);
1336
1337 /* Note that this call will leave a half-initialized record around on failure! */
1338
1339 r = user_group_record_mangle(v, load_flags, &h->json, &h->mask);
1340 if (r < 0)
1341 return r;
1342
1343 r = json_dispatch(h->json, user_dispatch_table, NULL, json_flags, h);
1344 if (r < 0)
1345 return r;
1346
1347 /* During the parsing operation above we ignored the 'perMachine', 'binding' and 'status' fields,
1348 * since we want them to override the global options. Let's process them now. */
1349
1350 r = dispatch_per_machine("perMachine", json_variant_by_key(h->json, "perMachine"), json_flags, h);
1351 if (r < 0)
1352 return r;
1353
1354 r = dispatch_binding("binding", json_variant_by_key(h->json, "binding"), json_flags, h);
1355 if (r < 0)
1356 return r;
1357
1358 r = dispatch_status("status", json_variant_by_key(h->json, "status"), json_flags, h);
1359 if (r < 0)
1360 return r;
1361
1362 if (FLAGS_SET(h->mask, USER_RECORD_REGULAR) && !h->user_name)
1363 return json_log(h->json, json_flags, SYNTHETIC_ERRNO(EINVAL), "User name field missing, refusing.");
1364
1365 r = user_record_augment(h, json_flags);
1366 if (r < 0)
1367 return r;
1368
1369 return 0;
1370 }
1371
1372 int user_record_build(UserRecord **ret, ...) {
1373 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1374 _cleanup_(user_record_unrefp) UserRecord *u = NULL;
1375 va_list ap;
1376 int r;
1377
1378 assert(ret);
1379
1380 va_start(ap, ret);
1381 r = json_buildv(&v, ap);
1382 va_end(ap);
1383
1384 if (r < 0)
1385 return r;
1386
1387 u = user_record_new();
1388 if (!u)
1389 return -ENOMEM;
1390
1391 r = user_record_load(u, v, USER_RECORD_LOAD_FULL);
1392 if (r < 0)
1393 return r;
1394
1395 *ret = TAKE_PTR(u);
1396 return 0;
1397 }
1398
1399 const char *user_record_user_name_and_realm(UserRecord *h) {
1400 assert(h);
1401
1402 /* Return the pre-initialized joined string if it is defined */
1403 if (h->user_name_and_realm_auto)
1404 return h->user_name_and_realm_auto;
1405
1406 /* If it's not defined then we cannot have a realm */
1407 assert(!h->realm);
1408 return h->user_name;
1409 }
1410
1411 UserStorage user_record_storage(UserRecord *h) {
1412 assert(h);
1413
1414 if (h->storage >= 0)
1415 return h->storage;
1416
1417 return USER_CLASSIC;
1418 }
1419
1420 const char *user_record_file_system_type(UserRecord *h) {
1421 assert(h);
1422
1423 return h->file_system_type ?: "ext4";
1424 }
1425
1426 const char *user_record_skeleton_directory(UserRecord *h) {
1427 assert(h);
1428
1429 return h->skeleton_directory ?: "/etc/skel";
1430 }
1431
1432 mode_t user_record_access_mode(UserRecord *h) {
1433 assert(h);
1434
1435 return h->access_mode != (mode_t) -1 ? h->access_mode : 0700;
1436 }
1437
1438 const char* user_record_home_directory(UserRecord *h) {
1439 assert(h);
1440
1441 if (h->home_directory)
1442 return h->home_directory;
1443 if (h->home_directory_auto)
1444 return h->home_directory_auto;
1445
1446 /* The root user is special, hence be special about it */
1447 if (streq_ptr(h->user_name, "root"))
1448 return "/root";
1449
1450 return "/";
1451 }
1452
1453 const char *user_record_image_path(UserRecord *h) {
1454 assert(h);
1455
1456 if (h->image_path)
1457 return h->image_path;
1458 if (h->image_path_auto)
1459 return h->image_path_auto;
1460
1461 return IN_SET(user_record_storage(h), USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT) ? user_record_home_directory(h) : NULL;
1462 }
1463
1464 const char *user_record_cifs_user_name(UserRecord *h) {
1465 assert(h);
1466
1467 return h->cifs_user_name ?: h->user_name;
1468 }
1469
1470 unsigned long user_record_mount_flags(UserRecord *h) {
1471 assert(h);
1472
1473 return (h->nosuid ? MS_NOSUID : 0) |
1474 (h->noexec ? MS_NOEXEC : 0) |
1475 (h->nodev ? MS_NODEV : 0);
1476 }
1477
1478 const char *user_record_shell(UserRecord *h) {
1479 assert(h);
1480
1481 if (h->shell)
1482 return h->shell;
1483
1484 if (streq_ptr(h->user_name, "root"))
1485 return "/bin/sh";
1486
1487 if (user_record_disposition(h) == USER_REGULAR)
1488 return "/bin/bash";
1489
1490 return NOLOGIN;
1491 }
1492
1493 const char *user_record_real_name(UserRecord *h) {
1494 assert(h);
1495
1496 return h->real_name ?: h->user_name;
1497 }
1498
1499 bool user_record_luks_discard(UserRecord *h) {
1500 const char *ip;
1501
1502 assert(h);
1503
1504 if (h->luks_discard >= 0)
1505 return h->luks_discard;
1506
1507 ip = user_record_image_path(h);
1508 if (!ip)
1509 return false;
1510
1511 /* Use discard by default if we are referring to a real block device, but not when operating on a
1512 * loopback device. We want to optimize for SSD and flash storage after all, but we should be careful
1513 * when storing stuff on top of regular file systems in loopback files as doing discard then would
1514 * mean thin provisioning and we should not do that willy-nilly since it means we'll risk EIO later
1515 * on should the disk space to back our file systems not be available. */
1516
1517 return path_startswith(ip, "/dev/");
1518 }
1519
1520 bool user_record_luks_offline_discard(UserRecord *h) {
1521 const char *ip;
1522
1523 assert(h);
1524
1525 if (h->luks_offline_discard >= 0)
1526 return h->luks_offline_discard;
1527
1528 /* Discard while we are logged out should generally be a good idea, except when operating directly on
1529 * physical media, where we should just bind it to the online discard mode. */
1530
1531 ip = user_record_image_path(h);
1532 if (!ip)
1533 return false;
1534
1535 if (path_startswith(ip, "/dev/"))
1536 return user_record_luks_discard(h);
1537
1538 return true;
1539 }
1540
1541 const char *user_record_luks_cipher(UserRecord *h) {
1542 assert(h);
1543
1544 return h->luks_cipher ?: "aes";
1545 }
1546
1547 const char *user_record_luks_cipher_mode(UserRecord *h) {
1548 assert(h);
1549
1550 return h->luks_cipher_mode ?: "xts-plain64";
1551 }
1552
1553 uint64_t user_record_luks_volume_key_size(UserRecord *h) {
1554 assert(h);
1555
1556 /* We return a value here that can be cast without loss into size_t which is what libcrypsetup expects */
1557
1558 if (h->luks_volume_key_size == UINT64_MAX)
1559 return 256 / 8;
1560
1561 return MIN(h->luks_volume_key_size, SIZE_MAX);
1562 }
1563
1564 const char* user_record_luks_pbkdf_type(UserRecord *h) {
1565 assert(h);
1566
1567 return h->luks_pbkdf_type ?: "argon2i";
1568 }
1569
1570 uint64_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h) {
1571 assert(h);
1572
1573 /* Returns a value with ms granularity, since that's what libcryptsetup expects */
1574
1575 if (h->luks_pbkdf_time_cost_usec == UINT64_MAX)
1576 return 500 * USEC_PER_MSEC; /* We default to 500ms, in contrast to libcryptsetup's 2s, which is just awfully slow on every login */
1577
1578 return MIN(DIV_ROUND_UP(h->luks_pbkdf_time_cost_usec, USEC_PER_MSEC), UINT32_MAX) * USEC_PER_MSEC;
1579 }
1580
1581 uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h) {
1582 assert(h);
1583
1584 /* Returns a value with kb granularity, since that's what libcryptsetup expects */
1585
1586 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1587 return 64*1024*1024; /* We default to 64M, since this should work on smaller systems too */
1588
1589 return MIN(DIV_ROUND_UP(h->luks_pbkdf_memory_cost, 1024), UINT32_MAX) * 1024;
1590 }
1591
1592 uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) {
1593 assert(h);
1594
1595 if (h->luks_pbkdf_memory_cost == UINT64_MAX)
1596 return 1; /* We default to 1, since this should work on smaller systems too */
1597
1598 return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX);
1599 }
1600
1601 const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h) {
1602 assert(h);
1603
1604 return h->luks_pbkdf_hash_algorithm ?: "sha512";
1605 }
1606
1607 gid_t user_record_gid(UserRecord *h) {
1608 assert(h);
1609
1610 if (gid_is_valid(h->gid))
1611 return h->gid;
1612
1613 return (gid_t) h->uid;
1614 }
1615
1616 UserDisposition user_record_disposition(UserRecord *h) {
1617 assert(h);
1618
1619 if (h->disposition >= 0)
1620 return h->disposition;
1621
1622 /* If not declared, derive from UID */
1623
1624 if (!uid_is_valid(h->uid))
1625 return _USER_DISPOSITION_INVALID;
1626
1627 if (h->uid == 0 || h->uid == UID_NOBODY)
1628 return USER_INTRINSIC;
1629
1630 if (uid_is_system(h->uid))
1631 return USER_SYSTEM;
1632
1633 if (uid_is_dynamic(h->uid))
1634 return USER_DYNAMIC;
1635
1636 if (uid_is_container(h->uid))
1637 return USER_CONTAINER;
1638
1639 if (h->uid > INT32_MAX)
1640 return USER_RESERVED;
1641
1642 return USER_REGULAR;
1643 }
1644
1645 int user_record_removable(UserRecord *h) {
1646 UserStorage storage;
1647 assert(h);
1648
1649 if (h->removable >= 0)
1650 return h->removable;
1651
1652 /* Refuse to decide for classic records */
1653 storage = user_record_storage(h);
1654 if (h->storage < 0 || h->storage == USER_CLASSIC)
1655 return -1;
1656
1657 /* For now consider only LUKS home directories with a reference by path as removable */
1658 return storage == USER_LUKS && path_startswith(user_record_image_path(h), "/dev/");
1659 }
1660
1661 uint64_t user_record_ratelimit_interval_usec(UserRecord *h) {
1662 assert(h);
1663
1664 if (h->ratelimit_interval_usec == UINT64_MAX)
1665 return DEFAULT_RATELIMIT_INTERVAL_USEC;
1666
1667 return h->ratelimit_interval_usec;
1668 }
1669
1670 uint64_t user_record_ratelimit_burst(UserRecord *h) {
1671 assert(h);
1672
1673 if (h->ratelimit_burst == UINT64_MAX)
1674 return DEFAULT_RATELIMIT_BURST;
1675
1676 return h->ratelimit_burst;
1677 }
1678
1679 bool user_record_can_authenticate(UserRecord *h) {
1680 assert(h);
1681
1682 /* Returns true if there's some form of property configured that the user can authenticate against */
1683
1684 if (h->n_pkcs11_encrypted_key > 0)
1685 return true;
1686
1687 return !strv_isempty(h->hashed_password);
1688 }
1689
1690 uint64_t user_record_ratelimit_next_try(UserRecord *h) {
1691 assert(h);
1692
1693 /* Calculates when the it's possible to login next. Returns:
1694 *
1695 * UINT64_MAX → Nothing known
1696 * 0 → Right away
1697 * Any other → Next time in CLOCK_REALTIME in usec (which could be in the past)
1698 */
1699
1700 if (h->ratelimit_begin_usec == UINT64_MAX ||
1701 h->ratelimit_count == UINT64_MAX)
1702 return UINT64_MAX;
1703
1704 if (h->ratelimit_count < user_record_ratelimit_burst(h))
1705 return 0;
1706
1707 return usec_add(h->ratelimit_begin_usec, user_record_ratelimit_interval_usec(h));
1708 }
1709
1710 bool user_record_equal(UserRecord *a, UserRecord *b) {
1711 assert(a);
1712 assert(b);
1713
1714 /* We assume that when a record is modified its JSON data is updated at the same time, hence it's
1715 * sufficient to compare the JSON data. */
1716
1717 return json_variant_equal(a->json, b->json);
1718 }
1719
1720 bool user_record_compatible(UserRecord *a, UserRecord *b) {
1721 assert(a);
1722 assert(b);
1723
1724 /* If either lacks a the regular section, we can't really decide, let's hence say they are
1725 * incompatible. */
1726 if (!(a->mask & b->mask & USER_RECORD_REGULAR))
1727 return false;
1728
1729 return streq_ptr(a->user_name, b->user_name) &&
1730 streq_ptr(a->realm, b->realm);
1731 }
1732
1733 int user_record_compare_last_change(UserRecord *a, UserRecord *b) {
1734 assert(a);
1735 assert(b);
1736
1737 if (a->last_change_usec == b->last_change_usec)
1738 return 0;
1739
1740 /* Always consider a record with a timestamp newer than one without */
1741 if (a->last_change_usec == UINT64_MAX)
1742 return -1;
1743 if (b->last_change_usec == UINT64_MAX)
1744 return 1;
1745
1746 return CMP(a->last_change_usec, b->last_change_usec);
1747 }
1748
1749 int user_record_clone(UserRecord *h, UserRecordLoadFlags flags, UserRecord **ret) {
1750 _cleanup_(user_record_unrefp) UserRecord *c = NULL;
1751 int r;
1752
1753 assert(h);
1754 assert(ret);
1755
1756 c = user_record_new();
1757 if (!c)
1758 return -ENOMEM;
1759
1760 r = user_record_load(c, h->json, flags);
1761 if (r < 0)
1762 return r;
1763
1764 *ret = TAKE_PTR(c);
1765 return 0;
1766 }
1767
1768 int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask) {
1769 _cleanup_(user_record_unrefp) UserRecord *x = NULL, *y = NULL;
1770 int r;
1771
1772 assert(a);
1773 assert(b);
1774
1775 /* Compares the two records, but ignores anything not listed in the specified mask */
1776
1777 if ((a->mask & ~mask) != 0) {
1778 r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &x);
1779 if (r < 0)
1780 return r;
1781
1782 a = x;
1783 }
1784
1785 if ((b->mask & ~mask) != 0) {
1786 r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &y);
1787 if (r < 0)
1788 return r;
1789
1790 b = y;
1791 }
1792
1793 return user_record_equal(a, b);
1794 }
1795
1796 int user_record_test_blocked(UserRecord *h) {
1797 usec_t n;
1798
1799 /* Checks whether access to the specified user shall be allowed at the moment. Returns:
1800 *
1801 * -ESTALE: Record is from the future
1802 * -ENOLCK: Record is blocked
1803 * -EL2HLT: Record is not valid yet
1804 * -EL3HLT: Record is not valid anymore
1805 *
1806 */
1807
1808 assert(h);
1809
1810 n = now(CLOCK_REALTIME);
1811 if (h->last_change_usec != UINT64_MAX &&
1812 h->last_change_usec > n) /* Don't allow log ins when the record is from the future */
1813 return -ESTALE;
1814
1815 if (h->locked > 0)
1816 return -ENOLCK;
1817
1818 if (h->not_before_usec != UINT64_MAX && n < h->not_before_usec)
1819 return -EL2HLT;
1820 if (h->not_after_usec != UINT64_MAX && n > h->not_after_usec)
1821 return -EL3HLT;
1822
1823 return 0;
1824 }
1825
1826 int user_record_test_password_change_required(UserRecord *h) {
1827 bool change_permitted;
1828 usec_t n;
1829
1830 assert(h);
1831
1832 /* Checks whether the user must change the password when logging in
1833
1834 -EKEYREVOKED: Change password now because admin said so
1835 -EOWNERDEAD: Change password now because it expired
1836 -EKEYREJECTED: Password is expired, no changing is allowed
1837 -EKEYEXPIRED: Password is about to expire, warn user
1838 -ENETDOWN: Record has expiration info but no password change timestamp
1839 -EROFS: No password change required nor permitted
1840 0: No password change required, but permitted
1841 */
1842
1843 /* If a password change request has been set explicitly, it overrides everything */
1844 if (h->password_change_now > 0)
1845 return -EKEYREVOKED;
1846
1847 n = now(CLOCK_REALTIME);
1848
1849 /* Then, let's check if password changing is currently allowed at all */
1850 if (h->password_change_min_usec != UINT64_MAX) {
1851
1852 /* Expiry configured but no password change timestamp known? */
1853 if (h->last_password_change_usec == UINT64_MAX)
1854 return -ENETDOWN;
1855
1856 if (h->password_change_min_usec >= UINT64_MAX - h->last_password_change_usec)
1857 change_permitted = false;
1858 else
1859 change_permitted = n >= h->last_password_change_usec + h->password_change_min_usec;
1860
1861 } else
1862 change_permitted = true;
1863
1864 /* Let's check whether the password has expired. */
1865 if (!(h->password_change_max_usec == UINT64_MAX ||
1866 h->password_change_max_usec >= UINT64_MAX - h->last_password_change_usec)) {
1867
1868 uint64_t change_before;
1869
1870 /* Expiry configured but no password change timestamp known? */
1871 if (h->last_password_change_usec == UINT64_MAX)
1872 return -ENETDOWN;
1873
1874 /* Password is in inactive phase? */
1875 if (h->password_change_inactive_usec != UINT64_MAX &&
1876 h->password_change_inactive_usec < UINT64_MAX - h->password_change_max_usec) {
1877 usec_t added;
1878
1879 added = h->password_change_inactive_usec + h->password_change_max_usec;
1880 if (added < UINT64_MAX - h->last_password_change_usec &&
1881 n >= h->last_password_change_usec + added)
1882 return -EKEYREJECTED;
1883 }
1884
1885 /* Password needs to be changed now? */
1886 change_before = h->last_password_change_usec + h->password_change_max_usec;
1887 if (n >= change_before)
1888 return change_permitted ? -EOWNERDEAD : -EKEYREJECTED;
1889
1890 /* Warn user? */
1891 if (h->password_change_warn_usec != UINT64_MAX &&
1892 (change_before < h->password_change_warn_usec ||
1893 n >= change_before - h->password_change_warn_usec))
1894 return change_permitted ? -EKEYEXPIRED : -EROFS;
1895 }
1896
1897 /* No password changing necessary */
1898 return change_permitted ? 0 : -EROFS;
1899 }
1900
1901 static const char* const user_storage_table[_USER_STORAGE_MAX] = {
1902 [USER_CLASSIC] = "classic",
1903 [USER_LUKS] = "luks",
1904 [USER_DIRECTORY] = "directory",
1905 [USER_SUBVOLUME] = "subvolume",
1906 [USER_FSCRYPT] = "fscrypt",
1907 [USER_CIFS] = "cifs",
1908 };
1909
1910 DEFINE_STRING_TABLE_LOOKUP(user_storage, UserStorage);
1911
1912 static const char* const user_disposition_table[_USER_DISPOSITION_MAX] = {
1913 [USER_INTRINSIC] = "intrinsic",
1914 [USER_SYSTEM] = "system",
1915 [USER_DYNAMIC] = "dynamic",
1916 [USER_REGULAR] = "regular",
1917 [USER_CONTAINER] = "container",
1918 [USER_RESERVED] = "reserved",
1919 };
1920
1921 DEFINE_STRING_TABLE_LOOKUP(user_disposition, UserDisposition);