]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
80c41552 | 2 | |
80c41552 | 3 | #include "errno-util.h" |
d8e32c47 | 4 | #include "glyph-util.h" |
80c41552 LP |
5 | #include "homectl-recovery-key.h" |
6 | #include "libcrypt-util.h" | |
80c41552 | 7 | #include "memory-util.h" |
f1b82359 | 8 | #include "qrcode-util.h" |
80c41552 | 9 | #include "random-util.h" |
73d874ba | 10 | #include "recovery-key.h" |
80c41552 LP |
11 | #include "strv.h" |
12 | #include "terminal-util.h" | |
13 | ||
80c41552 LP |
14 | static int add_privileged(JsonVariant **v, const char *hashed) { |
15 | _cleanup_(json_variant_unrefp) JsonVariant *e = NULL, *w = NULL, *l = NULL; | |
16 | int r; | |
17 | ||
18 | assert(v); | |
19 | assert(hashed); | |
20 | ||
21 | r = json_build(&e, JSON_BUILD_OBJECT( | |
0cdf6b14 | 22 | JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("modhex64")), |
80c41552 LP |
23 | JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)))); |
24 | if (r < 0) | |
25 | return log_error_errno(r, "Failed to build recover key JSON object: %m"); | |
26 | ||
27 | json_variant_sensitive(e); | |
28 | ||
29 | w = json_variant_ref(json_variant_by_key(*v, "privileged")); | |
30 | l = json_variant_ref(json_variant_by_key(w, "recoveryKey")); | |
31 | ||
32 | r = json_variant_append_array(&l, e); | |
33 | if (r < 0) | |
34 | return log_error_errno(r, "Failed append recovery key: %m"); | |
35 | ||
36 | r = json_variant_set_field(&w, "recoveryKey", l); | |
37 | if (r < 0) | |
38 | return log_error_errno(r, "Failed to set recovery key array: %m"); | |
39 | ||
40 | r = json_variant_set_field(v, "privileged", w); | |
41 | if (r < 0) | |
42 | return log_error_errno(r, "Failed to update privileged field: %m"); | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
47 | static int add_public(JsonVariant **v) { | |
48 | _cleanup_strv_free_ char **types = NULL; | |
49 | int r; | |
50 | ||
51 | assert(v); | |
52 | ||
53 | r = json_variant_strv(json_variant_by_key(*v, "recoveryKeyType"), &types); | |
54 | if (r < 0) | |
55 | return log_error_errno(r, "Failed to parse recovery key type list: %m"); | |
56 | ||
57 | r = strv_extend(&types, "modhex64"); | |
58 | if (r < 0) | |
59 | return log_oom(); | |
60 | ||
61 | r = json_variant_set_field_strv(v, "recoveryKeyType", types); | |
62 | if (r < 0) | |
63 | return log_error_errno(r, "Failed to update recovery key types: %m"); | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | static int add_secret(JsonVariant **v, const char *password) { | |
69 | _cleanup_(json_variant_unrefp) JsonVariant *w = NULL, *l = NULL; | |
5d2a48da | 70 | _cleanup_strv_free_erase_ char **passwords = NULL; |
80c41552 LP |
71 | int r; |
72 | ||
73 | assert(v); | |
74 | assert(password); | |
75 | ||
76 | w = json_variant_ref(json_variant_by_key(*v, "secret")); | |
77 | l = json_variant_ref(json_variant_by_key(w, "password")); | |
78 | ||
79 | r = json_variant_strv(l, &passwords); | |
80 | if (r < 0) | |
81 | return log_error_errno(r, "Failed to convert password array: %m"); | |
82 | ||
83 | r = strv_extend(&passwords, password); | |
84 | if (r < 0) | |
85 | return log_oom(); | |
86 | ||
87 | r = json_variant_new_array_strv(&l, passwords); | |
88 | if (r < 0) | |
89 | return log_error_errno(r, "Failed to allocate new password array JSON: %m"); | |
90 | ||
91 | json_variant_sensitive(l); | |
92 | ||
93 | r = json_variant_set_field(&w, "password", l); | |
94 | if (r < 0) | |
95 | return log_error_errno(r, "Failed to update password field: %m"); | |
96 | ||
97 | r = json_variant_set_field(v, "secret", w); | |
98 | if (r < 0) | |
99 | return log_error_errno(r, "Failed to update secret object: %m"); | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
80c41552 | 104 | int identity_add_recovery_key(JsonVariant **v) { |
0e98d17e | 105 | _cleanup_(erase_and_freep) char *password = NULL, *hashed = NULL; |
80c41552 LP |
106 | int r; |
107 | ||
108 | assert(v); | |
109 | ||
110 | /* First, let's generate a secret key */ | |
111 | r = make_recovery_key(&password); | |
112 | if (r < 0) | |
73d874ba | 113 | return log_error_errno(r, "Failed to generate recovery key: %m"); |
80c41552 LP |
114 | |
115 | /* Let's UNIX hash it */ | |
0e98d17e | 116 | r = hash_password(password, &hashed); |
80c41552 | 117 | if (r < 0) |
80c41552 LP |
118 | return log_error_errno(errno_or_else(EINVAL), "Failed to UNIX hash secret key: %m"); |
119 | ||
120 | /* Let's now add the "privileged" version of the recovery key */ | |
0e98d17e | 121 | r = add_privileged(v, hashed); |
80c41552 LP |
122 | if (r < 0) |
123 | return r; | |
124 | ||
125 | /* Let's then add the public information about the recovery key */ | |
126 | r = add_public(v); | |
127 | if (r < 0) | |
128 | return r; | |
129 | ||
130 | /* Finally, let's add the new key to the secret part, too */ | |
131 | r = add_secret(v, password); | |
132 | if (r < 0) | |
133 | return r; | |
134 | ||
135 | /* We output the key itself with a trailing newline to stdout and the decoration around it to stderr | |
136 | * instead. */ | |
137 | ||
138 | fflush(stdout); | |
139 | fprintf(stderr, | |
140 | "A secret recovery key has been generated for this account:\n\n" | |
141 | " %s%s%s", | |
142 | emoji_enabled() ? special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY) : "", | |
143 | emoji_enabled() ? " " : "", | |
144 | ansi_highlight()); | |
145 | fflush(stderr); | |
146 | ||
147 | fputs(password, stdout); | |
148 | fflush(stdout); | |
149 | ||
150 | fputs(ansi_normal(), stderr); | |
151 | fflush(stderr); | |
152 | ||
153 | fputc('\n', stdout); | |
154 | fflush(stdout); | |
155 | ||
156 | fputs("\nPlease save this secret recovery key at a secure location. It may be used to\n" | |
157 | "regain access to the account if the other configured access credentials have\n" | |
158 | "been lost or forgotten. The recovery key may be entered in place of a password\n" | |
159 | "whenever authentication is requested.\n", stderr); | |
160 | fflush(stderr); | |
161 | ||
f1b82359 | 162 | (void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password); |
80c41552 LP |
163 | |
164 | return 0; | |
165 | } |