Deleted Added
full compact
geom_eli.c (162347) geom_eli.c (162353)
1/*-
2 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 162347 2006-09-16 09:26:57Z pjd $");
28__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 162353 2006-09-16 10:43:17Z pjd $");
29
30#include <stdio.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <readpassphrase.h>
36#include <string.h>
37#include <strings.h>
38#include <libgeom.h>
39#include <paths.h>
40#include <errno.h>
41#include <assert.h>
42
43#include <sys/param.h>
44#include <sys/mman.h>
45#include <sys/resource.h>
46#include <opencrypto/cryptodev.h>
47#include <geom/eli/g_eli.h>
48#include <geom/eli/pkcs5v2.h>
49
50#include "core/geom.h"
51#include "misc/subr.h"
52
53
54uint32_t lib_version = G_LIB_VERSION;
55uint32_t version = G_ELI_VERSION;
56
57static char aalgo[] = "none";
58static char ealgo[] = "aes";
59static intmax_t keylen = 0;
60static intmax_t keyno = -1;
61static intmax_t iterations = -1;
62static intmax_t sectorsize = 0;
63static char keyfile[] = "", newkeyfile[] = "";
64
65static void eli_main(struct gctl_req *req, unsigned flags);
66static void eli_init(struct gctl_req *req);
67static void eli_attach(struct gctl_req *req);
29
30#include <stdio.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <readpassphrase.h>
36#include <string.h>
37#include <strings.h>
38#include <libgeom.h>
39#include <paths.h>
40#include <errno.h>
41#include <assert.h>
42
43#include <sys/param.h>
44#include <sys/mman.h>
45#include <sys/resource.h>
46#include <opencrypto/cryptodev.h>
47#include <geom/eli/g_eli.h>
48#include <geom/eli/pkcs5v2.h>
49
50#include "core/geom.h"
51#include "misc/subr.h"
52
53
54uint32_t lib_version = G_LIB_VERSION;
55uint32_t version = G_ELI_VERSION;
56
57static char aalgo[] = "none";
58static char ealgo[] = "aes";
59static intmax_t keylen = 0;
60static intmax_t keyno = -1;
61static intmax_t iterations = -1;
62static intmax_t sectorsize = 0;
63static char keyfile[] = "", newkeyfile[] = "";
64
65static void eli_main(struct gctl_req *req, unsigned flags);
66static void eli_init(struct gctl_req *req);
67static void eli_attach(struct gctl_req *req);
68static void eli_configure(struct gctl_req *req);
68static void eli_setkey(struct gctl_req *req);
69static void eli_delkey(struct gctl_req *req);
70static void eli_kill(struct gctl_req *req);
71static void eli_backup(struct gctl_req *req);
72static void eli_restore(struct gctl_req *req);
73static void eli_clear(struct gctl_req *req);
74static void eli_dump(struct gctl_req *req);
75
76/*
77 * Available commands:
78 *
79 * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
80 * label - alias for 'init'
81 * attach [-dprv] [-k keyfile] prov
82 * detach [-fl] prov ...
83 * stop - alias for 'detach'
84 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
69static void eli_setkey(struct gctl_req *req);
70static void eli_delkey(struct gctl_req *req);
71static void eli_kill(struct gctl_req *req);
72static void eli_backup(struct gctl_req *req);
73static void eli_restore(struct gctl_req *req);
74static void eli_clear(struct gctl_req *req);
75static void eli_dump(struct gctl_req *req);
76
77/*
78 * Available commands:
79 *
80 * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov
81 * label - alias for 'init'
82 * attach [-dprv] [-k keyfile] prov
83 * detach [-fl] prov ...
84 * stop - alias for 'detach'
85 * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ...
86 * configure [-bB] prov ...
85 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
86 * delkey [-afv] [-n keyno] prov
87 * kill [-av] [prov ...]
88 * backup [-v] prov file
89 * restore [-v] file prov
90 * clear [-v] prov ...
91 * dump [-v] prov ...
92 */
93struct g_command class_commands[] = {
94 { "init", G_FLAG_VERBOSE, eli_main,
95 {
96 { 'a', "aalgo", aalgo, G_TYPE_STRING },
97 { 'b', "boot", NULL, G_TYPE_NONE },
98 { 'e', "ealgo", ealgo, G_TYPE_STRING },
99 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
100 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
101 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
102 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
103 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
104 G_OPT_SENTINEL
105 },
106 "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
107 },
108 { "label", G_FLAG_VERBOSE, eli_main,
109 {
110 { 'a', "aalgo", aalgo, G_TYPE_STRING },
111 { 'b', "boot", NULL, G_TYPE_NONE },
112 { 'e', "ealgo", ealgo, G_TYPE_STRING },
113 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
114 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
115 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
116 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
117 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
118 G_OPT_SENTINEL
119 },
120 "- an alias for 'init'"
121 },
122 { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
123 {
124 { 'd', "detach", NULL, G_TYPE_NONE },
125 { 'k', "keyfile", keyfile, G_TYPE_STRING },
126 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
127 { 'r', "readonly", NULL, G_TYPE_NONE },
128 G_OPT_SENTINEL
129 },
130 "[-dprv] [-k keyfile] prov"
131 },
132 { "detach", 0, NULL,
133 {
134 { 'f', "force", NULL, G_TYPE_NONE },
135 { 'l', "last", NULL, G_TYPE_NONE },
136 G_OPT_SENTINEL
137 },
138 "[-fl] prov ..."
139 },
140 { "stop", 0, NULL,
141 {
142 { 'f', "force", NULL, G_TYPE_NONE },
143 { 'l', "last", NULL, G_TYPE_NONE },
144 G_OPT_SENTINEL
145 },
146 "- an alias for 'detach'"
147 },
148 { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
149 {
150 { 'a', "aalgo", aalgo, G_TYPE_STRING },
151 { 'd', "detach", NULL, G_TYPE_NONE },
152 { 'e', "ealgo", ealgo, G_TYPE_STRING },
153 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
154 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
155 G_OPT_SENTINEL
156 },
157 "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
158 },
87 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
88 * delkey [-afv] [-n keyno] prov
89 * kill [-av] [prov ...]
90 * backup [-v] prov file
91 * restore [-v] file prov
92 * clear [-v] prov ...
93 * dump [-v] prov ...
94 */
95struct g_command class_commands[] = {
96 { "init", G_FLAG_VERBOSE, eli_main,
97 {
98 { 'a', "aalgo", aalgo, G_TYPE_STRING },
99 { 'b', "boot", NULL, G_TYPE_NONE },
100 { 'e', "ealgo", ealgo, G_TYPE_STRING },
101 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
102 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
103 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
104 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
105 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
106 G_OPT_SENTINEL
107 },
108 "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
109 },
110 { "label", G_FLAG_VERBOSE, eli_main,
111 {
112 { 'a', "aalgo", aalgo, G_TYPE_STRING },
113 { 'b', "boot", NULL, G_TYPE_NONE },
114 { 'e', "ealgo", ealgo, G_TYPE_STRING },
115 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
116 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
117 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
118 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
119 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
120 G_OPT_SENTINEL
121 },
122 "- an alias for 'init'"
123 },
124 { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
125 {
126 { 'd', "detach", NULL, G_TYPE_NONE },
127 { 'k', "keyfile", keyfile, G_TYPE_STRING },
128 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
129 { 'r', "readonly", NULL, G_TYPE_NONE },
130 G_OPT_SENTINEL
131 },
132 "[-dprv] [-k keyfile] prov"
133 },
134 { "detach", 0, NULL,
135 {
136 { 'f', "force", NULL, G_TYPE_NONE },
137 { 'l', "last", NULL, G_TYPE_NONE },
138 G_OPT_SENTINEL
139 },
140 "[-fl] prov ..."
141 },
142 { "stop", 0, NULL,
143 {
144 { 'f', "force", NULL, G_TYPE_NONE },
145 { 'l', "last", NULL, G_TYPE_NONE },
146 G_OPT_SENTINEL
147 },
148 "- an alias for 'detach'"
149 },
150 { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
151 {
152 { 'a', "aalgo", aalgo, G_TYPE_STRING },
153 { 'd', "detach", NULL, G_TYPE_NONE },
154 { 'e', "ealgo", ealgo, G_TYPE_STRING },
155 { 'l', "keylen", &keylen, G_TYPE_NUMBER },
156 { 's', "sectorsize", &sectorsize, G_TYPE_NUMBER },
157 G_OPT_SENTINEL
158 },
159 "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..."
160 },
161 { "configure", G_FLAG_VERBOSE, eli_main,
162 {
163 { 'b', "boot", NULL, G_TYPE_NONE },
164 { 'B', "noboot", NULL, G_TYPE_NONE },
165 G_OPT_SENTINEL
166 },
167 "[-bB] prov ..."
168 },
159 { "setkey", G_FLAG_VERBOSE, eli_main,
160 {
161 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
162 { 'k', "keyfile", keyfile, G_TYPE_STRING },
163 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
164 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
165 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
166 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
167 G_OPT_SENTINEL
168 },
169 "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
170 },
171 { "delkey", G_FLAG_VERBOSE, eli_main,
172 {
173 { 'a', "all", NULL, G_TYPE_NONE },
174 { 'f', "force", NULL, G_TYPE_NONE },
175 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
176 G_OPT_SENTINEL
177 },
178 "[-afv] [-n keyno] prov"
179 },
180 { "kill", G_FLAG_VERBOSE, eli_main,
181 {
182 { 'a', "all", NULL, G_TYPE_NONE },
183 G_OPT_SENTINEL
184 },
185 "[-av] [prov ...]"
186 },
187 { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
188 "[-v] prov file"
189 },
190 { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
191 "[-v] file prov"
192 },
193 { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
194 "[-v] prov ..."
195 },
196 { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
197 "[-v] prov ..."
198 },
199 G_CMD_SENTINEL
200};
201
202static int verbose = 0;
203
204static int
205eli_protect(struct gctl_req *req)
206{
207 struct rlimit rl;
208
209 /* Disable core dumps. */
210 rl.rlim_cur = 0;
211 rl.rlim_max = 0;
212 if (setrlimit(RLIMIT_CORE, &rl) == -1) {
213 gctl_error(req, "Cannot disable core dumps: %s.",
214 strerror(errno));
215 return (-1);
216 }
217 /* Disable swapping. */
218 if (mlockall(MCL_FUTURE) == -1) {
219 gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
220 return (-1);
221 }
222 return (0);
223}
224
225static void
226eli_main(struct gctl_req *req, unsigned flags)
227{
228 const char *name;
229
230 if (eli_protect(req) == -1)
231 return;
232
233 if ((flags & G_FLAG_VERBOSE) != 0)
234 verbose = 1;
235
236 name = gctl_get_ascii(req, "verb");
237 if (name == NULL) {
238 gctl_error(req, "No '%s' argument.", "verb");
239 return;
240 }
241 if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
242 eli_init(req);
243 else if (strcmp(name, "attach") == 0)
244 eli_attach(req);
169 { "setkey", G_FLAG_VERBOSE, eli_main,
170 {
171 { 'i', "iterations", &iterations, G_TYPE_NUMBER },
172 { 'k', "keyfile", keyfile, G_TYPE_STRING },
173 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING },
174 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
175 { 'p', "nopassphrase", NULL, G_TYPE_NONE },
176 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE },
177 G_OPT_SENTINEL
178 },
179 "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
180 },
181 { "delkey", G_FLAG_VERBOSE, eli_main,
182 {
183 { 'a', "all", NULL, G_TYPE_NONE },
184 { 'f', "force", NULL, G_TYPE_NONE },
185 { 'n', "keyno", &keyno, G_TYPE_NUMBER },
186 G_OPT_SENTINEL
187 },
188 "[-afv] [-n keyno] prov"
189 },
190 { "kill", G_FLAG_VERBOSE, eli_main,
191 {
192 { 'a', "all", NULL, G_TYPE_NONE },
193 G_OPT_SENTINEL
194 },
195 "[-av] [prov ...]"
196 },
197 { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
198 "[-v] prov file"
199 },
200 { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
201 "[-v] file prov"
202 },
203 { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
204 "[-v] prov ..."
205 },
206 { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
207 "[-v] prov ..."
208 },
209 G_CMD_SENTINEL
210};
211
212static int verbose = 0;
213
214static int
215eli_protect(struct gctl_req *req)
216{
217 struct rlimit rl;
218
219 /* Disable core dumps. */
220 rl.rlim_cur = 0;
221 rl.rlim_max = 0;
222 if (setrlimit(RLIMIT_CORE, &rl) == -1) {
223 gctl_error(req, "Cannot disable core dumps: %s.",
224 strerror(errno));
225 return (-1);
226 }
227 /* Disable swapping. */
228 if (mlockall(MCL_FUTURE) == -1) {
229 gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
230 return (-1);
231 }
232 return (0);
233}
234
235static void
236eli_main(struct gctl_req *req, unsigned flags)
237{
238 const char *name;
239
240 if (eli_protect(req) == -1)
241 return;
242
243 if ((flags & G_FLAG_VERBOSE) != 0)
244 verbose = 1;
245
246 name = gctl_get_ascii(req, "verb");
247 if (name == NULL) {
248 gctl_error(req, "No '%s' argument.", "verb");
249 return;
250 }
251 if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
252 eli_init(req);
253 else if (strcmp(name, "attach") == 0)
254 eli_attach(req);
255 else if (strcmp(name, "configure") == 0)
256 eli_configure(req);
245 else if (strcmp(name, "setkey") == 0)
246 eli_setkey(req);
247 else if (strcmp(name, "delkey") == 0)
248 eli_delkey(req);
249 else if (strcmp(name, "kill") == 0)
250 eli_kill(req);
251 else if (strcmp(name, "backup") == 0)
252 eli_backup(req);
253 else if (strcmp(name, "restore") == 0)
254 eli_restore(req);
255 else if (strcmp(name, "dump") == 0)
256 eli_dump(req);
257 else if (strcmp(name, "clear") == 0)
258 eli_clear(req);
259 else
260 gctl_error(req, "Unknown command: %s.", name);
261}
262
263static void
264arc4rand(unsigned char *buf, size_t size)
265{
266 uint32_t *buf4;
267 size_t size4;
268 unsigned i;
269
270 buf4 = (uint32_t *)buf;
271 size4 = size / 4;
272
273 for (i = 0; i < size4; i++)
274 buf4[i] = arc4random();
275 for (i *= 4; i < size; i++)
276 buf[i] = arc4random() % 0xff;
277}
278
279static int
280eli_is_attached(const char *prov)
281{
282 char name[MAXPATHLEN];
283 unsigned secsize;
284
285 /*
286 * Not the best way to do it, but the easiest.
287 * We try to open provider and check if it is a GEOM provider
288 * by asking about its sectorsize.
289 */
290 snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
291 secsize = g_get_sectorsize(name);
292 if (secsize > 0)
293 return (1);
294 return (0);
295}
296
297static unsigned char *
298eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
299 int new)
300{
301 struct hmac_ctx ctx;
302 const char *str;
303 int error, nopassphrase;
304
305 nopassphrase =
306 gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
307
308 g_eli_crypto_hmac_init(&ctx, NULL, 0);
309
310 str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
311 if (str[0] == '\0' && nopassphrase) {
312 gctl_error(req, "No key components given.");
313 return (NULL);
314 } else if (str[0] != '\0') {
315 char buf[MAXPHYS];
316 ssize_t done;
317 int fd;
318
319 if (strcmp(str, "-") == 0)
320 fd = STDIN_FILENO;
321 else {
322 fd = open(str, O_RDONLY);
323 if (fd == -1) {
324 gctl_error(req, "Cannot open keyfile %s: %s.",
325 str, strerror(errno));
326 return (NULL);
327 }
328 }
329 while ((done = read(fd, buf, sizeof(buf))) > 0)
330 g_eli_crypto_hmac_update(&ctx, buf, done);
331 error = errno;
332 if (strcmp(str, "-") != 0)
333 close(fd);
334 bzero(buf, sizeof(buf));
335 if (done == -1) {
336 gctl_error(req, "Cannot read keyfile %s: %s.", str,
337 strerror(error));
338 return (NULL);
339 }
340 }
341
342 if (!nopassphrase) {
343 char buf1[BUFSIZ], buf2[BUFSIZ], *p;
344
345 if (!new && md->md_iterations == -1) {
346 gctl_error(req, "Missing -p flag.");
347 return (NULL);
348 }
349 for (;;) {
350 p = readpassphrase(
351 new ? "Enter new passphrase:" : "Enter passphrase:",
352 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
353 if (p == NULL) {
354 bzero(buf1, sizeof(buf1));
355 gctl_error(req, "Cannot read passphrase: %s.",
356 strerror(errno));
357 return (NULL);
358 }
359
360 if (new) {
361 p = readpassphrase("Reenter new passphrase: ",
362 buf2, sizeof(buf2),
363 RPP_ECHO_OFF | RPP_REQUIRE_TTY);
364 if (p == NULL) {
365 bzero(buf1, sizeof(buf1));
366 gctl_error(req,
367 "Cannot read passphrase: %s.",
368 strerror(errno));
369 return (NULL);
370 }
371
372 if (strcmp(buf1, buf2) != 0) {
373 bzero(buf2, sizeof(buf2));
374 fprintf(stderr, "They didn't match.\n");
375 continue;
376 }
377 bzero(buf2, sizeof(buf2));
378 }
379 break;
380 }
381 /*
382 * Field md_iterations equal to -1 means "choose some sane
383 * value for me".
384 */
385 if (md->md_iterations == -1) {
386 assert(new);
387 if (verbose)
388 printf("Calculating number of iterations...\n");
389 md->md_iterations = pkcs5v2_calculate(2000000);
390 assert(md->md_iterations > 0);
391 if (verbose) {
392 printf("Done, using %d iterations.\n",
393 md->md_iterations);
394 }
395 }
396 /*
397 * If md_iterations is equal to 0, user don't want PKCS#5v2.
398 */
399 if (md->md_iterations == 0) {
400 g_eli_crypto_hmac_update(&ctx, md->md_salt,
401 sizeof(md->md_salt));
402 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
403 } else /* if (md->md_iterations > 0) */ {
404 unsigned char dkey[G_ELI_USERKEYLEN];
405
406 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
407 sizeof(md->md_salt), buf1, md->md_iterations);
408 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
409 bzero(dkey, sizeof(dkey));
410 }
411 bzero(buf1, sizeof(buf1));
412 }
413 g_eli_crypto_hmac_final(&ctx, key, 0);
414 return (key);
415}
416
417static int
418eli_metadata_read(struct gctl_req *req, const char *prov,
419 struct g_eli_metadata *md)
420{
421 unsigned char sector[sizeof(struct g_eli_metadata)];
422 int error;
423
424 if (g_get_sectorsize(prov) == 0) {
425 int fd;
426
427 /* This is a file probably. */
428 fd = open(prov, O_RDONLY);
429 if (fd == -1) {
430 gctl_error(req, "Cannot open %s: %s.", prov,
431 strerror(errno));
432 return (-1);
433 }
434 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
435 gctl_error(req, "Cannot read metadata from %s: %s.",
436 prov, strerror(errno));
437 close(fd);
438 return (-1);
439 }
440 close(fd);
441 } else {
442 /* This is a GEOM provider. */
443 error = g_metadata_read(prov, sector, sizeof(sector),
444 G_ELI_MAGIC);
445 if (error != 0) {
446 gctl_error(req, "Cannot read metadata from %s: %s.",
447 prov, strerror(error));
448 return (-1);
449 }
450 }
451 if (eli_metadata_decode(sector, md) != 0) {
452 gctl_error(req, "MD5 hash mismatch for %s.", prov);
453 return (-1);
454 }
455 return (0);
456}
457
458static int
459eli_metadata_store(struct gctl_req *req, const char *prov,
460 struct g_eli_metadata *md)
461{
462 unsigned char sector[sizeof(struct g_eli_metadata)];
463 int error;
464
465 eli_metadata_encode(md, sector);
466 if (g_get_sectorsize(prov) == 0) {
467 int fd;
468
469 /* This is a file probably. */
470 fd = open(prov, O_WRONLY | O_TRUNC);
471 if (fd == -1) {
472 gctl_error(req, "Cannot open %s: %s.", prov,
473 strerror(errno));
474 bzero(sector, sizeof(sector));
475 return (-1);
476 }
477 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
478 gctl_error(req, "Cannot write metadata to %s: %s.",
479 prov, strerror(errno));
480 bzero(sector, sizeof(sector));
481 close(fd);
482 return (-1);
483 }
484 close(fd);
485 } else {
486 /* This is a GEOM provider. */
487 error = g_metadata_store(prov, sector, sizeof(sector));
488 if (error != 0) {
489 gctl_error(req, "Cannot write metadata to %s: %s.",
490 prov, strerror(errno));
491 bzero(sector, sizeof(sector));
492 return (-1);
493 }
494 }
495 bzero(sector, sizeof(sector));
496 return (0);
497}
498
499static void
500eli_init(struct gctl_req *req)
501{
502 struct g_eli_metadata md;
503 unsigned char sector[sizeof(struct g_eli_metadata)];
504 unsigned char key[G_ELI_USERKEYLEN];
505 const char *str, *prov;
506 unsigned secsize;
507 off_t mediasize;
508 intmax_t val;
509 int error, nargs;
510
511 nargs = gctl_get_int(req, "nargs");
512 if (nargs != 1) {
513 gctl_error(req, "Invalid number of arguments.");
514 return;
515 }
516 prov = gctl_get_ascii(req, "arg0");
517 mediasize = g_get_mediasize(prov);
518 secsize = g_get_sectorsize(prov);
519 if (mediasize == 0 || secsize == 0) {
520 gctl_error(req, "Cannot get informations about %s: %s.", prov,
521 strerror(errno));
522 return;
523 }
524
525 bzero(&md, sizeof(md));
526 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
527 md.md_version = G_ELI_VERSION;
528 md.md_flags = 0;
529 if (gctl_get_int(req, "boot"))
530 md.md_flags |= G_ELI_FLAG_BOOT;
531 md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
532 str = gctl_get_ascii(req, "aalgo");
533 if (strcmp(str, "none") != 0) {
534 md.md_aalgo = g_eli_str2aalgo(str);
535 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
536 md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
537 md.md_flags |= G_ELI_FLAG_AUTH;
538 } else {
539 /*
540 * For backward compatibility, check if the -a option
541 * was used to provide encryption algorithm.
542 */
543 md.md_ealgo = g_eli_str2ealgo(str);
544 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
545 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
546 gctl_error(req,
547 "Invalid authentication algorithm.");
548 return;
549 } else {
550 fprintf(stderr, "warning: The -e option, not "
551 "the -a option is now used to specify "
552 "encryption algorithm to use.\n");
553 }
554 }
555 }
556 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
557 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
558 str = gctl_get_ascii(req, "ealgo");
559 md.md_ealgo = g_eli_str2ealgo(str);
560 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
561 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
562 gctl_error(req, "Invalid encryption algorithm.");
563 return;
564 }
565 }
566 val = gctl_get_intmax(req, "keylen");
567 md.md_keylen = val;
568 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
569 if (md.md_keylen == 0) {
570 gctl_error(req, "Invalid key length.");
571 return;
572 }
573 md.md_provsize = mediasize;
574
575 val = gctl_get_intmax(req, "iterations");
576 if (val != -1) {
577 int nonewpassphrase;
578
579 /*
580 * Don't allow to set iterations when there will be no
581 * passphrase.
582 */
583 nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
584 if (nonewpassphrase) {
585 gctl_error(req,
586 "Options -i and -P are mutually exclusive.");
587 return;
588 }
589 }
590 md.md_iterations = val;
591
592 val = gctl_get_intmax(req, "sectorsize");
593 if (val == 0)
594 md.md_sectorsize = secsize;
595 else {
596 if (val < 0 || (val % secsize) != 0) {
597 gctl_error(req, "Invalid sector size.");
598 return;
599 }
600 md.md_sectorsize = val;
601 }
602
603 md.md_keys = 0x01;
604 arc4rand(md.md_salt, sizeof(md.md_salt));
605 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
606
607 /* Generate user key. */
608 if (eli_genkey(req, &md, key, 1) == NULL) {
609 bzero(key, sizeof(key));
610 bzero(&md, sizeof(md));
611 return;
612 }
613
614 /* Encrypt the first and the only Master Key. */
615 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
616 bzero(key, sizeof(key));
617 if (error != 0) {
618 bzero(&md, sizeof(md));
619 gctl_error(req, "Cannot encrypt Master Key: %s.",
620 strerror(error));
621 return;
622 }
623
624 eli_metadata_encode(&md, sector);
625 bzero(&md, sizeof(md));
626 error = g_metadata_store(prov, sector, sizeof(sector));
627 bzero(sector, sizeof(sector));
628 if (error != 0) {
629 gctl_error(req, "Cannot store metadata on %s: %s.", prov,
630 strerror(error));
631 return;
632 }
633 if (verbose)
634 printf("Metadata value stored on %s.\n", prov);
635}
636
637static void
638eli_attach(struct gctl_req *req)
639{
640 struct g_eli_metadata md;
641 unsigned char key[G_ELI_USERKEYLEN];
642 const char *prov;
643 int nargs;
644
645 nargs = gctl_get_int(req, "nargs");
646 if (nargs != 1) {
647 gctl_error(req, "Invalid number of arguments.");
648 return;
649 }
650 prov = gctl_get_ascii(req, "arg0");
651
652 if (eli_metadata_read(req, prov, &md) == -1)
653 return;
654
655 if (eli_genkey(req, &md, key, 0) == NULL) {
656 bzero(key, sizeof(key));
657 return;
658 }
659
660 gctl_ro_param(req, "key", sizeof(key), key);
661 if (gctl_issue(req) == NULL) {
662 if (verbose)
663 printf("Attched to %s.\n", prov);
664 }
665 bzero(key, sizeof(key));
666}
667
668static void
257 else if (strcmp(name, "setkey") == 0)
258 eli_setkey(req);
259 else if (strcmp(name, "delkey") == 0)
260 eli_delkey(req);
261 else if (strcmp(name, "kill") == 0)
262 eli_kill(req);
263 else if (strcmp(name, "backup") == 0)
264 eli_backup(req);
265 else if (strcmp(name, "restore") == 0)
266 eli_restore(req);
267 else if (strcmp(name, "dump") == 0)
268 eli_dump(req);
269 else if (strcmp(name, "clear") == 0)
270 eli_clear(req);
271 else
272 gctl_error(req, "Unknown command: %s.", name);
273}
274
275static void
276arc4rand(unsigned char *buf, size_t size)
277{
278 uint32_t *buf4;
279 size_t size4;
280 unsigned i;
281
282 buf4 = (uint32_t *)buf;
283 size4 = size / 4;
284
285 for (i = 0; i < size4; i++)
286 buf4[i] = arc4random();
287 for (i *= 4; i < size; i++)
288 buf[i] = arc4random() % 0xff;
289}
290
291static int
292eli_is_attached(const char *prov)
293{
294 char name[MAXPATHLEN];
295 unsigned secsize;
296
297 /*
298 * Not the best way to do it, but the easiest.
299 * We try to open provider and check if it is a GEOM provider
300 * by asking about its sectorsize.
301 */
302 snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
303 secsize = g_get_sectorsize(name);
304 if (secsize > 0)
305 return (1);
306 return (0);
307}
308
309static unsigned char *
310eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
311 int new)
312{
313 struct hmac_ctx ctx;
314 const char *str;
315 int error, nopassphrase;
316
317 nopassphrase =
318 gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
319
320 g_eli_crypto_hmac_init(&ctx, NULL, 0);
321
322 str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
323 if (str[0] == '\0' && nopassphrase) {
324 gctl_error(req, "No key components given.");
325 return (NULL);
326 } else if (str[0] != '\0') {
327 char buf[MAXPHYS];
328 ssize_t done;
329 int fd;
330
331 if (strcmp(str, "-") == 0)
332 fd = STDIN_FILENO;
333 else {
334 fd = open(str, O_RDONLY);
335 if (fd == -1) {
336 gctl_error(req, "Cannot open keyfile %s: %s.",
337 str, strerror(errno));
338 return (NULL);
339 }
340 }
341 while ((done = read(fd, buf, sizeof(buf))) > 0)
342 g_eli_crypto_hmac_update(&ctx, buf, done);
343 error = errno;
344 if (strcmp(str, "-") != 0)
345 close(fd);
346 bzero(buf, sizeof(buf));
347 if (done == -1) {
348 gctl_error(req, "Cannot read keyfile %s: %s.", str,
349 strerror(error));
350 return (NULL);
351 }
352 }
353
354 if (!nopassphrase) {
355 char buf1[BUFSIZ], buf2[BUFSIZ], *p;
356
357 if (!new && md->md_iterations == -1) {
358 gctl_error(req, "Missing -p flag.");
359 return (NULL);
360 }
361 for (;;) {
362 p = readpassphrase(
363 new ? "Enter new passphrase:" : "Enter passphrase:",
364 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
365 if (p == NULL) {
366 bzero(buf1, sizeof(buf1));
367 gctl_error(req, "Cannot read passphrase: %s.",
368 strerror(errno));
369 return (NULL);
370 }
371
372 if (new) {
373 p = readpassphrase("Reenter new passphrase: ",
374 buf2, sizeof(buf2),
375 RPP_ECHO_OFF | RPP_REQUIRE_TTY);
376 if (p == NULL) {
377 bzero(buf1, sizeof(buf1));
378 gctl_error(req,
379 "Cannot read passphrase: %s.",
380 strerror(errno));
381 return (NULL);
382 }
383
384 if (strcmp(buf1, buf2) != 0) {
385 bzero(buf2, sizeof(buf2));
386 fprintf(stderr, "They didn't match.\n");
387 continue;
388 }
389 bzero(buf2, sizeof(buf2));
390 }
391 break;
392 }
393 /*
394 * Field md_iterations equal to -1 means "choose some sane
395 * value for me".
396 */
397 if (md->md_iterations == -1) {
398 assert(new);
399 if (verbose)
400 printf("Calculating number of iterations...\n");
401 md->md_iterations = pkcs5v2_calculate(2000000);
402 assert(md->md_iterations > 0);
403 if (verbose) {
404 printf("Done, using %d iterations.\n",
405 md->md_iterations);
406 }
407 }
408 /*
409 * If md_iterations is equal to 0, user don't want PKCS#5v2.
410 */
411 if (md->md_iterations == 0) {
412 g_eli_crypto_hmac_update(&ctx, md->md_salt,
413 sizeof(md->md_salt));
414 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
415 } else /* if (md->md_iterations > 0) */ {
416 unsigned char dkey[G_ELI_USERKEYLEN];
417
418 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
419 sizeof(md->md_salt), buf1, md->md_iterations);
420 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
421 bzero(dkey, sizeof(dkey));
422 }
423 bzero(buf1, sizeof(buf1));
424 }
425 g_eli_crypto_hmac_final(&ctx, key, 0);
426 return (key);
427}
428
429static int
430eli_metadata_read(struct gctl_req *req, const char *prov,
431 struct g_eli_metadata *md)
432{
433 unsigned char sector[sizeof(struct g_eli_metadata)];
434 int error;
435
436 if (g_get_sectorsize(prov) == 0) {
437 int fd;
438
439 /* This is a file probably. */
440 fd = open(prov, O_RDONLY);
441 if (fd == -1) {
442 gctl_error(req, "Cannot open %s: %s.", prov,
443 strerror(errno));
444 return (-1);
445 }
446 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
447 gctl_error(req, "Cannot read metadata from %s: %s.",
448 prov, strerror(errno));
449 close(fd);
450 return (-1);
451 }
452 close(fd);
453 } else {
454 /* This is a GEOM provider. */
455 error = g_metadata_read(prov, sector, sizeof(sector),
456 G_ELI_MAGIC);
457 if (error != 0) {
458 gctl_error(req, "Cannot read metadata from %s: %s.",
459 prov, strerror(error));
460 return (-1);
461 }
462 }
463 if (eli_metadata_decode(sector, md) != 0) {
464 gctl_error(req, "MD5 hash mismatch for %s.", prov);
465 return (-1);
466 }
467 return (0);
468}
469
470static int
471eli_metadata_store(struct gctl_req *req, const char *prov,
472 struct g_eli_metadata *md)
473{
474 unsigned char sector[sizeof(struct g_eli_metadata)];
475 int error;
476
477 eli_metadata_encode(md, sector);
478 if (g_get_sectorsize(prov) == 0) {
479 int fd;
480
481 /* This is a file probably. */
482 fd = open(prov, O_WRONLY | O_TRUNC);
483 if (fd == -1) {
484 gctl_error(req, "Cannot open %s: %s.", prov,
485 strerror(errno));
486 bzero(sector, sizeof(sector));
487 return (-1);
488 }
489 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
490 gctl_error(req, "Cannot write metadata to %s: %s.",
491 prov, strerror(errno));
492 bzero(sector, sizeof(sector));
493 close(fd);
494 return (-1);
495 }
496 close(fd);
497 } else {
498 /* This is a GEOM provider. */
499 error = g_metadata_store(prov, sector, sizeof(sector));
500 if (error != 0) {
501 gctl_error(req, "Cannot write metadata to %s: %s.",
502 prov, strerror(errno));
503 bzero(sector, sizeof(sector));
504 return (-1);
505 }
506 }
507 bzero(sector, sizeof(sector));
508 return (0);
509}
510
511static void
512eli_init(struct gctl_req *req)
513{
514 struct g_eli_metadata md;
515 unsigned char sector[sizeof(struct g_eli_metadata)];
516 unsigned char key[G_ELI_USERKEYLEN];
517 const char *str, *prov;
518 unsigned secsize;
519 off_t mediasize;
520 intmax_t val;
521 int error, nargs;
522
523 nargs = gctl_get_int(req, "nargs");
524 if (nargs != 1) {
525 gctl_error(req, "Invalid number of arguments.");
526 return;
527 }
528 prov = gctl_get_ascii(req, "arg0");
529 mediasize = g_get_mediasize(prov);
530 secsize = g_get_sectorsize(prov);
531 if (mediasize == 0 || secsize == 0) {
532 gctl_error(req, "Cannot get informations about %s: %s.", prov,
533 strerror(errno));
534 return;
535 }
536
537 bzero(&md, sizeof(md));
538 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
539 md.md_version = G_ELI_VERSION;
540 md.md_flags = 0;
541 if (gctl_get_int(req, "boot"))
542 md.md_flags |= G_ELI_FLAG_BOOT;
543 md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
544 str = gctl_get_ascii(req, "aalgo");
545 if (strcmp(str, "none") != 0) {
546 md.md_aalgo = g_eli_str2aalgo(str);
547 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
548 md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
549 md.md_flags |= G_ELI_FLAG_AUTH;
550 } else {
551 /*
552 * For backward compatibility, check if the -a option
553 * was used to provide encryption algorithm.
554 */
555 md.md_ealgo = g_eli_str2ealgo(str);
556 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
557 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
558 gctl_error(req,
559 "Invalid authentication algorithm.");
560 return;
561 } else {
562 fprintf(stderr, "warning: The -e option, not "
563 "the -a option is now used to specify "
564 "encryption algorithm to use.\n");
565 }
566 }
567 }
568 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
569 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
570 str = gctl_get_ascii(req, "ealgo");
571 md.md_ealgo = g_eli_str2ealgo(str);
572 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
573 md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
574 gctl_error(req, "Invalid encryption algorithm.");
575 return;
576 }
577 }
578 val = gctl_get_intmax(req, "keylen");
579 md.md_keylen = val;
580 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
581 if (md.md_keylen == 0) {
582 gctl_error(req, "Invalid key length.");
583 return;
584 }
585 md.md_provsize = mediasize;
586
587 val = gctl_get_intmax(req, "iterations");
588 if (val != -1) {
589 int nonewpassphrase;
590
591 /*
592 * Don't allow to set iterations when there will be no
593 * passphrase.
594 */
595 nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
596 if (nonewpassphrase) {
597 gctl_error(req,
598 "Options -i and -P are mutually exclusive.");
599 return;
600 }
601 }
602 md.md_iterations = val;
603
604 val = gctl_get_intmax(req, "sectorsize");
605 if (val == 0)
606 md.md_sectorsize = secsize;
607 else {
608 if (val < 0 || (val % secsize) != 0) {
609 gctl_error(req, "Invalid sector size.");
610 return;
611 }
612 md.md_sectorsize = val;
613 }
614
615 md.md_keys = 0x01;
616 arc4rand(md.md_salt, sizeof(md.md_salt));
617 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
618
619 /* Generate user key. */
620 if (eli_genkey(req, &md, key, 1) == NULL) {
621 bzero(key, sizeof(key));
622 bzero(&md, sizeof(md));
623 return;
624 }
625
626 /* Encrypt the first and the only Master Key. */
627 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
628 bzero(key, sizeof(key));
629 if (error != 0) {
630 bzero(&md, sizeof(md));
631 gctl_error(req, "Cannot encrypt Master Key: %s.",
632 strerror(error));
633 return;
634 }
635
636 eli_metadata_encode(&md, sector);
637 bzero(&md, sizeof(md));
638 error = g_metadata_store(prov, sector, sizeof(sector));
639 bzero(sector, sizeof(sector));
640 if (error != 0) {
641 gctl_error(req, "Cannot store metadata on %s: %s.", prov,
642 strerror(error));
643 return;
644 }
645 if (verbose)
646 printf("Metadata value stored on %s.\n", prov);
647}
648
649static void
650eli_attach(struct gctl_req *req)
651{
652 struct g_eli_metadata md;
653 unsigned char key[G_ELI_USERKEYLEN];
654 const char *prov;
655 int nargs;
656
657 nargs = gctl_get_int(req, "nargs");
658 if (nargs != 1) {
659 gctl_error(req, "Invalid number of arguments.");
660 return;
661 }
662 prov = gctl_get_ascii(req, "arg0");
663
664 if (eli_metadata_read(req, prov, &md) == -1)
665 return;
666
667 if (eli_genkey(req, &md, key, 0) == NULL) {
668 bzero(key, sizeof(key));
669 return;
670 }
671
672 gctl_ro_param(req, "key", sizeof(key), key);
673 if (gctl_issue(req) == NULL) {
674 if (verbose)
675 printf("Attched to %s.\n", prov);
676 }
677 bzero(key, sizeof(key));
678}
679
680static void
681eli_configure_detached(struct gctl_req *req, const char *prov, int boot)
682{
683 struct g_eli_metadata md;
684
685 if (eli_metadata_read(req, prov, &md) == -1)
686 return;
687
688 if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
689 if (verbose)
690 printf("BOOT flag already configured for %s.\n", prov);
691 } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
692 if (verbose)
693 printf("BOOT flag not configured for %s.\n", prov);
694 } else {
695 if (boot)
696 md.md_flags |= G_ELI_FLAG_BOOT;
697 else
698 md.md_flags &= ~G_ELI_FLAG_BOOT;
699 eli_metadata_store(req, prov, &md);
700 }
701 bzero(&md, sizeof(md));
702}
703
704static void
705eli_configure(struct gctl_req *req)
706{
707 const char *prov;
708 int i, nargs, boot, noboot;
709
710 nargs = gctl_get_int(req, "nargs");
711 if (nargs == 0) {
712 gctl_error(req, "Too few arguments.");
713 return;
714 }
715
716 boot = gctl_get_int(req, "boot");
717 noboot = gctl_get_int(req, "noboot");
718
719 if (boot && noboot) {
720 gctl_error(req, "Options -b and -B are mutually exclusive.");
721 return;
722 }
723 if (!boot && !noboot) {
724 gctl_error(req, "No option given.");
725 return;
726 }
727
728 /* First attached providers. */
729 gctl_issue(req);
730 /* Now the rest. */
731 for (i = 0; i < nargs; i++) {
732 prov = gctl_get_ascii(req, "arg%d", i);
733 if (!eli_is_attached(prov))
734 eli_configure_detached(req, prov, boot);
735 }
736}
737
738static void
669eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
670{
671 unsigned char key[G_ELI_USERKEYLEN];
672 intmax_t val;
673
674 val = gctl_get_intmax(req, "iterations");
675 /* Check if iterations number should be changed. */
676 if (val != -1)
677 md->md_iterations = val;
678
679 /* Generate key for Master Key encryption. */
680 if (eli_genkey(req, md, key, 1) == NULL) {
681 bzero(key, sizeof(key));
682 return;
683 }
684
685 gctl_ro_param(req, "key", sizeof(key), key);
686 gctl_issue(req);
687 bzero(key, sizeof(key));
688}
689
690static void
691eli_setkey_detached(struct gctl_req *req, const char *prov,
692 struct g_eli_metadata *md)
693{
694 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
695 unsigned char *mkeydst;
696 intmax_t val;
697 unsigned nkey;
698 int error;
699
700 if (md->md_keys == 0) {
701 gctl_error(req, "No valid keys on %s.", prov);
702 return;
703 }
704
705 /* Generate key for Master Key decryption. */
706 if (eli_genkey(req, md, key, 0) == NULL) {
707 bzero(key, sizeof(key));
708 return;
709 }
710
711 /* Decrypt Master Key. */
712 error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
713 bzero(key, sizeof(key));
714 if (error != 0) {
715 bzero(md, sizeof(*md));
716 if (error == -1)
717 gctl_error(req, "Wrong key for %s.", prov);
718 else /* if (error > 0) */ {
719 gctl_error(req, "Cannot decrypt Master Key: %s.",
720 strerror(error));
721 }
722 return;
723 }
724 if (verbose)
725 printf("Decrypted Master Key %u.\n", nkey);
726
727 val = gctl_get_intmax(req, "keyno");
728 if (val != -1)
729 nkey = val;
730#if 0
731 else
732 ; /* Use the key number which was found during decryption. */
733#endif
734 if (nkey >= G_ELI_MAXMKEYS) {
735 gctl_error(req, "Invalid '%s' argument.", "keyno");
736 return;
737 }
738
739 val = gctl_get_intmax(req, "iterations");
740 /* Check if iterations number should and can be changed. */
741 if (val != -1) {
742 if (bitcount32(md->md_keys) != 1) {
743 gctl_error(req, "To be able to use '-i' option, only "
744 "one key can be defined.");
745 return;
746 }
747 if (md->md_keys != (1 << nkey)) {
748 gctl_error(req, "Only already defined key can be "
749 "changed when '-i' option is used.");
750 return;
751 }
752 md->md_iterations = val;
753 }
754
755 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
756 md->md_keys |= (1 << nkey);
757
758 bcopy(mkey, mkeydst, sizeof(mkey));
759 bzero(mkey, sizeof(mkey));
760
761 /* Generate key for Master Key encryption. */
762 if (eli_genkey(req, md, key, 1) == NULL) {
763 bzero(key, sizeof(key));
764 bzero(md, sizeof(*md));
765 return;
766 }
767
768 /* Encrypt the Master-Key with the new key. */
769 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
770 bzero(key, sizeof(key));
771 if (error != 0) {
772 bzero(md, sizeof(*md));
773 gctl_error(req, "Cannot encrypt Master Key: %s.",
774 strerror(error));
775 return;
776 }
777
778 /* Store metadata with fresh key. */
779 eli_metadata_store(req, prov, md);
780 bzero(md, sizeof(*md));
781}
782
783static void
784eli_setkey(struct gctl_req *req)
785{
786 struct g_eli_metadata md;
787 const char *prov;
788 int nargs;
789
790 nargs = gctl_get_int(req, "nargs");
791 if (nargs != 1) {
792 gctl_error(req, "Invalid number of arguments.");
793 return;
794 }
795 prov = gctl_get_ascii(req, "arg0");
796
797 if (eli_metadata_read(req, prov, &md) == -1)
798 return;
799
800 if (eli_is_attached(prov))
801 eli_setkey_attached(req, &md);
802 else
803 eli_setkey_detached(req, prov, &md);
804}
805
806static void
807eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
808{
809
810 gctl_issue(req);
811}
812
813static void
814eli_delkey_detached(struct gctl_req *req, const char *prov)
815{
816 struct g_eli_metadata md;
817 unsigned char *mkeydst;
818 intmax_t val;
819 unsigned nkey;
820 int all, force;
821
822 if (eli_metadata_read(req, prov, &md) == -1)
823 return;
824
825 all = gctl_get_int(req, "all");
826 if (all)
827 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
828 else {
829 force = gctl_get_int(req, "force");
830 val = gctl_get_intmax(req, "keyno");
831 if (val == -1) {
832 gctl_error(req, "Key number has to be specified.");
833 return;
834 }
835 nkey = val;
836 if (nkey >= G_ELI_MAXMKEYS) {
837 gctl_error(req, "Invalid '%s' argument.", "keyno");
838 return;
839 }
840 if (!(md.md_keys & (1 << nkey)) && !force) {
841 gctl_error(req, "Master Key %u is not set.", nkey);
842 return;
843 }
844 md.md_keys &= ~(1 << nkey);
845 if (md.md_keys == 0 && !force) {
846 gctl_error(req, "This is the last Master Key. Use '-f' "
847 "option if you really want to remove it.");
848 return;
849 }
850 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
851 arc4rand(mkeydst, G_ELI_MKEYLEN);
852 }
853
854 eli_metadata_store(req, prov, &md);
855 bzero(&md, sizeof(md));
856}
857
858static void
859eli_delkey(struct gctl_req *req)
860{
861 const char *prov;
862 int nargs;
863
864 nargs = gctl_get_int(req, "nargs");
865 if (nargs != 1) {
866 gctl_error(req, "Invalid number of arguments.");
867 return;
868 }
869 prov = gctl_get_ascii(req, "arg0");
870
871 if (eli_is_attached(prov))
872 eli_delkey_attached(req, prov);
873 else
874 eli_delkey_detached(req, prov);
875}
876
877static void
878eli_kill_detached(struct gctl_req *req, const char *prov)
879{
880 struct g_eli_metadata md;
881 int error;
882
883 /*
884 * NOTE: Maybe we should verify if this is geli provider first,
885 * but 'kill' command is quite critical so better don't waste
886 * the time.
887 */
888#if 0
889 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
890 G_ELI_MAGIC);
891 if (error != 0) {
892 gctl_error(req, "Cannot read metadata from %s: %s.", prov,
893 strerror(error));
894 return;
895 }
896#endif
897
898 arc4rand((unsigned char *)&md, sizeof(md));
899 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
900 if (error != 0) {
901 gctl_error(req, "Cannot write metadata to %s: %s.", prov,
902 strerror(error));
903 }
904}
905
906static void
907eli_kill(struct gctl_req *req)
908{
909 const char *prov;
910 int i, nargs, all;
911
912 nargs = gctl_get_int(req, "nargs");
913 all = gctl_get_int(req, "all");
914 if (!all && nargs == 0) {
915 gctl_error(req, "Too few arguments.");
916 return;
917 }
918 /*
919 * How '-a' option combine with a list of providers:
920 * Delete Master Keys from all attached providers:
921 * geli kill -a
922 * Delete Master Keys from all attached provider and from
923 * detached da0 and da1:
924 * geli kill -a da0 da1
925 * Delete Master Keys from (attached or detached) da0 and da1:
926 * geli kill da0 da1
927 */
928
929 /* First detached provider. */
930 for (i = 0; i < nargs; i++) {
931 prov = gctl_get_ascii(req, "arg%d", i);
932 if (!eli_is_attached(prov))
933 eli_kill_detached(req, prov);
934 }
935 /* Now attached providers. */
936 gctl_issue(req);
937}
938
939static void
940eli_backup(struct gctl_req *req)
941{
942 struct g_eli_metadata md;
943 const char *file, *prov;
944 unsigned secsize;
945 unsigned char *sector;
946 off_t mediasize;
947 int nargs, filefd, provfd;
948
949 nargs = gctl_get_int(req, "nargs");
950 if (nargs != 2) {
951 gctl_error(req, "Invalid number of arguments.");
952 return;
953 }
954 prov = gctl_get_ascii(req, "arg0");
955 file = gctl_get_ascii(req, "arg1");
956
957 provfd = filefd = -1;
958 sector = NULL;
959 secsize = 0;
960
961 provfd = open(prov, O_RDONLY);
962 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
963 char devprov[MAXPATHLEN];
964
965 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
966 provfd = open(devprov, O_RDONLY);
967 }
968 if (provfd == -1) {
969 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
970 return;
971 }
972 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
973 if (filefd == -1) {
974 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
975 goto out;
976 }
977
978 mediasize = g_get_mediasize(prov);
979 secsize = g_get_sectorsize(prov);
980 if (mediasize == 0 || secsize == 0) {
981 gctl_error(req, "Cannot get informations about %s: %s.", prov,
982 strerror(errno));
983 return;
984 }
985
986 sector = malloc(secsize);
987 if (sector == NULL) {
988 gctl_error(req, "Cannot allocate memory.");
989 return;
990 }
991
992 /* Read metadata from the provider. */
993 if (pread(provfd, sector, secsize, mediasize - secsize) !=
994 (ssize_t)secsize) {
995 gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
996 goto out;
997 }
998 /* Check if this is geli provider. */
999 if (eli_metadata_decode(sector, &md) != 0) {
1000 gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1001 goto out;
1002 }
1003 /* Write metadata to the destination file. */
1004 if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1005 gctl_error(req, "Cannot write to %s: %s.", file,
1006 strerror(errno));
1007 goto out;
1008 }
1009out:
1010 if (provfd > 0)
1011 close(provfd);
1012 if (filefd > 0)
1013 close(filefd);
1014 if (sector != NULL) {
1015 bzero(sector, secsize);
1016 free(sector);
1017 }
1018}
1019
1020static void
1021eli_restore(struct gctl_req *req)
1022{
1023 struct g_eli_metadata md;
1024 const char *file, *prov;
1025 unsigned char *sector;
1026 unsigned secsize;
1027 off_t mediasize;
1028 int nargs, filefd, provfd;
1029
1030 nargs = gctl_get_int(req, "nargs");
1031 if (nargs != 2) {
1032 gctl_error(req, "Invalid number of arguments.");
1033 return;
1034 }
1035 file = gctl_get_ascii(req, "arg0");
1036 prov = gctl_get_ascii(req, "arg1");
1037
1038 provfd = filefd = -1;
1039 sector = NULL;
1040 secsize = 0;
1041
1042 filefd = open(file, O_RDONLY);
1043 if (filefd == -1) {
1044 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1045 goto out;
1046 }
1047 provfd = open(prov, O_WRONLY);
1048 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1049 char devprov[MAXPATHLEN];
1050
1051 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1052 provfd = open(devprov, O_WRONLY);
1053 }
1054 if (provfd == -1) {
1055 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1056 return;
1057 }
1058
1059 mediasize = g_get_mediasize(prov);
1060 secsize = g_get_sectorsize(prov);
1061 if (mediasize == 0 || secsize == 0) {
1062 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1063 strerror(errno));
1064 return;
1065 }
1066
1067 sector = malloc(secsize);
1068 if (sector == NULL) {
1069 gctl_error(req, "Cannot allocate memory.");
1070 return;
1071 }
1072
1073 /* Read metadata from the backup file. */
1074 if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1075 gctl_error(req, "Cannot read from %s: %s.", file,
1076 strerror(errno));
1077 goto out;
1078 }
1079 /* Check if this file contains geli metadata. */
1080 if (eli_metadata_decode(sector, &md) != 0) {
1081 gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1082 goto out;
1083 }
1084 /* Read metadata from the provider. */
1085 if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1086 (ssize_t)secsize) {
1087 gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1088 goto out;
1089 }
1090out:
1091 if (provfd > 0)
1092 close(provfd);
1093 if (filefd > 0)
1094 close(filefd);
1095 if (sector != NULL) {
1096 bzero(sector, secsize);
1097 free(sector);
1098 }
1099}
1100
1101static void
1102eli_clear(struct gctl_req *req)
1103{
1104 const char *name;
1105 int error, i, nargs;
1106
1107 nargs = gctl_get_int(req, "nargs");
1108 if (nargs < 1) {
1109 gctl_error(req, "Too few arguments.");
1110 return;
1111 }
1112
1113 for (i = 0; i < nargs; i++) {
1114 name = gctl_get_ascii(req, "arg%d", i);
1115 error = g_metadata_clear(name, G_ELI_MAGIC);
1116 if (error != 0) {
1117 fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1118 name, strerror(error));
1119 gctl_error(req, "Not fully done.");
1120 continue;
1121 }
1122 if (verbose)
1123 printf("Metadata cleared on %s.\n", name);
1124 }
1125}
1126
1127static void
1128eli_dump(struct gctl_req *req)
1129{
1130 struct g_eli_metadata md, tmpmd;
1131 const char *name;
1132 int error, i, nargs;
1133
1134 nargs = gctl_get_int(req, "nargs");
1135 if (nargs < 1) {
1136 gctl_error(req, "Too few arguments.");
1137 return;
1138 }
1139
1140 for (i = 0; i < nargs; i++) {
1141 name = gctl_get_ascii(req, "arg%d", i);
1142 error = g_metadata_read(name, (unsigned char *)&tmpmd,
1143 sizeof(tmpmd), G_ELI_MAGIC);
1144 if (error != 0) {
1145 fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1146 name, strerror(error));
1147 gctl_error(req, "Not fully done.");
1148 continue;
1149 }
1150 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1151 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1152 name);
1153 gctl_error(req, "Not fully done.");
1154 continue;
1155 }
1156 printf("Metadata on %s:\n", name);
1157 eli_metadata_dump(&md);
1158 printf("\n");
1159 }
1160}
739eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
740{
741 unsigned char key[G_ELI_USERKEYLEN];
742 intmax_t val;
743
744 val = gctl_get_intmax(req, "iterations");
745 /* Check if iterations number should be changed. */
746 if (val != -1)
747 md->md_iterations = val;
748
749 /* Generate key for Master Key encryption. */
750 if (eli_genkey(req, md, key, 1) == NULL) {
751 bzero(key, sizeof(key));
752 return;
753 }
754
755 gctl_ro_param(req, "key", sizeof(key), key);
756 gctl_issue(req);
757 bzero(key, sizeof(key));
758}
759
760static void
761eli_setkey_detached(struct gctl_req *req, const char *prov,
762 struct g_eli_metadata *md)
763{
764 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
765 unsigned char *mkeydst;
766 intmax_t val;
767 unsigned nkey;
768 int error;
769
770 if (md->md_keys == 0) {
771 gctl_error(req, "No valid keys on %s.", prov);
772 return;
773 }
774
775 /* Generate key for Master Key decryption. */
776 if (eli_genkey(req, md, key, 0) == NULL) {
777 bzero(key, sizeof(key));
778 return;
779 }
780
781 /* Decrypt Master Key. */
782 error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
783 bzero(key, sizeof(key));
784 if (error != 0) {
785 bzero(md, sizeof(*md));
786 if (error == -1)
787 gctl_error(req, "Wrong key for %s.", prov);
788 else /* if (error > 0) */ {
789 gctl_error(req, "Cannot decrypt Master Key: %s.",
790 strerror(error));
791 }
792 return;
793 }
794 if (verbose)
795 printf("Decrypted Master Key %u.\n", nkey);
796
797 val = gctl_get_intmax(req, "keyno");
798 if (val != -1)
799 nkey = val;
800#if 0
801 else
802 ; /* Use the key number which was found during decryption. */
803#endif
804 if (nkey >= G_ELI_MAXMKEYS) {
805 gctl_error(req, "Invalid '%s' argument.", "keyno");
806 return;
807 }
808
809 val = gctl_get_intmax(req, "iterations");
810 /* Check if iterations number should and can be changed. */
811 if (val != -1) {
812 if (bitcount32(md->md_keys) != 1) {
813 gctl_error(req, "To be able to use '-i' option, only "
814 "one key can be defined.");
815 return;
816 }
817 if (md->md_keys != (1 << nkey)) {
818 gctl_error(req, "Only already defined key can be "
819 "changed when '-i' option is used.");
820 return;
821 }
822 md->md_iterations = val;
823 }
824
825 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
826 md->md_keys |= (1 << nkey);
827
828 bcopy(mkey, mkeydst, sizeof(mkey));
829 bzero(mkey, sizeof(mkey));
830
831 /* Generate key for Master Key encryption. */
832 if (eli_genkey(req, md, key, 1) == NULL) {
833 bzero(key, sizeof(key));
834 bzero(md, sizeof(*md));
835 return;
836 }
837
838 /* Encrypt the Master-Key with the new key. */
839 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
840 bzero(key, sizeof(key));
841 if (error != 0) {
842 bzero(md, sizeof(*md));
843 gctl_error(req, "Cannot encrypt Master Key: %s.",
844 strerror(error));
845 return;
846 }
847
848 /* Store metadata with fresh key. */
849 eli_metadata_store(req, prov, md);
850 bzero(md, sizeof(*md));
851}
852
853static void
854eli_setkey(struct gctl_req *req)
855{
856 struct g_eli_metadata md;
857 const char *prov;
858 int nargs;
859
860 nargs = gctl_get_int(req, "nargs");
861 if (nargs != 1) {
862 gctl_error(req, "Invalid number of arguments.");
863 return;
864 }
865 prov = gctl_get_ascii(req, "arg0");
866
867 if (eli_metadata_read(req, prov, &md) == -1)
868 return;
869
870 if (eli_is_attached(prov))
871 eli_setkey_attached(req, &md);
872 else
873 eli_setkey_detached(req, prov, &md);
874}
875
876static void
877eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
878{
879
880 gctl_issue(req);
881}
882
883static void
884eli_delkey_detached(struct gctl_req *req, const char *prov)
885{
886 struct g_eli_metadata md;
887 unsigned char *mkeydst;
888 intmax_t val;
889 unsigned nkey;
890 int all, force;
891
892 if (eli_metadata_read(req, prov, &md) == -1)
893 return;
894
895 all = gctl_get_int(req, "all");
896 if (all)
897 arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
898 else {
899 force = gctl_get_int(req, "force");
900 val = gctl_get_intmax(req, "keyno");
901 if (val == -1) {
902 gctl_error(req, "Key number has to be specified.");
903 return;
904 }
905 nkey = val;
906 if (nkey >= G_ELI_MAXMKEYS) {
907 gctl_error(req, "Invalid '%s' argument.", "keyno");
908 return;
909 }
910 if (!(md.md_keys & (1 << nkey)) && !force) {
911 gctl_error(req, "Master Key %u is not set.", nkey);
912 return;
913 }
914 md.md_keys &= ~(1 << nkey);
915 if (md.md_keys == 0 && !force) {
916 gctl_error(req, "This is the last Master Key. Use '-f' "
917 "option if you really want to remove it.");
918 return;
919 }
920 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
921 arc4rand(mkeydst, G_ELI_MKEYLEN);
922 }
923
924 eli_metadata_store(req, prov, &md);
925 bzero(&md, sizeof(md));
926}
927
928static void
929eli_delkey(struct gctl_req *req)
930{
931 const char *prov;
932 int nargs;
933
934 nargs = gctl_get_int(req, "nargs");
935 if (nargs != 1) {
936 gctl_error(req, "Invalid number of arguments.");
937 return;
938 }
939 prov = gctl_get_ascii(req, "arg0");
940
941 if (eli_is_attached(prov))
942 eli_delkey_attached(req, prov);
943 else
944 eli_delkey_detached(req, prov);
945}
946
947static void
948eli_kill_detached(struct gctl_req *req, const char *prov)
949{
950 struct g_eli_metadata md;
951 int error;
952
953 /*
954 * NOTE: Maybe we should verify if this is geli provider first,
955 * but 'kill' command is quite critical so better don't waste
956 * the time.
957 */
958#if 0
959 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
960 G_ELI_MAGIC);
961 if (error != 0) {
962 gctl_error(req, "Cannot read metadata from %s: %s.", prov,
963 strerror(error));
964 return;
965 }
966#endif
967
968 arc4rand((unsigned char *)&md, sizeof(md));
969 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
970 if (error != 0) {
971 gctl_error(req, "Cannot write metadata to %s: %s.", prov,
972 strerror(error));
973 }
974}
975
976static void
977eli_kill(struct gctl_req *req)
978{
979 const char *prov;
980 int i, nargs, all;
981
982 nargs = gctl_get_int(req, "nargs");
983 all = gctl_get_int(req, "all");
984 if (!all && nargs == 0) {
985 gctl_error(req, "Too few arguments.");
986 return;
987 }
988 /*
989 * How '-a' option combine with a list of providers:
990 * Delete Master Keys from all attached providers:
991 * geli kill -a
992 * Delete Master Keys from all attached provider and from
993 * detached da0 and da1:
994 * geli kill -a da0 da1
995 * Delete Master Keys from (attached or detached) da0 and da1:
996 * geli kill da0 da1
997 */
998
999 /* First detached provider. */
1000 for (i = 0; i < nargs; i++) {
1001 prov = gctl_get_ascii(req, "arg%d", i);
1002 if (!eli_is_attached(prov))
1003 eli_kill_detached(req, prov);
1004 }
1005 /* Now attached providers. */
1006 gctl_issue(req);
1007}
1008
1009static void
1010eli_backup(struct gctl_req *req)
1011{
1012 struct g_eli_metadata md;
1013 const char *file, *prov;
1014 unsigned secsize;
1015 unsigned char *sector;
1016 off_t mediasize;
1017 int nargs, filefd, provfd;
1018
1019 nargs = gctl_get_int(req, "nargs");
1020 if (nargs != 2) {
1021 gctl_error(req, "Invalid number of arguments.");
1022 return;
1023 }
1024 prov = gctl_get_ascii(req, "arg0");
1025 file = gctl_get_ascii(req, "arg1");
1026
1027 provfd = filefd = -1;
1028 sector = NULL;
1029 secsize = 0;
1030
1031 provfd = open(prov, O_RDONLY);
1032 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1033 char devprov[MAXPATHLEN];
1034
1035 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1036 provfd = open(devprov, O_RDONLY);
1037 }
1038 if (provfd == -1) {
1039 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1040 return;
1041 }
1042 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1043 if (filefd == -1) {
1044 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1045 goto out;
1046 }
1047
1048 mediasize = g_get_mediasize(prov);
1049 secsize = g_get_sectorsize(prov);
1050 if (mediasize == 0 || secsize == 0) {
1051 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1052 strerror(errno));
1053 return;
1054 }
1055
1056 sector = malloc(secsize);
1057 if (sector == NULL) {
1058 gctl_error(req, "Cannot allocate memory.");
1059 return;
1060 }
1061
1062 /* Read metadata from the provider. */
1063 if (pread(provfd, sector, secsize, mediasize - secsize) !=
1064 (ssize_t)secsize) {
1065 gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
1066 goto out;
1067 }
1068 /* Check if this is geli provider. */
1069 if (eli_metadata_decode(sector, &md) != 0) {
1070 gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1071 goto out;
1072 }
1073 /* Write metadata to the destination file. */
1074 if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1075 gctl_error(req, "Cannot write to %s: %s.", file,
1076 strerror(errno));
1077 goto out;
1078 }
1079out:
1080 if (provfd > 0)
1081 close(provfd);
1082 if (filefd > 0)
1083 close(filefd);
1084 if (sector != NULL) {
1085 bzero(sector, secsize);
1086 free(sector);
1087 }
1088}
1089
1090static void
1091eli_restore(struct gctl_req *req)
1092{
1093 struct g_eli_metadata md;
1094 const char *file, *prov;
1095 unsigned char *sector;
1096 unsigned secsize;
1097 off_t mediasize;
1098 int nargs, filefd, provfd;
1099
1100 nargs = gctl_get_int(req, "nargs");
1101 if (nargs != 2) {
1102 gctl_error(req, "Invalid number of arguments.");
1103 return;
1104 }
1105 file = gctl_get_ascii(req, "arg0");
1106 prov = gctl_get_ascii(req, "arg1");
1107
1108 provfd = filefd = -1;
1109 sector = NULL;
1110 secsize = 0;
1111
1112 filefd = open(file, O_RDONLY);
1113 if (filefd == -1) {
1114 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1115 goto out;
1116 }
1117 provfd = open(prov, O_WRONLY);
1118 if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1119 char devprov[MAXPATHLEN];
1120
1121 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1122 provfd = open(devprov, O_WRONLY);
1123 }
1124 if (provfd == -1) {
1125 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1126 return;
1127 }
1128
1129 mediasize = g_get_mediasize(prov);
1130 secsize = g_get_sectorsize(prov);
1131 if (mediasize == 0 || secsize == 0) {
1132 gctl_error(req, "Cannot get informations about %s: %s.", prov,
1133 strerror(errno));
1134 return;
1135 }
1136
1137 sector = malloc(secsize);
1138 if (sector == NULL) {
1139 gctl_error(req, "Cannot allocate memory.");
1140 return;
1141 }
1142
1143 /* Read metadata from the backup file. */
1144 if (read(filefd, sector, secsize) != (ssize_t)secsize) {
1145 gctl_error(req, "Cannot read from %s: %s.", file,
1146 strerror(errno));
1147 goto out;
1148 }
1149 /* Check if this file contains geli metadata. */
1150 if (eli_metadata_decode(sector, &md) != 0) {
1151 gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1152 goto out;
1153 }
1154 /* Read metadata from the provider. */
1155 if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
1156 (ssize_t)secsize) {
1157 gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1158 goto out;
1159 }
1160out:
1161 if (provfd > 0)
1162 close(provfd);
1163 if (filefd > 0)
1164 close(filefd);
1165 if (sector != NULL) {
1166 bzero(sector, secsize);
1167 free(sector);
1168 }
1169}
1170
1171static void
1172eli_clear(struct gctl_req *req)
1173{
1174 const char *name;
1175 int error, i, nargs;
1176
1177 nargs = gctl_get_int(req, "nargs");
1178 if (nargs < 1) {
1179 gctl_error(req, "Too few arguments.");
1180 return;
1181 }
1182
1183 for (i = 0; i < nargs; i++) {
1184 name = gctl_get_ascii(req, "arg%d", i);
1185 error = g_metadata_clear(name, G_ELI_MAGIC);
1186 if (error != 0) {
1187 fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1188 name, strerror(error));
1189 gctl_error(req, "Not fully done.");
1190 continue;
1191 }
1192 if (verbose)
1193 printf("Metadata cleared on %s.\n", name);
1194 }
1195}
1196
1197static void
1198eli_dump(struct gctl_req *req)
1199{
1200 struct g_eli_metadata md, tmpmd;
1201 const char *name;
1202 int error, i, nargs;
1203
1204 nargs = gctl_get_int(req, "nargs");
1205 if (nargs < 1) {
1206 gctl_error(req, "Too few arguments.");
1207 return;
1208 }
1209
1210 for (i = 0; i < nargs; i++) {
1211 name = gctl_get_ascii(req, "arg%d", i);
1212 error = g_metadata_read(name, (unsigned char *)&tmpmd,
1213 sizeof(tmpmd), G_ELI_MAGIC);
1214 if (error != 0) {
1215 fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1216 name, strerror(error));
1217 gctl_error(req, "Not fully done.");
1218 continue;
1219 }
1220 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1221 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1222 name);
1223 gctl_error(req, "Not fully done.");
1224 continue;
1225 }
1226 printf("Metadata on %s:\n", name);
1227 eli_metadata_dump(&md);
1228 printf("\n");
1229 }
1230}