]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptenroll/cryptenroll-list.c
alloc-util: simplify GREEDY_REALLOC() logic by relying on malloc_usable_size()
[thirdparty/systemd.git] / src / cryptenroll / cryptenroll-list.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "cryptenroll-list.h"
4 #include "cryptenroll.h"
5 #include "format-table.h"
6 #include "parse-util.h"
7
8 int list_enrolled(struct crypt_device *cd) {
9
10 struct keyslot_metadata {
11 int slot;
12 const char *type;
13 } *keyslot_metadata = NULL;
14 _cleanup_(table_unrefp) Table *t = NULL;
15 size_t n_keyslot_metadata = 0;
16 int slot_max, r;
17 TableCell *cell;
18
19 assert(cd);
20
21 /* First step, find out all currently used slots */
22 assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0);
23 for (int slot = 0; slot < slot_max; slot++) {
24 crypt_keyslot_info status;
25
26 status = crypt_keyslot_status(cd, slot);
27 if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST))
28 continue;
29
30 if (!GREEDY_REALLOC(keyslot_metadata, n_keyslot_metadata+1))
31 return log_oom();
32
33 keyslot_metadata[n_keyslot_metadata++] = (struct keyslot_metadata) {
34 .slot = slot,
35 };
36 }
37
38 /* Second step, enumerate through all tokens, and update the slot table, indicating what kind of
39 * token they are assigned to */
40 for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
41 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
42 const char *type;
43 JsonVariant *w, *z;
44 EnrollType et;
45
46 r = cryptsetup_get_token_as_json(cd, token, NULL, &v);
47 if (IN_SET(r, -ENOENT, -EINVAL))
48 continue;
49 if (r < 0) {
50 log_warning_errno(r, "Failed to read JSON token data off disk, ignoring: %m");
51 continue;
52 }
53
54 w = json_variant_by_key(v, "type");
55 if (!w || !json_variant_is_string(w)) {
56 log_warning("Token JSON data lacks type field, ignoring.");
57 continue;
58 }
59
60 et = luks2_token_type_from_string(json_variant_string(w));
61 if (et < 0)
62 type = "other";
63 else
64 type = enroll_type_to_string(et);
65
66 w = json_variant_by_key(v, "keyslots");
67 if (!w || !json_variant_is_array(w)) {
68 log_warning("Token JSON data lacks keyslots field, ignoring.");
69 continue;
70 }
71
72 JSON_VARIANT_ARRAY_FOREACH(z, w) {
73 unsigned u;
74
75 if (!json_variant_is_string(z)) {
76 log_warning("Token JSON data's keyslot field is not an array of strings, ignoring.");
77 continue;
78 }
79
80 r = safe_atou(json_variant_string(z), &u);
81 if (r < 0) {
82 log_warning_errno(r, "Token JSON data's keyslot filed is not an integer formatted as string, ignoring.");
83 continue;
84 }
85
86 for (size_t i = 0; i < n_keyslot_metadata; i++) {
87 if ((unsigned) keyslot_metadata[i].slot != u)
88 continue;
89
90 if (keyslot_metadata[i].type) /* Slot claimed multiple times? */
91 keyslot_metadata[i].type = POINTER_MAX;
92 else
93 keyslot_metadata[i].type = type;
94 }
95 }
96 }
97
98 /* Finally, create a table out of it all */
99 t = table_new("slot", "type");
100 if (!t)
101 return log_oom();
102
103 assert_se(cell = table_get_cell(t, 0, 0));
104 (void) table_set_align_percent(t, cell, 100);
105
106 for (size_t i = 0; i < n_keyslot_metadata; i++) {
107 r = table_add_many(
108 t,
109 TABLE_INT, keyslot_metadata[i].slot,
110 TABLE_STRING, keyslot_metadata[i].type == POINTER_MAX ? "conflict" :
111 keyslot_metadata[i].type ?: "password");
112 if (r < 0)
113 return table_log_add_error(r);
114 }
115
116 if (table_get_rows(t) <= 1) {
117 log_info("No slots found.");
118 return 0;
119 }
120
121 r = table_print(t, stdout);
122 if (r < 0)
123 return log_error_errno(r, "Failed to show slot table: %m");
124
125 return 0;
126 }