geom_eli.c revision 213058
1/*-
2 * Copyright (c) 2004-2008 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 213058 2010-09-23 10:58:13Z 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
57#define	GELI_BACKUP_DIR	"/var/backups/"
58#define	GELI_ENC_ALGO	"aes"
59
60static void eli_main(struct gctl_req *req, unsigned flags);
61static void eli_init(struct gctl_req *req);
62static void eli_attach(struct gctl_req *req);
63static void eli_configure(struct gctl_req *req);
64static void eli_setkey(struct gctl_req *req);
65static void eli_delkey(struct gctl_req *req);
66static void eli_kill(struct gctl_req *req);
67static void eli_backup(struct gctl_req *req);
68static void eli_restore(struct gctl_req *req);
69static void eli_resize(struct gctl_req *req);
70static void eli_clear(struct gctl_req *req);
71static void eli_dump(struct gctl_req *req);
72
73static int eli_backup_create(struct gctl_req *req, const char *prov,
74    const char *file);
75
76/*
77 * Available commands:
78 *
79 * init [-bhPv] [-a aalgo] [-B backupfile] [-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
85 * configure [-bB] prov ...
86 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov
87 * delkey [-afv] [-n keyno] prov
88 * kill [-av] [prov ...]
89 * backup [-v] prov file
90 * restore [-fv] file prov
91 * resize [-v] -s oldsize 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", "", G_TYPE_STRING },
99		{ 'b', "boot", NULL, G_TYPE_BOOL },
100		{ 'B', "backupfile", "", G_TYPE_STRING },
101		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
102		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
103		{ 'K', "newkeyfile", "", G_TYPE_STRING },
104		{ 'l', "keylen", "0", G_TYPE_NUMBER },
105		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
106		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
107		G_OPT_SENTINEL
108	    },
109	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov"
110	},
111	{ "label", G_FLAG_VERBOSE, eli_main,
112	    {
113		{ 'a', "aalgo", "", G_TYPE_STRING },
114		{ 'b', "boot", NULL, G_TYPE_BOOL },
115		{ 'B', "backupfile", "", G_TYPE_STRING },
116		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
117		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
118		{ 'K', "newkeyfile", "", G_TYPE_STRING },
119		{ 'l', "keylen", "0", G_TYPE_NUMBER },
120		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
121		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
122		G_OPT_SENTINEL
123	    },
124	    "- an alias for 'init'"
125	},
126	{ "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main,
127	    {
128		{ 'd', "detach", NULL, G_TYPE_BOOL },
129		{ 'k', "keyfile", "", G_TYPE_STRING },
130		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
131		{ 'r', "readonly", NULL, G_TYPE_BOOL },
132		G_OPT_SENTINEL
133	    },
134	    "[-dprv] [-k keyfile] prov"
135	},
136	{ "detach", 0, NULL,
137	    {
138		{ 'f', "force", NULL, G_TYPE_BOOL },
139		{ 'l', "last", NULL, G_TYPE_BOOL },
140		G_OPT_SENTINEL
141	    },
142	    "[-fl] prov ..."
143	},
144	{ "stop", 0, NULL,
145	    {
146		{ 'f', "force", NULL, G_TYPE_BOOL },
147		{ 'l', "last", NULL, G_TYPE_BOOL },
148		G_OPT_SENTINEL
149	    },
150	    "- an alias for 'detach'"
151	},
152	{ "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
153	    {
154		{ 'a', "aalgo", "", G_TYPE_STRING },
155		{ 'd', "detach", NULL, G_TYPE_BOOL },
156		{ 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING },
157		{ 'l', "keylen", "0", G_TYPE_NUMBER },
158		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
159		G_OPT_SENTINEL
160	    },
161	    "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov"
162	},
163	{ "configure", G_FLAG_VERBOSE, eli_main,
164	    {
165		{ 'b', "boot", NULL, G_TYPE_BOOL },
166		{ 'B', "noboot", NULL, G_TYPE_BOOL },
167		G_OPT_SENTINEL
168	    },
169	    "[-bB] prov ..."
170	},
171	{ "setkey", G_FLAG_VERBOSE, eli_main,
172	    {
173		{ 'i', "iterations", "-1", G_TYPE_NUMBER },
174		{ 'k', "keyfile", "", G_TYPE_STRING },
175		{ 'K', "newkeyfile", "", G_TYPE_STRING },
176		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
177		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
178		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
179		G_OPT_SENTINEL
180	    },
181	    "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov"
182	},
183	{ "delkey", G_FLAG_VERBOSE, eli_main,
184	    {
185		{ 'a', "all", NULL, G_TYPE_BOOL },
186		{ 'f', "force", NULL, G_TYPE_BOOL },
187		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
188		G_OPT_SENTINEL
189	    },
190	    "[-afv] [-n keyno] prov"
191	},
192	{ "kill", G_FLAG_VERBOSE, eli_main,
193	    {
194		{ 'a', "all", NULL, G_TYPE_BOOL },
195		G_OPT_SENTINEL
196	    },
197	    "[-av] [prov ...]"
198	},
199	{ "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
200	    "[-v] prov file"
201	},
202	{ "restore", G_FLAG_VERBOSE, eli_main,
203	    {
204		{ 'f', "force", NULL, G_TYPE_BOOL },
205		G_OPT_SENTINEL
206	    },
207	    "[-fv] file prov"
208	},
209	{ "resize", G_FLAG_VERBOSE, eli_main,
210	    {
211		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
212		G_OPT_SENTINEL
213	    },
214	    "[-v] -s oldsize prov"
215	},
216	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
217	    "[-v] prov ..."
218	},
219	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
220	    "[-v] prov ..."
221	},
222	G_CMD_SENTINEL
223};
224
225static int verbose = 0;
226
227static int
228eli_protect(struct gctl_req *req)
229{
230	struct rlimit rl;
231
232	/* Disable core dumps. */
233	rl.rlim_cur = 0;
234	rl.rlim_max = 0;
235	if (setrlimit(RLIMIT_CORE, &rl) == -1) {
236		gctl_error(req, "Cannot disable core dumps: %s.",
237		    strerror(errno));
238		return (-1);
239	}
240	/* Disable swapping. */
241	if (mlockall(MCL_FUTURE) == -1) {
242		gctl_error(req, "Cannot lock memory: %s.", strerror(errno));
243		return (-1);
244	}
245	return (0);
246}
247
248static void
249eli_main(struct gctl_req *req, unsigned flags)
250{
251	const char *name;
252
253	if (eli_protect(req) == -1)
254		return;
255
256	if ((flags & G_FLAG_VERBOSE) != 0)
257		verbose = 1;
258
259	name = gctl_get_ascii(req, "verb");
260	if (name == NULL) {
261		gctl_error(req, "No '%s' argument.", "verb");
262		return;
263	}
264	if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0)
265		eli_init(req);
266	else if (strcmp(name, "attach") == 0)
267		eli_attach(req);
268	else if (strcmp(name, "configure") == 0)
269		eli_configure(req);
270	else if (strcmp(name, "setkey") == 0)
271		eli_setkey(req);
272	else if (strcmp(name, "delkey") == 0)
273		eli_delkey(req);
274	else if (strcmp(name, "kill") == 0)
275		eli_kill(req);
276	else if (strcmp(name, "backup") == 0)
277		eli_backup(req);
278	else if (strcmp(name, "restore") == 0)
279		eli_restore(req);
280	else if (strcmp(name, "resize") == 0)
281		eli_resize(req);
282	else if (strcmp(name, "dump") == 0)
283		eli_dump(req);
284	else if (strcmp(name, "clear") == 0)
285		eli_clear(req);
286	else
287		gctl_error(req, "Unknown command: %s.", name);
288}
289
290static void
291arc4rand(unsigned char *buf, size_t size)
292{
293	uint32_t *buf4;
294	size_t size4;
295	unsigned i;
296
297	buf4 = (uint32_t *)buf;
298	size4 = size / 4;
299
300	for (i = 0; i < size4; i++)
301		buf4[i] = arc4random();
302	for (i *= 4; i < size; i++)
303		buf[i] = arc4random() % 0xff;
304}
305
306static int
307eli_is_attached(const char *prov)
308{
309	char name[MAXPATHLEN];
310	unsigned secsize;
311
312	/*
313	 * Not the best way to do it, but the easiest.
314	 * We try to open provider and check if it is a GEOM provider
315	 * by asking about its sectorsize.
316	 */
317	snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX);
318	secsize = g_get_sectorsize(name);
319	if (secsize > 0)
320		return (1);
321	return (0);
322}
323
324static unsigned char *
325eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key,
326    int new)
327{
328	struct hmac_ctx ctx;
329	const char *str;
330	int error, nopassphrase;
331
332	nopassphrase =
333	    gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase");
334
335	g_eli_crypto_hmac_init(&ctx, NULL, 0);
336
337	str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile");
338	if (str[0] == '\0' && nopassphrase) {
339		gctl_error(req, "No key components given.");
340		return (NULL);
341	} else if (str[0] != '\0') {
342		char buf[MAXPHYS];
343		ssize_t done;
344		int fd;
345
346		if (strcmp(str, "-") == 0)
347			fd = STDIN_FILENO;
348		else {
349			fd = open(str, O_RDONLY);
350			if (fd == -1) {
351				gctl_error(req, "Cannot open keyfile %s: %s.",
352				    str, strerror(errno));
353				return (NULL);
354			}
355		}
356		while ((done = read(fd, buf, sizeof(buf))) > 0)
357			g_eli_crypto_hmac_update(&ctx, buf, done);
358		error = errno;
359		if (strcmp(str, "-") != 0)
360			close(fd);
361		bzero(buf, sizeof(buf));
362		if (done == -1) {
363			gctl_error(req, "Cannot read keyfile %s: %s.", str,
364			    strerror(error));
365			return (NULL);
366		}
367	}
368
369	if (!nopassphrase) {
370		char buf1[BUFSIZ], buf2[BUFSIZ], *p;
371
372		if (!new && md->md_iterations == -1) {
373			gctl_error(req, "Missing -p flag.");
374			return (NULL);
375		}
376		for (;;) {
377			p = readpassphrase(
378			    new ? "Enter new passphrase:" : "Enter passphrase:",
379			    buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY);
380			if (p == NULL) {
381				bzero(buf1, sizeof(buf1));
382				gctl_error(req, "Cannot read passphrase: %s.",
383				    strerror(errno));
384				return (NULL);
385			}
386
387			if (new) {
388				p = readpassphrase("Reenter new passphrase: ",
389				    buf2, sizeof(buf2),
390				    RPP_ECHO_OFF | RPP_REQUIRE_TTY);
391				if (p == NULL) {
392					bzero(buf1, sizeof(buf1));
393					gctl_error(req,
394					    "Cannot read passphrase: %s.",
395					    strerror(errno));
396					return (NULL);
397				}
398
399				if (strcmp(buf1, buf2) != 0) {
400					bzero(buf2, sizeof(buf2));
401					fprintf(stderr, "They didn't match.\n");
402					continue;
403				}
404				bzero(buf2, sizeof(buf2));
405			}
406			break;
407		}
408		/*
409		 * Field md_iterations equal to -1 means "choose some sane
410		 * value for me".
411		 */
412		if (md->md_iterations == -1) {
413			assert(new);
414			if (verbose)
415				printf("Calculating number of iterations...\n");
416			md->md_iterations = pkcs5v2_calculate(2000000);
417			assert(md->md_iterations > 0);
418			if (verbose) {
419				printf("Done, using %d iterations.\n",
420				    md->md_iterations);
421			}
422		}
423		/*
424		 * If md_iterations is equal to 0, user don't want PKCS#5v2.
425		 */
426		if (md->md_iterations == 0) {
427			g_eli_crypto_hmac_update(&ctx, md->md_salt,
428			    sizeof(md->md_salt));
429			g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1));
430		} else /* if (md->md_iterations > 0) */ {
431			unsigned char dkey[G_ELI_USERKEYLEN];
432
433			pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt,
434			    sizeof(md->md_salt), buf1, md->md_iterations);
435			g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
436			bzero(dkey, sizeof(dkey));
437		}
438		bzero(buf1, sizeof(buf1));
439	}
440	g_eli_crypto_hmac_final(&ctx, key, 0);
441	return (key);
442}
443
444static int
445eli_metadata_read(struct gctl_req *req, const char *prov,
446    struct g_eli_metadata *md)
447{
448	unsigned char sector[sizeof(struct g_eli_metadata)];
449	int error;
450
451	if (g_get_sectorsize(prov) == 0) {
452		int fd;
453
454		/* This is a file probably. */
455		fd = open(prov, O_RDONLY);
456		if (fd == -1) {
457			gctl_error(req, "Cannot open %s: %s.", prov,
458			    strerror(errno));
459			return (-1);
460		}
461		if (read(fd, sector, sizeof(sector)) != sizeof(sector)) {
462			gctl_error(req, "Cannot read metadata from %s: %s.",
463			    prov, strerror(errno));
464			close(fd);
465			return (-1);
466		}
467		close(fd);
468	} else {
469		/* This is a GEOM provider. */
470		error = g_metadata_read(prov, sector, sizeof(sector),
471		    G_ELI_MAGIC);
472		if (error != 0) {
473			gctl_error(req, "Cannot read metadata from %s: %s.",
474			    prov, strerror(error));
475			return (-1);
476		}
477	}
478	if (eli_metadata_decode(sector, md) != 0) {
479		gctl_error(req, "MD5 hash mismatch for %s.", prov);
480		return (-1);
481	}
482	return (0);
483}
484
485static int
486eli_metadata_store(struct gctl_req *req, const char *prov,
487    struct g_eli_metadata *md)
488{
489	unsigned char sector[sizeof(struct g_eli_metadata)];
490	int error;
491
492	eli_metadata_encode(md, sector);
493	if (g_get_sectorsize(prov) == 0) {
494		int fd;
495
496		/* This is a file probably. */
497		fd = open(prov, O_WRONLY | O_TRUNC);
498		if (fd == -1) {
499			gctl_error(req, "Cannot open %s: %s.", prov,
500			    strerror(errno));
501			bzero(sector, sizeof(sector));
502			return (-1);
503		}
504		if (write(fd, sector, sizeof(sector)) != sizeof(sector)) {
505			gctl_error(req, "Cannot write metadata to %s: %s.",
506			    prov, strerror(errno));
507			bzero(sector, sizeof(sector));
508			close(fd);
509			return (-1);
510		}
511		close(fd);
512	} else {
513		/* This is a GEOM provider. */
514		error = g_metadata_store(prov, sector, sizeof(sector));
515		if (error != 0) {
516			gctl_error(req, "Cannot write metadata to %s: %s.",
517			    prov, strerror(errno));
518			bzero(sector, sizeof(sector));
519			return (-1);
520		}
521	}
522	bzero(sector, sizeof(sector));
523	return (0);
524}
525
526static void
527eli_init(struct gctl_req *req)
528{
529	struct g_eli_metadata md;
530	unsigned char sector[sizeof(struct g_eli_metadata)];
531	unsigned char key[G_ELI_USERKEYLEN];
532	char backfile[MAXPATHLEN];
533	const char *str, *prov;
534	unsigned secsize;
535	off_t mediasize;
536	intmax_t val;
537	int error, nargs;
538
539	nargs = gctl_get_int(req, "nargs");
540	if (nargs != 1) {
541		gctl_error(req, "Invalid number of arguments.");
542		return;
543	}
544	prov = gctl_get_ascii(req, "arg0");
545	mediasize = g_get_mediasize(prov);
546	secsize = g_get_sectorsize(prov);
547	if (mediasize == 0 || secsize == 0) {
548		gctl_error(req, "Cannot get informations about %s: %s.", prov,
549		    strerror(errno));
550		return;
551	}
552
553	bzero(&md, sizeof(md));
554	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
555	md.md_version = G_ELI_VERSION;
556	md.md_flags = 0;
557	if (gctl_get_int(req, "boot"))
558		md.md_flags |= G_ELI_FLAG_BOOT;
559	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
560	str = gctl_get_ascii(req, "aalgo");
561	if (*str != '\0') {
562		md.md_aalgo = g_eli_str2aalgo(str);
563		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
564		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
565			md.md_flags |= G_ELI_FLAG_AUTH;
566		} else {
567			/*
568			 * For backward compatibility, check if the -a option
569			 * was used to provide encryption algorithm.
570			 */
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,
575				    "Invalid authentication algorithm.");
576				return;
577			} else {
578				fprintf(stderr, "warning: The -e option, not "
579				    "the -a option is now used to specify "
580				    "encryption algorithm to use.\n");
581			}
582		}
583	}
584	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
585	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
586		str = gctl_get_ascii(req, "ealgo");
587		md.md_ealgo = g_eli_str2ealgo(str);
588		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
589		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
590			gctl_error(req, "Invalid encryption algorithm.");
591			return;
592		}
593	}
594	val = gctl_get_intmax(req, "keylen");
595	md.md_keylen = val;
596	md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen);
597	if (md.md_keylen == 0) {
598		gctl_error(req, "Invalid key length.");
599		return;
600	}
601	md.md_provsize = mediasize;
602
603	val = gctl_get_intmax(req, "iterations");
604	if (val != -1) {
605		int nonewpassphrase;
606
607		/*
608		 * Don't allow to set iterations when there will be no
609		 * passphrase.
610		 */
611		nonewpassphrase = gctl_get_int(req, "nonewpassphrase");
612		if (nonewpassphrase) {
613			gctl_error(req,
614			    "Options -i and -P are mutually exclusive.");
615			return;
616		}
617	}
618	md.md_iterations = val;
619
620	val = gctl_get_intmax(req, "sectorsize");
621	if (val == 0)
622		md.md_sectorsize = secsize;
623	else {
624		if (val < 0 || (val % secsize) != 0) {
625			gctl_error(req, "Invalid sector size.");
626			return;
627		}
628		if (val > sysconf(_SC_PAGE_SIZE)) {
629			gctl_error(req, "warning: Using sectorsize bigger than "
630			    "the page size!");
631		}
632		md.md_sectorsize = val;
633	}
634
635	md.md_keys = 0x01;
636	arc4rand(md.md_salt, sizeof(md.md_salt));
637	arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
638
639	/* Generate user key. */
640	if (eli_genkey(req, &md, key, 1) == NULL) {
641		bzero(key, sizeof(key));
642		bzero(&md, sizeof(md));
643		return;
644	}
645
646	/* Encrypt the first and the only Master Key. */
647	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys);
648	bzero(key, sizeof(key));
649	if (error != 0) {
650		bzero(&md, sizeof(md));
651		gctl_error(req, "Cannot encrypt Master Key: %s.",
652		    strerror(error));
653		return;
654	}
655
656	eli_metadata_encode(&md, sector);
657	bzero(&md, sizeof(md));
658	error = g_metadata_store(prov, sector, sizeof(sector));
659	bzero(sector, sizeof(sector));
660	if (error != 0) {
661		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
662		    strerror(error));
663		return;
664	}
665	if (verbose)
666		printf("Metadata value stored on %s.\n", prov);
667	/* Backup metadata to a file. */
668	str = gctl_get_ascii(req, "backupfile");
669	if (str[0] != '\0') {
670		/* Backupfile given be the user, just copy it. */
671		strlcpy(backfile, str, sizeof(backfile));
672	} else {
673		/* Generate file name automatically. */
674		const char *p = prov;
675		unsigned int i;
676
677		if (strncmp(p, _PATH_DEV, strlen(_PATH_DEV)) == 0)
678			p += strlen(_PATH_DEV);
679		snprintf(backfile, sizeof(backfile), "%s%s.eli",
680		    GELI_BACKUP_DIR, p);
681		/* Replace all / with _. */
682		for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) {
683			if (backfile[i] == '/')
684				backfile[i] = '_';
685		}
686	}
687	if (strcmp(backfile, "none") != 0 &&
688	    eli_backup_create(req, prov, backfile) == 0) {
689		printf("\nMetadata backup can be found in %s and\n", backfile);
690		printf("can be restored with the following command:\n");
691		printf("\n\t# geli restore %s %s\n\n", backfile, prov);
692	}
693}
694
695static void
696eli_attach(struct gctl_req *req)
697{
698	struct g_eli_metadata md;
699	unsigned char key[G_ELI_USERKEYLEN];
700	const char *prov;
701	off_t mediasize;
702	int nargs;
703
704	nargs = gctl_get_int(req, "nargs");
705	if (nargs != 1) {
706		gctl_error(req, "Invalid number of arguments.");
707		return;
708	}
709	prov = gctl_get_ascii(req, "arg0");
710
711	if (eli_metadata_read(req, prov, &md) == -1)
712		return;
713
714	mediasize = g_get_mediasize(prov);
715	if (md.md_provsize != (uint64_t)mediasize) {
716		gctl_error(req, "Provider size mismatch.");
717		return;
718	}
719
720	if (eli_genkey(req, &md, key, 0) == NULL) {
721		bzero(key, sizeof(key));
722		return;
723	}
724
725	gctl_ro_param(req, "key", sizeof(key), key);
726	if (gctl_issue(req) == NULL) {
727		if (verbose)
728			printf("Attached to %s.\n", prov);
729	}
730	bzero(key, sizeof(key));
731}
732
733static void
734eli_configure_detached(struct gctl_req *req, const char *prov, int boot)
735{
736	struct g_eli_metadata md;
737
738	if (eli_metadata_read(req, prov, &md) == -1)
739		return;
740
741	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
742		if (verbose)
743			printf("BOOT flag already configured for %s.\n", prov);
744	} else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) {
745		if (verbose)
746			printf("BOOT flag not configured for %s.\n", prov);
747	} else {
748		if (boot)
749			md.md_flags |= G_ELI_FLAG_BOOT;
750		else
751			md.md_flags &= ~G_ELI_FLAG_BOOT;
752		eli_metadata_store(req, prov, &md);
753	}
754	bzero(&md, sizeof(md));
755}
756
757static void
758eli_configure(struct gctl_req *req)
759{
760	const char *prov;
761	int i, nargs, boot, noboot;
762
763	nargs = gctl_get_int(req, "nargs");
764	if (nargs == 0) {
765		gctl_error(req, "Too few arguments.");
766		return;
767	}
768
769	boot = gctl_get_int(req, "boot");
770	noboot = gctl_get_int(req, "noboot");
771
772	if (boot && noboot) {
773		gctl_error(req, "Options -b and -B are mutually exclusive.");
774		return;
775	}
776	if (!boot && !noboot) {
777		gctl_error(req, "No option given.");
778		return;
779	}
780
781	/* First attached providers. */
782	gctl_issue(req);
783	/* Now the rest. */
784	for (i = 0; i < nargs; i++) {
785		prov = gctl_get_ascii(req, "arg%d", i);
786		if (!eli_is_attached(prov))
787			eli_configure_detached(req, prov, boot);
788	}
789}
790
791static void
792eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md)
793{
794	unsigned char key[G_ELI_USERKEYLEN];
795	intmax_t val, old = 0;
796	int error;
797
798	val = gctl_get_intmax(req, "iterations");
799	/* Check if iterations number should be changed. */
800	if (val != -1)
801		md->md_iterations = val;
802	else
803		old = md->md_iterations;
804
805	/* Generate key for Master Key encryption. */
806	if (eli_genkey(req, md, key, 1) == NULL) {
807		bzero(key, sizeof(key));
808		return;
809	}
810	/*
811	 * If number of iterations has changed, but wasn't given as a
812	 * command-line argument, update the request.
813	 */
814	if (val == -1 && md->md_iterations != old) {
815		error = gctl_change_param(req, "iterations", sizeof(intmax_t),
816		    &md->md_iterations);
817		assert(error == 0);
818	}
819
820	gctl_ro_param(req, "key", sizeof(key), key);
821	gctl_issue(req);
822	bzero(key, sizeof(key));
823}
824
825static void
826eli_setkey_detached(struct gctl_req *req, const char *prov,
827 struct g_eli_metadata *md)
828{
829	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
830	unsigned char *mkeydst;
831	intmax_t val;
832	unsigned nkey;
833	int error;
834
835	if (md->md_keys == 0) {
836		gctl_error(req, "No valid keys on %s.", prov);
837		return;
838	}
839
840	/* Generate key for Master Key decryption. */
841	if (eli_genkey(req, md, key, 0) == NULL) {
842		bzero(key, sizeof(key));
843		return;
844	}
845
846	/* Decrypt Master Key. */
847	error = g_eli_mkey_decrypt(md, key, mkey, &nkey);
848	bzero(key, sizeof(key));
849	if (error != 0) {
850		bzero(md, sizeof(*md));
851		if (error == -1)
852			gctl_error(req, "Wrong key for %s.", prov);
853		else /* if (error > 0) */ {
854			gctl_error(req, "Cannot decrypt Master Key: %s.",
855			    strerror(error));
856		}
857		return;
858	}
859	if (verbose)
860		printf("Decrypted Master Key %u.\n", nkey);
861
862	val = gctl_get_intmax(req, "keyno");
863	if (val != -1)
864		nkey = val;
865#if 0
866	else
867		; /* Use the key number which was found during decryption. */
868#endif
869	if (nkey >= G_ELI_MAXMKEYS) {
870		gctl_error(req, "Invalid '%s' argument.", "keyno");
871		return;
872	}
873
874	val = gctl_get_intmax(req, "iterations");
875	/* Check if iterations number should and can be changed. */
876	if (val != -1) {
877		if (bitcount32(md->md_keys) != 1) {
878			gctl_error(req, "To be able to use '-i' option, only "
879			    "one key can be defined.");
880			return;
881		}
882		if (md->md_keys != (1 << nkey)) {
883			gctl_error(req, "Only already defined key can be "
884			    "changed when '-i' option is used.");
885			return;
886		}
887		md->md_iterations = val;
888	}
889
890	mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN;
891	md->md_keys |= (1 << nkey);
892
893	bcopy(mkey, mkeydst, sizeof(mkey));
894	bzero(mkey, sizeof(mkey));
895
896	/* Generate key for Master Key encryption. */
897	if (eli_genkey(req, md, key, 1) == NULL) {
898		bzero(key, sizeof(key));
899		bzero(md, sizeof(*md));
900		return;
901	}
902
903	/* Encrypt the Master-Key with the new key. */
904	error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst);
905	bzero(key, sizeof(key));
906	if (error != 0) {
907		bzero(md, sizeof(*md));
908		gctl_error(req, "Cannot encrypt Master Key: %s.",
909		    strerror(error));
910		return;
911	}
912
913	/* Store metadata with fresh key. */
914	eli_metadata_store(req, prov, md);
915	bzero(md, sizeof(*md));
916}
917
918static void
919eli_setkey(struct gctl_req *req)
920{
921	struct g_eli_metadata md;
922	const char *prov;
923	int nargs;
924
925	nargs = gctl_get_int(req, "nargs");
926	if (nargs != 1) {
927		gctl_error(req, "Invalid number of arguments.");
928		return;
929	}
930	prov = gctl_get_ascii(req, "arg0");
931
932	if (eli_metadata_read(req, prov, &md) == -1)
933		return;
934
935	if (eli_is_attached(prov))
936		eli_setkey_attached(req, &md);
937	else
938		eli_setkey_detached(req, prov, &md);
939
940	if (req->error == NULL || req->error[0] == '\0') {
941		printf("Note, that the master key encrypted with old keys "
942		    "and/or passphrase may still exists in a metadata backup "
943		    "file.\n");
944	}
945}
946
947static void
948eli_delkey_attached(struct gctl_req *req, const char *prov __unused)
949{
950
951	gctl_issue(req);
952}
953
954static void
955eli_delkey_detached(struct gctl_req *req, const char *prov)
956{
957	struct g_eli_metadata md;
958	unsigned char *mkeydst;
959	intmax_t val;
960	unsigned nkey;
961	int all, force;
962
963	if (eli_metadata_read(req, prov, &md) == -1)
964		return;
965
966	all = gctl_get_int(req, "all");
967	if (all)
968		arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
969	else {
970		force = gctl_get_int(req, "force");
971		val = gctl_get_intmax(req, "keyno");
972		if (val == -1) {
973			gctl_error(req, "Key number has to be specified.");
974			return;
975		}
976		nkey = val;
977		if (nkey >= G_ELI_MAXMKEYS) {
978			gctl_error(req, "Invalid '%s' argument.", "keyno");
979			return;
980		}
981		if (!(md.md_keys & (1 << nkey)) && !force) {
982			gctl_error(req, "Master Key %u is not set.", nkey);
983			return;
984		}
985		md.md_keys &= ~(1 << nkey);
986		if (md.md_keys == 0 && !force) {
987			gctl_error(req, "This is the last Master Key. Use '-f' "
988			    "option if you really want to remove it.");
989			return;
990		}
991		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
992		arc4rand(mkeydst, G_ELI_MKEYLEN);
993	}
994
995	eli_metadata_store(req, prov, &md);
996	bzero(&md, sizeof(md));
997}
998
999static void
1000eli_delkey(struct gctl_req *req)
1001{
1002	const char *prov;
1003	int nargs;
1004
1005	nargs = gctl_get_int(req, "nargs");
1006	if (nargs != 1) {
1007		gctl_error(req, "Invalid number of arguments.");
1008		return;
1009	}
1010	prov = gctl_get_ascii(req, "arg0");
1011
1012	if (eli_is_attached(prov))
1013		eli_delkey_attached(req, prov);
1014	else
1015		eli_delkey_detached(req, prov);
1016}
1017
1018static void
1019eli_kill_detached(struct gctl_req *req, const char *prov)
1020{
1021	struct g_eli_metadata md;
1022	int error;
1023
1024	/*
1025	 * NOTE: Maybe we should verify if this is geli provider first,
1026	 *       but 'kill' command is quite critical so better don't waste
1027	 *       the time.
1028	 */
1029#if 0
1030	error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md),
1031	    G_ELI_MAGIC);
1032	if (error != 0) {
1033		gctl_error(req, "Cannot read metadata from %s: %s.", prov,
1034		    strerror(error));
1035		return;
1036	}
1037#endif
1038
1039	arc4rand((unsigned char *)&md, sizeof(md));
1040	error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md));
1041	if (error != 0) {
1042		gctl_error(req, "Cannot write metadata to %s: %s.", prov,
1043		    strerror(error));
1044	}
1045}
1046
1047static void
1048eli_kill(struct gctl_req *req)
1049{
1050	const char *prov;
1051	int i, nargs, all;
1052
1053	nargs = gctl_get_int(req, "nargs");
1054	all = gctl_get_int(req, "all");
1055	if (!all && nargs == 0) {
1056		gctl_error(req, "Too few arguments.");
1057		return;
1058	}
1059	/*
1060	 * How '-a' option combine with a list of providers:
1061	 * Delete Master Keys from all attached providers:
1062	 * geli kill -a
1063	 * Delete Master Keys from all attached providers and from
1064	 * detached da0 and da1:
1065	 * geli kill -a da0 da1
1066	 * Delete Master Keys from (attached or detached) da0 and da1:
1067	 * geli kill da0 da1
1068	 */
1069
1070	/* First detached providers. */
1071	for (i = 0; i < nargs; i++) {
1072		prov = gctl_get_ascii(req, "arg%d", i);
1073		if (!eli_is_attached(prov))
1074			eli_kill_detached(req, prov);
1075	}
1076	/* Now attached providers. */
1077	gctl_issue(req);
1078}
1079
1080static int
1081eli_backup_create(struct gctl_req *req, const char *prov, const char *file)
1082{
1083	struct g_eli_metadata md;
1084	unsigned secsize;
1085	unsigned char *sector;
1086	off_t mediasize;
1087	int filefd, provfd, ret;
1088
1089	ret = -1;
1090	provfd = filefd = -1;
1091	sector = NULL;
1092	secsize = 0;
1093
1094	provfd = open(prov, O_RDONLY);
1095	if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
1096		char devprov[MAXPATHLEN];
1097
1098		snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
1099		provfd = open(devprov, O_RDONLY);
1100	}
1101	if (provfd == -1) {
1102		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1103		goto out;
1104	}
1105	filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600);
1106	if (filefd == -1) {
1107		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1108		goto out;
1109	}
1110
1111	mediasize = g_get_mediasize(prov);
1112	secsize = g_get_sectorsize(prov);
1113	if (mediasize == 0 || secsize == 0) {
1114		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1115		    strerror(errno));
1116		goto out;
1117	}
1118
1119	sector = malloc(secsize);
1120	if (sector == NULL) {
1121		gctl_error(req, "Cannot allocate memory.");
1122		goto out;
1123	}
1124
1125	/* Read metadata from the provider. */
1126	if (pread(provfd, sector, secsize, mediasize - secsize) !=
1127	    (ssize_t)secsize) {
1128		gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
1129		goto out;
1130	}
1131	/* Check if this is geli provider. */
1132	if (eli_metadata_decode(sector, &md) != 0) {
1133		gctl_error(req, "MD5 hash mismatch: not a geli provider?");
1134		goto out;
1135	}
1136	/* Write metadata to the destination file. */
1137	if (write(filefd, sector, secsize) != (ssize_t)secsize) {
1138		gctl_error(req, "Cannot write to %s: %s.", file,
1139		    strerror(errno));
1140		goto out;
1141	}
1142	/* Success. */
1143	ret = 0;
1144out:
1145	if (provfd > 0)
1146		close(provfd);
1147	if (filefd > 0)
1148		close(filefd);
1149	if (sector != NULL) {
1150		bzero(sector, secsize);
1151		free(sector);
1152	}
1153	return (ret);
1154}
1155
1156static void
1157eli_backup(struct gctl_req *req)
1158{
1159	const char *file, *prov;
1160	int nargs;
1161
1162	nargs = gctl_get_int(req, "nargs");
1163	if (nargs != 2) {
1164		gctl_error(req, "Invalid number of arguments.");
1165		return;
1166	}
1167	prov = gctl_get_ascii(req, "arg0");
1168	file = gctl_get_ascii(req, "arg1");
1169
1170	eli_backup_create(req, prov, file);
1171}
1172
1173static void
1174eli_restore(struct gctl_req *req)
1175{
1176	struct g_eli_metadata md;
1177	const char *file, *prov;
1178	unsigned char *sector;
1179	ssize_t secsize;
1180	off_t mediasize;
1181	int nargs, filefd, provfd;
1182
1183	nargs = gctl_get_int(req, "nargs");
1184	if (nargs != 2) {
1185		gctl_error(req, "Invalid number of arguments.");
1186		return;
1187	}
1188	file = gctl_get_ascii(req, "arg0");
1189	prov = gctl_get_ascii(req, "arg1");
1190
1191	provfd = filefd = -1;
1192	sector = NULL;
1193	secsize = 0;
1194
1195	filefd = open(file, O_RDONLY);
1196	if (filefd == -1) {
1197		gctl_error(req, "Cannot open %s: %s.", file, strerror(errno));
1198		goto out;
1199	}
1200	provfd = g_open(prov, 1);
1201	if (provfd == -1) {
1202		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1203		goto out;
1204	}
1205
1206	mediasize = g_mediasize(provfd);
1207	secsize = g_sectorsize(provfd);
1208	if (mediasize == -1 || secsize == -1) {
1209		gctl_error(req, "Cannot get informations about %s: %s.", prov,
1210		    strerror(errno));
1211		goto out;
1212	}
1213
1214	sector = malloc(secsize);
1215	if (sector == NULL) {
1216		gctl_error(req, "Cannot allocate memory.");
1217		goto out;
1218	}
1219
1220	/* Read metadata from the backup file. */
1221	if (read(filefd, sector, secsize) != secsize) {
1222		gctl_error(req, "Cannot read from %s: %s.", file,
1223		    strerror(errno));
1224		goto out;
1225	}
1226	/* Check if this file contains geli metadata. */
1227	if (eli_metadata_decode(sector, &md) != 0) {
1228		gctl_error(req, "MD5 hash mismatch: not a geli backup file?");
1229		goto out;
1230	}
1231	/* Check if the provider size has changed since we did the backup. */
1232	if (md.md_provsize != (uint64_t)mediasize) {
1233		if (gctl_get_int(req, "force")) {
1234			md.md_provsize = mediasize;
1235			eli_metadata_encode(&md, sector);
1236		} else {
1237			gctl_error(req, "Provider size mismatch: "
1238			    "wrong backup file?");
1239			goto out;
1240		}
1241	}
1242	/* Write metadata from the provider. */
1243	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1244		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1245		goto out;
1246	}
1247	(void)g_flush(provfd);
1248out:
1249	if (provfd >= 0)
1250		(void)g_close(provfd);
1251	if (filefd >= 0)
1252		(void)close(filefd);
1253	if (sector != NULL) {
1254		bzero(sector, secsize);
1255		free(sector);
1256	}
1257}
1258
1259static void
1260eli_resize(struct gctl_req *req)
1261{
1262	struct g_eli_metadata md;
1263	const char *prov;
1264	unsigned char *sector;
1265	ssize_t secsize;
1266	off_t mediasize, oldsize;
1267	int nargs, provfd;
1268
1269	nargs = gctl_get_int(req, "nargs");
1270	if (nargs != 1) {
1271		gctl_error(req, "Invalid number of arguments.");
1272		return;
1273	}
1274	prov = gctl_get_ascii(req, "arg0");
1275
1276	provfd = -1;
1277	sector = NULL;
1278	secsize = 0;
1279
1280	provfd = g_open(prov, 1);
1281	if (provfd == -1) {
1282		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
1283		goto out;
1284	}
1285
1286	mediasize = g_mediasize(provfd);
1287	secsize = g_sectorsize(provfd);
1288	if (mediasize == -1 || secsize == -1) {
1289		gctl_error(req, "Cannot get information about %s: %s.", prov,
1290		    strerror(errno));
1291		goto out;
1292	}
1293
1294	sector = malloc(secsize);
1295	if (sector == NULL) {
1296		gctl_error(req, "Cannot allocate memory.");
1297		goto out;
1298	}
1299
1300	oldsize = gctl_get_intmax(req, "oldsize");
1301	if (oldsize < 0 || oldsize > mediasize) {
1302		gctl_error(req, "Invalid oldsize: Out of range.");
1303		goto out;
1304	}
1305	if (oldsize == mediasize) {
1306		gctl_error(req, "Size hasn't changed.");
1307		goto out;
1308	}
1309
1310	/* Read metadata from the 'oldsize' offset. */
1311	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
1312		gctl_error(req, "Cannot read old metadata: %s.",
1313		    strerror(errno));
1314		goto out;
1315	}
1316
1317	/* Check if this sector contains geli metadata. */
1318	if (eli_metadata_decode(sector, &md) != 0) {
1319		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
1320		goto out;
1321	}
1322
1323	/*
1324	 * If the old metadata doesn't have a correct provider size, refuse
1325	 * to resize.
1326	 */
1327	if (md.md_provsize != (uint64_t)oldsize) {
1328		gctl_error(req, "Provider size mismatch at oldsize.");
1329		goto out;
1330	}
1331
1332	/*
1333	 * Update the old metadata with the current provider size and write
1334	 * it back to the correct place on the provider.
1335	 */
1336	md.md_provsize = mediasize;
1337	eli_metadata_encode(&md, sector);
1338	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
1339		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
1340		goto out;
1341	}
1342	(void)g_flush(provfd);
1343
1344	/* Now trash the old metadata. */
1345	arc4rand(sector, secsize);
1346	if (pwrite(provfd, sector, secsize, oldsize - secsize) != secsize) {
1347		gctl_error(req, "Failed to clobber old metadata: %s.",
1348		    strerror(errno));
1349		goto out;
1350	}
1351out:
1352	if (provfd >= 0)
1353		(void)g_close(provfd);
1354	if (sector != NULL) {
1355		bzero(sector, secsize);
1356		free(sector);
1357	}
1358}
1359
1360static void
1361eli_clear(struct gctl_req *req)
1362{
1363	const char *name;
1364	int error, i, nargs;
1365
1366	nargs = gctl_get_int(req, "nargs");
1367	if (nargs < 1) {
1368		gctl_error(req, "Too few arguments.");
1369		return;
1370	}
1371
1372	for (i = 0; i < nargs; i++) {
1373		name = gctl_get_ascii(req, "arg%d", i);
1374		error = g_metadata_clear(name, G_ELI_MAGIC);
1375		if (error != 0) {
1376			fprintf(stderr, "Cannot clear metadata on %s: %s.\n",
1377			    name, strerror(error));
1378			gctl_error(req, "Not fully done.");
1379			continue;
1380		}
1381		if (verbose)
1382			printf("Metadata cleared on %s.\n", name);
1383	}
1384}
1385
1386static void
1387eli_dump(struct gctl_req *req)
1388{
1389	struct g_eli_metadata md, tmpmd;
1390	const char *name;
1391	int error, i, nargs;
1392
1393	nargs = gctl_get_int(req, "nargs");
1394	if (nargs < 1) {
1395		gctl_error(req, "Too few arguments.");
1396		return;
1397	}
1398
1399	for (i = 0; i < nargs; i++) {
1400		name = gctl_get_ascii(req, "arg%d", i);
1401		error = g_metadata_read(name, (unsigned char *)&tmpmd,
1402		    sizeof(tmpmd), G_ELI_MAGIC);
1403		if (error != 0) {
1404			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
1405			    name, strerror(error));
1406			gctl_error(req, "Not fully done.");
1407			continue;
1408		}
1409		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
1410			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
1411			    name);
1412			gctl_error(req, "Not fully done.");
1413			continue;
1414		}
1415		printf("Metadata on %s:\n", name);
1416		eli_metadata_dump(&md);
1417		printf("\n");
1418	}
1419}
1420