summaryrefslogtreecommitdiffstats
path: root/src/cryptenroll/cryptenroll-list.c
blob: ffc1067d2db547c2f478bcc86fe1e8775088e2e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* SPDX-License-Identifier: LGPL-2.1-or-later */

#include "sd-json.h"

#include "cryptenroll-list.h"
#include "cryptenroll.h"
#include "format-table.h"
#include "json-util.h"
#include "parse-util.h"

struct keyslot_metadata {
        int slot;
        const char *type;
};

int list_enrolled(struct crypt_device *cd) {
        _cleanup_free_ struct keyslot_metadata *keyslot_metadata = NULL;
        _cleanup_(table_unrefp) Table *t = NULL;
        size_t n_keyslot_metadata = 0;
        int slot_max, r;
        TableCell *cell;

        assert(cd);

        /* First step, find out all currently used slots */
        assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0);
        for (int slot = 0; slot < slot_max; slot++) {
                crypt_keyslot_info status;

                status = crypt_keyslot_status(cd, slot);
                if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST))
                        continue;

                if (!GREEDY_REALLOC(keyslot_metadata, n_keyslot_metadata+1))
                        return log_oom();

                keyslot_metadata[n_keyslot_metadata++] = (struct keyslot_metadata) {
                        .slot = slot,
                };
        }

        /* Second step, enumerate through all tokens, and update the slot table, indicating what kind of
         * token they are assigned to */
        for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
                const char *type;
                sd_json_variant *w, *z;
                EnrollType et;

                r = cryptsetup_get_token_as_json(cd, token, NULL, &v);
                if (IN_SET(r, -ENOENT, -EINVAL))
                        continue;
                if (r < 0) {
                        log_warning_errno(r, "Failed to read JSON token data off disk, ignoring: %m");
                        continue;
                }

                w = sd_json_variant_by_key(v, "type");
                if (!w || !sd_json_variant_is_string(w)) {
                        log_warning("Token JSON data lacks type field, ignoring.");
                        continue;
                }

                et = luks2_token_type_from_string(sd_json_variant_string(w));
                if (et < 0)
                        type = "other";
                else
                        type = enroll_type_to_string(et);

                w = sd_json_variant_by_key(v, "keyslots");
                if (!w || !sd_json_variant_is_array(w)) {
                        log_warning("Token JSON data lacks keyslots field, ignoring.");
                        continue;
                }

                JSON_VARIANT_ARRAY_FOREACH(z, w) {
                        unsigned u;

                        if (!sd_json_variant_is_string(z)) {
                                log_warning("Token JSON data's keyslot field is not an array of strings, ignoring.");
                                continue;
                        }

                        r = safe_atou(sd_json_variant_string(z), &u);
                        if (r < 0) {
                                log_warning_errno(r, "Token JSON data's keyslot field is not an integer formatted as string, ignoring.");
                                continue;
                        }

                        for (size_t i = 0; i < n_keyslot_metadata; i++) {
                                if ((unsigned) keyslot_metadata[i].slot != u)
                                        continue;

                                if (keyslot_metadata[i].type) /* Slot claimed multiple times? */
                                        keyslot_metadata[i].type = POINTER_MAX;
                                else
                                        keyslot_metadata[i].type = type;
                        }
                }
        }

        /* Finally, create a table out of it all */
        t = table_new("slot", "type");
        if (!t)
                return log_oom();

        assert_se(cell = table_get_cell(t, 0, 0));
        (void) table_set_align_percent(t, cell, 100);

        for (size_t i = 0; i < n_keyslot_metadata; i++) {
                r = table_add_many(
                                t,
                                TABLE_INT, keyslot_metadata[i].slot,
                                TABLE_STRING, keyslot_metadata[i].type == POINTER_MAX ? "conflict" :
                                              keyslot_metadata[i].type ?: "password");
                if (r < 0)
                        return table_log_add_error(r);
        }

        if (table_isempty(t)) {
                log_info("No slots found.");
                return 0;
        }

        r = table_print(t, stdout);
        if (r < 0)
                return log_error_errno(r, "Failed to show slot table: %m");

        return 0;
}