Home | History | Annotate | Line # | Download | only in cgdconfig
      1  1.63  christos /* $NetBSD: cgdconfig.c,v 1.63 2024/05/12 18:02:16 christos Exp $ */
      2   1.1     elric 
      3   1.1     elric /*-
      4   1.5     elric  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
      5   1.1     elric  * All rights reserved.
      6   1.1     elric  *
      7   1.1     elric  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1     elric  * by Roland C. Dowdeswell.
      9   1.1     elric  *
     10   1.1     elric  * Redistribution and use in source and binary forms, with or without
     11   1.1     elric  * modification, are permitted provided that the following conditions
     12   1.1     elric  * are met:
     13   1.1     elric  * 1. Redistributions of source code must retain the above copyright
     14   1.1     elric  *    notice, this list of conditions and the following disclaimer.
     15   1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17   1.1     elric  *    documentation and/or other materials provided with the distribution.
     18   1.1     elric  *
     19   1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1     elric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1     elric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1     elric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1     elric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1     elric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1     elric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1     elric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1     elric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1     elric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1     elric  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1     elric  */
     31   1.1     elric 
     32   1.1     elric #include <sys/cdefs.h>
     33   1.1     elric #ifndef lint
     34  1.24     lukem __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
     35  1.24     lukem  The NetBSD Foundation, Inc.  All rights reserved.");
     36  1.63  christos __RCSID("$NetBSD: cgdconfig.c,v 1.63 2024/05/12 18:02:16 christos Exp $");
     37   1.1     elric #endif
     38   1.1     elric 
     39  1.53       nia #ifdef HAVE_ARGON2
     40  1.53       nia #include <argon2.h>
     41  1.53       nia #endif
     42  1.56  riastrad #include <assert.h>
     43   1.5     elric #include <err.h>
     44   1.1     elric #include <errno.h>
     45   1.1     elric #include <fcntl.h>
     46   1.1     elric #include <libgen.h>
     47   1.1     elric #include <stdio.h>
     48   1.1     elric #include <stdlib.h>
     49   1.1     elric #include <string.h>
     50   1.1     elric #include <unistd.h>
     51   1.1     elric #include <util.h>
     52  1.35  christos #include <paths.h>
     53  1.35  christos #include <dirent.h>
     54   1.1     elric 
     55  1.54  riastrad /* base64 gunk */
     56  1.54  riastrad #include <netinet/in.h>
     57  1.54  riastrad #include <arpa/nameser.h>
     58  1.54  riastrad #include <resolv.h>
     59  1.54  riastrad 
     60   1.1     elric #include <sys/ioctl.h>
     61  1.41  christos #include <sys/stat.h>
     62  1.37   mlelstv #include <sys/bootblock.h>
     63   1.3     elric #include <sys/disklabel.h>
     64  1.37   mlelstv #include <sys/disklabel_gpt.h>
     65  1.14     elric #include <sys/mman.h>
     66   1.1     elric #include <sys/param.h>
     67  1.13     elric #include <sys/resource.h>
     68  1.34  christos #include <sys/statvfs.h>
     69  1.35  christos #include <sys/bitops.h>
     70  1.56  riastrad #include <sys/queue.h>
     71   1.1     elric 
     72   1.1     elric #include <dev/cgdvar.h>
     73   1.1     elric 
     74   1.5     elric #include <ufs/ffs/fs.h>
     75   1.5     elric 
     76  1.63  christos #ifdef HAVE_ZFS
     77  1.63  christos #include <sys/vdev_impl.h>
     78  1.63  christos #include <sha2.h>
     79  1.63  christos #endif
     80  1.63  christos 
     81   1.1     elric #include "params.h"
     82   1.1     elric #include "pkcs5_pbkdf2.h"
     83   1.1     elric #include "utils.h"
     84  1.28     pooka #include "cgdconfig.h"
     85  1.32     pooka #include "prog_ops.h"
     86  1.56  riastrad #include "hkdf_hmac_sha256.h"
     87   1.1     elric 
     88   1.1     elric #define CGDCONFIG_CFILE		CGDCONFIG_DIR "/cgd.conf"
     89   1.1     elric 
     90  1.17    cbiere enum action {
     91  1.17    cbiere 	 ACTION_DEFAULT,		/* default -> configure */
     92  1.17    cbiere 	 ACTION_CONFIGURE,		/* configure, with paramsfile */
     93  1.17    cbiere 	 ACTION_UNCONFIGURE,		/* unconfigure */
     94  1.17    cbiere 	 ACTION_GENERATE,		/* generate a paramsfile */
     95  1.17    cbiere 	 ACTION_GENERATE_CONVERT,	/* generate a ``dup'' paramsfile */
     96  1.17    cbiere 	 ACTION_CONFIGALL,		/* configure all from config file */
     97  1.17    cbiere 	 ACTION_UNCONFIGALL,		/* unconfigure all from config file */
     98  1.34  christos 	 ACTION_CONFIGSTDIN,		/* configure, key from stdin */
     99  1.54  riastrad 	 ACTION_LIST,			/* list configured devices */
    100  1.54  riastrad 	 ACTION_PRINTKEY,		/* print key to stdout */
    101  1.55  riastrad 	 ACTION_PRINTALLKEYS,		/* print all keys to stdout */
    102  1.17    cbiere };
    103   1.1     elric 
    104   1.1     elric /* if nflag is set, do not configure/unconfigure the cgd's */
    105   1.1     elric 
    106  1.63  christos static int	nflag = 0;
    107   1.1     elric 
    108  1.57  riastrad /* if Sflag is set, generate shared keys */
    109  1.57  riastrad 
    110  1.63  christos static int	Sflag = 0;
    111  1.57  riastrad 
    112  1.22     elric /* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
    113  1.22     elric 
    114  1.46     alnsn #define	PFLAG_GETPASS		0x01
    115  1.46     alnsn #define	PFLAG_GETPASS_ECHO	0x02
    116  1.46     alnsn #define	PFLAG_GETPASS_MASK	0x03
    117  1.46     alnsn #define	PFLAG_STDIN		0x04
    118  1.63  christos static int	pflag = PFLAG_GETPASS;
    119  1.22     elric 
    120  1.56  riastrad /*
    121  1.56  riastrad  * When configuring all cgds, save a cache of shared keys for key
    122  1.59  riastrad  * derivation.  If the _first_ verification with a shared key fails, we
    123  1.59  riastrad  * chuck it and start over; if _subsequent_ verifications fail, we
    124  1.59  riastrad  * assume the disk is wrong and give up on it immediately.
    125  1.56  riastrad  */
    126  1.56  riastrad 
    127  1.56  riastrad struct sharedkey {
    128  1.56  riastrad 	int			 alg;
    129  1.56  riastrad 	string_t		*id;
    130  1.56  riastrad 	bits_t			*key;
    131  1.56  riastrad 	LIST_ENTRY(sharedkey)	 list;
    132  1.59  riastrad 	SLIST_ENTRY(sharedkey)	 used;
    133  1.59  riastrad 	int			 verified;
    134  1.56  riastrad };
    135  1.63  christos static LIST_HEAD(, sharedkey) sharedkeys;
    136  1.59  riastrad SLIST_HEAD(sharedkeyhits, sharedkey);
    137  1.56  riastrad 
    138   1.3     elric static int	configure(int, char **, struct params *, int);
    139   1.1     elric static int	configure_stdin(struct params *, int argc, char **);
    140  1.57  riastrad static int	generate(struct params *, int, char **, const char *,
    141  1.57  riastrad 		    const char *);
    142  1.58  riastrad static int	generate_convert(struct params *, int, char **, const char *,
    143  1.58  riastrad 		    const char *);
    144   1.3     elric static int	unconfigure(int, char **, struct params *, int);
    145   1.3     elric static int	do_all(const char *, int, char **,
    146   1.3     elric 		       int (*)(int, char **, struct params *, int));
    147  1.34  christos static int	do_list(int, char **);
    148  1.55  riastrad static int	printkey(const char *, const char *, const char *, ...)
    149  1.55  riastrad 		    __printflike(3,4);
    150  1.55  riastrad static int	printkey1(int, char **, struct params *, int);
    151  1.54  riastrad static int	do_printkey(int, char **);
    152   1.1     elric 
    153   1.1     elric #define CONFIG_FLAGS_FROMALL	1	/* called from configure_all() */
    154   1.1     elric #define CONFIG_FLAGS_FROMMAIN	2	/* called from main() */
    155   1.1     elric 
    156   1.2     elric static int	 configure_params(int, const char *, const char *,
    157   1.2     elric 				  struct params *);
    158  1.13     elric static void	 eliminate_cores(void);
    159  1.59  riastrad static bits_t	*getkey(const char *, struct keygen *, size_t,
    160  1.59  riastrad 		     struct sharedkeyhits *);
    161  1.19  christos static bits_t	*getkey_storedkey(const char *, struct keygen *, size_t);
    162  1.19  christos static bits_t	*getkey_randomkey(const char *, struct keygen *, size_t, int);
    163  1.53       nia #ifdef HAVE_ARGON2
    164  1.53       nia static bits_t	*getkey_argon2id(const char *, struct keygen *, size_t);
    165  1.53       nia #endif
    166  1.23     elric static bits_t	*getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t,
    167  1.23     elric 				     int);
    168  1.23     elric static bits_t	*getkey_shell_cmd(const char *, struct keygen *, size_t);
    169  1.22     elric static char	*maybe_getpass(char *);
    170  1.17    cbiere static int	 opendisk_werror(const char *, char *, size_t);
    171   1.3     elric static int	 unconfigure_fd(int);
    172   1.3     elric static int	 verify(struct params *, int);
    173   1.5     elric static int	 verify_disklabel(int);
    174   1.5     elric static int	 verify_ffs(int);
    175   1.9        cb static int	 verify_reenter(struct params *);
    176  1.37   mlelstv static int	 verify_mbr(int);
    177  1.37   mlelstv static int	 verify_gpt(int);
    178  1.63  christos #ifdef HAVE_ZFS
    179  1.63  christos static int	 verify_zfs(int);
    180  1.63  christos #endif
    181   1.1     elric 
    182  1.33     joerg __dead static void	 usage(void);
    183   1.1     elric 
    184   1.1     elric /* Verbose Framework */
    185  1.63  christos static unsigned	verbose = 0;
    186   1.1     elric 
    187   1.1     elric #define VERBOSE(x,y)	if (verbose >= x) y
    188  1.19  christos #define VPRINTF(x,y)	if (verbose >= x) (void)printf y
    189   1.1     elric 
    190   1.1     elric static void
    191   1.1     elric usage(void)
    192   1.1     elric {
    193   1.1     elric 
    194  1.46     alnsn 	(void)fprintf(stderr, "usage: %s [-enpv] [-V vmeth] cgd dev "
    195  1.45       kre 	    "[paramsfile]\n", getprogname());
    196  1.46     alnsn 	(void)fprintf(stderr, "       %s -C [-enpv] [-f configfile]\n",
    197   1.1     elric 	    getprogname());
    198  1.58  riastrad 	(void)fprintf(stderr, "       %s -G [-enpSv] [-i ivmeth] [-k kgmeth] "
    199  1.58  riastrad 	    "[-P paramsfile] [-o outfile] paramsfile\n", getprogname());
    200  1.57  riastrad 	(void)fprintf(stderr, "       %s -g [-Sv] [-i ivmeth] [-k kgmeth] "
    201  1.57  riastrad 	    "[-P paramsfile] [-o outfile] alg [keylen]\n", getprogname());
    202  1.45       kre 	(void)fprintf(stderr, "       %s -l [-v[v]] [cgd]\n", getprogname());
    203  1.19  christos 	(void)fprintf(stderr, "       %s -s [-nv] [-i ivmeth] cgd dev alg "
    204   1.1     elric 	    "[keylen]\n", getprogname());
    205  1.54  riastrad 	(void)fprintf(stderr, "       %s -t paramsfile\n", getprogname());
    206  1.55  riastrad 	(void)fprintf(stderr, "       %s -T [-f configfile]\n", getprogname());
    207  1.45       kre 	(void)fprintf(stderr, "       %s -U [-nv] [-f configfile]\n",
    208  1.45       kre 	    getprogname());
    209  1.19  christos 	(void)fprintf(stderr, "       %s -u [-nv] cgd\n", getprogname());
    210  1.17    cbiere 	exit(EXIT_FAILURE);
    211  1.17    cbiere }
    212  1.17    cbiere 
    213  1.17    cbiere static int
    214  1.19  christos parse_size_t(const char *s, size_t *l)
    215  1.17    cbiere {
    216  1.17    cbiere 	char *endptr;
    217  1.17    cbiere 	long v;
    218  1.17    cbiere 
    219  1.17    cbiere 	errno = 0;
    220  1.17    cbiere 	v = strtol(s, &endptr, 10);
    221  1.17    cbiere 	if ((v == LONG_MIN || v == LONG_MAX) && errno)
    222  1.17    cbiere 		return -1;
    223  1.17    cbiere 	if (v < INT_MIN || v > INT_MAX) {
    224  1.17    cbiere 		errno = ERANGE;
    225  1.17    cbiere 		return -1;
    226  1.17    cbiere 	}
    227  1.17    cbiere 	if (endptr == s) {
    228  1.17    cbiere 		errno = EINVAL;
    229  1.17    cbiere 		return -1;
    230  1.17    cbiere 	}
    231  1.19  christos 	*l = (size_t)v;
    232  1.19  christos 	return 0;
    233  1.17    cbiere }
    234  1.17    cbiere 
    235  1.17    cbiere static void
    236  1.17    cbiere set_action(enum action *action, enum action value)
    237  1.17    cbiere {
    238  1.17    cbiere 	if (*action != ACTION_DEFAULT)
    239  1.17    cbiere 		usage();
    240  1.17    cbiere 	*action = value;
    241   1.1     elric }
    242   1.1     elric 
    243   1.1     elric int
    244   1.1     elric main(int argc, char **argv)
    245   1.1     elric {
    246   1.5     elric 	struct params *p;
    247   1.5     elric 	struct params *tp;
    248   1.5     elric 	struct keygen *kg;
    249  1.17    cbiere 	enum action action = ACTION_DEFAULT;
    250   1.1     elric 	int	ch;
    251  1.17    cbiere 	const char	*cfile = NULL;
    252  1.17    cbiere 	const char	*outfile = NULL;
    253  1.57  riastrad 	const char	*Pfile = NULL;
    254   1.1     elric 
    255  1.15     elric 	setprogname(*argv);
    256  1.56  riastrad 	if (hkdf_hmac_sha256_selftest())
    257  1.56  riastrad 		err(EXIT_FAILURE, "Crypto self-test failed");
    258  1.13     elric 	eliminate_cores();
    259  1.14     elric 	if (mlockall(MCL_FUTURE))
    260  1.14     elric 		err(EXIT_FAILURE, "Can't lock memory");
    261   1.5     elric 	p = params_new();
    262   1.5     elric 	kg = NULL;
    263   1.1     elric 
    264  1.57  riastrad 	while ((ch = getopt(argc, argv, "CGP:STUV:b:ef:gi:k:lno:sptuv")) != -1)
    265   1.1     elric 		switch (ch) {
    266   1.1     elric 		case 'C':
    267  1.17    cbiere 			set_action(&action, ACTION_CONFIGALL);
    268   1.1     elric 			break;
    269   1.5     elric 		case 'G':
    270  1.17    cbiere 			set_action(&action, ACTION_GENERATE_CONVERT);
    271   1.5     elric 			break;
    272  1.57  riastrad 		case 'P':
    273  1.57  riastrad 			if (Pfile)
    274  1.57  riastrad 				usage();
    275  1.57  riastrad 			Pfile = estrdup(optarg);
    276  1.57  riastrad 			break;
    277  1.57  riastrad 		case 'S':
    278  1.57  riastrad 			Sflag = 1;
    279  1.57  riastrad 			break;
    280  1.55  riastrad 		case 'T':
    281  1.55  riastrad 			set_action(&action, ACTION_PRINTALLKEYS);
    282  1.55  riastrad 			break;
    283   1.1     elric 		case 'U':
    284  1.17    cbiere 			set_action(&action, ACTION_UNCONFIGALL);
    285   1.1     elric 			break;
    286   1.3     elric 		case 'V':
    287   1.5     elric 			tp = params_verify_method(string_fromcharstar(optarg));
    288   1.5     elric 			if (!tp)
    289   1.3     elric 				usage();
    290   1.5     elric 			p = params_combine(p, tp);
    291   1.3     elric 			break;
    292   1.1     elric 		case 'b':
    293  1.17    cbiere 			{
    294  1.19  christos 				size_t size;
    295  1.17    cbiere 
    296  1.19  christos 				if (parse_size_t(optarg, &size) == -1)
    297  1.17    cbiere 					usage();
    298  1.17    cbiere 				tp = params_bsize(size);
    299  1.17    cbiere 				if (!tp)
    300  1.17    cbiere 					usage();
    301  1.17    cbiere 				p = params_combine(p, tp);
    302  1.17    cbiere 			}
    303   1.1     elric 			break;
    304  1.46     alnsn 		case 'e':
    305  1.46     alnsn 			pflag = PFLAG_GETPASS_ECHO;
    306  1.46     alnsn 			break;
    307   1.1     elric 		case 'f':
    308  1.17    cbiere 			if (cfile)
    309  1.17    cbiere 				usage();
    310  1.17    cbiere 			cfile = estrdup(optarg);
    311   1.1     elric 			break;
    312   1.1     elric 		case 'g':
    313  1.17    cbiere 			set_action(&action, ACTION_GENERATE);
    314   1.1     elric 			break;
    315   1.1     elric 		case 'i':
    316   1.5     elric 			tp = params_ivmeth(string_fromcharstar(optarg));
    317   1.5     elric 			p = params_combine(p, tp);
    318   1.1     elric 			break;
    319   1.1     elric 		case 'k':
    320   1.5     elric 			kg = keygen_method(string_fromcharstar(optarg));
    321   1.5     elric 			if (!kg)
    322   1.1     elric 				usage();
    323   1.5     elric 			keygen_addlist(&p->keygen, kg);
    324   1.1     elric 			break;
    325  1.34  christos 		case 'l':
    326  1.34  christos 			set_action(&action, ACTION_LIST);
    327  1.34  christos 			break;
    328   1.1     elric 		case 'n':
    329   1.1     elric 			nflag = 1;
    330   1.1     elric 			break;
    331   1.1     elric 		case 'o':
    332  1.17    cbiere 			if (outfile)
    333  1.17    cbiere 				usage();
    334  1.17    cbiere 			outfile = estrdup(optarg);
    335   1.1     elric 			break;
    336  1.22     elric 		case 'p':
    337  1.22     elric 			pflag = PFLAG_STDIN;
    338  1.22     elric 			break;
    339   1.1     elric 		case 's':
    340  1.17    cbiere 			set_action(&action, ACTION_CONFIGSTDIN);
    341   1.1     elric 			break;
    342  1.54  riastrad 		case 't':
    343  1.54  riastrad 			set_action(&action, ACTION_PRINTKEY);
    344  1.54  riastrad 			break;
    345   1.1     elric 		case 'u':
    346  1.17    cbiere 			set_action(&action, ACTION_UNCONFIGURE);
    347   1.1     elric 			break;
    348   1.1     elric 		case 'v':
    349   1.1     elric 			verbose++;
    350   1.1     elric 			break;
    351   1.1     elric 		default:
    352   1.1     elric 			usage();
    353   1.1     elric 			/* NOTREACHED */
    354   1.1     elric 		}
    355   1.1     elric 
    356   1.1     elric 	argc -= optind;
    357   1.1     elric 	argv += optind;
    358   1.1     elric 
    359  1.17    cbiere 	if (!outfile)
    360  1.17    cbiere 		outfile = "";
    361  1.17    cbiere 	if (!cfile)
    362  1.17    cbiere 		cfile = "";
    363  1.17    cbiere 
    364  1.32     pooka 	if (prog_init && prog_init() == -1)
    365  1.32     pooka 		err(1, "init failed");
    366  1.32     pooka 
    367   1.1     elric 	/* validate the consistency of the arguments */
    368  1.58  riastrad 	if (Pfile != NULL &&
    369  1.58  riastrad 	    action != ACTION_GENERATE &&
    370  1.58  riastrad 	    action != ACTION_GENERATE_CONVERT) {
    371  1.58  riastrad 		warnx("-P is only for use with -g/-G action");
    372  1.57  riastrad 		usage();
    373  1.57  riastrad 	}
    374  1.57  riastrad 	if (Pfile != NULL && !Sflag) {
    375  1.57  riastrad 		warnx("-P only makes sense with -S flag");
    376  1.57  riastrad 	}
    377  1.58  riastrad 	if (Sflag &&
    378  1.58  riastrad 	    action != ACTION_GENERATE &&
    379  1.58  riastrad 	    action != ACTION_GENERATE_CONVERT) {
    380  1.58  riastrad 		warnx("-S is only for use with -g/-G action");
    381  1.57  riastrad 		usage();
    382  1.57  riastrad 	}
    383   1.1     elric 
    384   1.1     elric 	switch (action) {
    385  1.17    cbiere 	case ACTION_DEFAULT:	/* ACTION_CONFIGURE is the default */
    386   1.1     elric 	case ACTION_CONFIGURE:
    387   1.5     elric 		return configure(argc, argv, p, CONFIG_FLAGS_FROMMAIN);
    388   1.1     elric 	case ACTION_UNCONFIGURE:
    389   1.3     elric 		return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
    390   1.1     elric 	case ACTION_GENERATE:
    391  1.57  riastrad 		return generate(p, argc, argv, outfile, Pfile);
    392   1.5     elric 	case ACTION_GENERATE_CONVERT:
    393  1.58  riastrad 		return generate_convert(p, argc, argv, outfile, Pfile);
    394   1.1     elric 	case ACTION_CONFIGALL:
    395   1.1     elric 		return do_all(cfile, argc, argv, configure);
    396   1.1     elric 	case ACTION_UNCONFIGALL:
    397   1.1     elric 		return do_all(cfile, argc, argv, unconfigure);
    398   1.1     elric 	case ACTION_CONFIGSTDIN:
    399   1.5     elric 		return configure_stdin(p, argc, argv);
    400  1.34  christos 	case ACTION_LIST:
    401  1.34  christos 		return do_list(argc, argv);
    402  1.54  riastrad 	case ACTION_PRINTKEY:
    403  1.54  riastrad 		return do_printkey(argc, argv);
    404  1.55  riastrad 	case ACTION_PRINTALLKEYS:
    405  1.55  riastrad 		return do_all(cfile, argc, argv, printkey1);
    406  1.19  christos 	default:
    407  1.19  christos 		errx(EXIT_FAILURE, "undefined action");
    408  1.19  christos 		/* NOTREACHED */
    409   1.1     elric 	}
    410   1.1     elric }
    411   1.1     elric 
    412   1.5     elric static bits_t *
    413  1.56  riastrad getsubkey_hkdf_hmac_sha256(bits_t *key, bits_t *info, size_t subkeylen)
    414  1.56  riastrad {
    415  1.56  riastrad 	bits_t		*ret = NULL;
    416  1.56  riastrad 	uint8_t		*tmp;
    417  1.56  riastrad 
    418  1.56  riastrad 	tmp = emalloc(BITS2BYTES(subkeylen));
    419  1.56  riastrad 	if (hkdf_hmac_sha256(tmp, BITS2BYTES(subkeylen),
    420  1.56  riastrad 		bits_getbuf(key), BITS2BYTES(bits_len(key)),
    421  1.56  riastrad 		bits_getbuf(info), BITS2BYTES(bits_len(info)))) {
    422  1.56  riastrad 		warnx("failed to derive HKDF-HMAC-SHA256 subkey");
    423  1.56  riastrad 		goto out;
    424  1.56  riastrad 	}
    425  1.56  riastrad 
    426  1.56  riastrad 	ret = bits_new(tmp, subkeylen);
    427  1.56  riastrad 
    428  1.56  riastrad out:	free(tmp);
    429  1.56  riastrad 	return ret;
    430  1.56  riastrad }
    431  1.56  riastrad 
    432  1.56  riastrad static bits_t *
    433  1.56  riastrad getsubkey(int alg, bits_t *key, bits_t *info, size_t subkeylen)
    434  1.56  riastrad {
    435  1.56  riastrad 
    436  1.56  riastrad 	switch (alg) {
    437  1.56  riastrad 	case SHARED_ALG_HKDF_HMAC_SHA256:
    438  1.56  riastrad 		return getsubkey_hkdf_hmac_sha256(key, info, subkeylen);
    439  1.56  riastrad 	default:
    440  1.56  riastrad 		warnx("unrecognised shared key derivation method %d", alg);
    441  1.56  riastrad 		return NULL;
    442  1.56  riastrad 	}
    443  1.56  riastrad }
    444  1.56  riastrad 
    445  1.56  riastrad static bits_t *
    446  1.59  riastrad getkey(const char *dev, struct keygen *kg, size_t len0,
    447  1.59  riastrad     struct sharedkeyhits *skh)
    448   1.1     elric {
    449   1.5     elric 	bits_t	*ret = NULL;
    450   1.5     elric 	bits_t	*tmp;
    451   1.1     elric 
    452  1.56  riastrad 	VPRINTF(3, ("getkey(\"%s\", %p, %zu) called\n", dev, kg, len0));
    453   1.5     elric 	for (; kg; kg=kg->next) {
    454  1.56  riastrad 		struct sharedkey *sk = NULL;
    455  1.56  riastrad 		size_t len = len0;
    456  1.56  riastrad 
    457  1.56  riastrad 		/*
    458  1.56  riastrad 		 * If shared, determine the shared key's length and
    459  1.56  riastrad 		 * probe the cache of shared keys.
    460  1.56  riastrad 		 */
    461  1.56  riastrad 		if (kg->kg_sharedid) {
    462  1.56  riastrad 			const char *id = string_tocharstar(kg->kg_sharedid);
    463  1.56  riastrad 
    464  1.56  riastrad 			len = kg->kg_sharedlen;
    465  1.56  riastrad 			LIST_FOREACH(sk, &sharedkeys, list) {
    466  1.56  riastrad 				if (kg->kg_sharedalg == sk->alg &&
    467  1.56  riastrad 				    kg->kg_sharedlen == bits_len(sk->key) &&
    468  1.56  riastrad 				    strcmp(id, string_tocharstar(sk->id)) == 0)
    469  1.56  riastrad 					break;
    470  1.56  riastrad 			}
    471  1.56  riastrad 			if (sk) {
    472  1.56  riastrad 				tmp = sk->key;
    473  1.56  riastrad 				goto derive;
    474  1.56  riastrad 			}
    475  1.56  riastrad 		}
    476  1.56  riastrad 
    477   1.5     elric 		switch (kg->kg_method) {
    478   1.5     elric 		case KEYGEN_STOREDKEY:
    479   1.5     elric 			tmp = getkey_storedkey(dev, kg, len);
    480   1.5     elric 			break;
    481   1.5     elric 		case KEYGEN_RANDOMKEY:
    482  1.12        tv 			tmp = getkey_randomkey(dev, kg, len, 1);
    483  1.12        tv 			break;
    484  1.12        tv 		case KEYGEN_URANDOMKEY:
    485  1.12        tv 			tmp = getkey_randomkey(dev, kg, len, 0);
    486   1.5     elric 			break;
    487  1.53       nia #ifdef HAVE_ARGON2
    488  1.53       nia 		case KEYGEN_ARGON2ID:
    489  1.53       nia 			tmp = getkey_argon2id(dev, kg, len);
    490  1.53       nia 			break;
    491  1.53       nia #endif
    492  1.10       dan 		case KEYGEN_PKCS5_PBKDF2_SHA1:
    493  1.10       dan 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0);
    494  1.10       dan 			break;
    495  1.10       dan 		/* provide backwards compatibility for old config files */
    496  1.10       dan 		case KEYGEN_PKCS5_PBKDF2_OLD:
    497  1.10       dan 			tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 1);
    498   1.5     elric 			break;
    499  1.23     elric 		case KEYGEN_SHELL_CMD:
    500  1.23     elric 			tmp = getkey_shell_cmd(dev, kg, len);
    501  1.23     elric 			break;
    502   1.5     elric 		default:
    503   1.5     elric 			warnx("unrecognised keygen method %d in getkey()",
    504   1.5     elric 			    kg->kg_method);
    505   1.5     elric 			if (ret)
    506   1.5     elric 				bits_free(ret);
    507   1.5     elric 			return NULL;
    508   1.5     elric 		}
    509   1.5     elric 
    510  1.56  riastrad 		/*
    511  1.56  riastrad 		 * If shared, cache the key.
    512  1.56  riastrad 		 */
    513  1.56  riastrad 		if (kg->kg_sharedid) {
    514  1.56  riastrad 			assert(sk == NULL);
    515  1.56  riastrad 			sk = ecalloc(1, sizeof(*sk));
    516  1.56  riastrad 			sk->alg = kg->kg_sharedalg;
    517  1.56  riastrad 			sk->id = string_dup(kg->kg_sharedid);
    518  1.56  riastrad 			sk->key = tmp;
    519  1.56  riastrad 			LIST_INSERT_HEAD(&sharedkeys, sk, list);
    520  1.59  riastrad 			sk->verified = 0;
    521  1.56  riastrad 		}
    522  1.56  riastrad 
    523  1.56  riastrad derive:		if (kg->kg_sharedid) {
    524  1.59  riastrad 			assert(sk != NULL);
    525  1.56  riastrad 			/*
    526  1.56  riastrad 			 * tmp holds the master key, owned by the
    527  1.56  riastrad 			 * struct sharedkey record; replace it by the
    528  1.56  riastrad 			 * derived subkey.
    529  1.56  riastrad 			 */
    530  1.56  riastrad 			tmp = getsubkey(kg->kg_sharedalg, tmp,
    531  1.56  riastrad 			    kg->kg_sharedinfo, len0);
    532  1.56  riastrad 			if (tmp == NULL) {
    533  1.56  riastrad 				if (ret)
    534  1.56  riastrad 					bits_free(ret);
    535  1.56  riastrad 				return NULL;
    536  1.56  riastrad 			}
    537  1.59  riastrad 			if (skh)
    538  1.59  riastrad 				SLIST_INSERT_HEAD(skh, sk, used);
    539  1.56  riastrad 		}
    540   1.5     elric 		if (ret)
    541   1.5     elric 			ret = bits_xor_d(tmp, ret);
    542   1.5     elric 		else
    543   1.5     elric 			ret = tmp;
    544   1.1     elric 	}
    545   1.5     elric 
    546   1.5     elric 	return ret;
    547   1.5     elric }
    548   1.5     elric 
    549   1.5     elric /*ARGSUSED*/
    550   1.5     elric static bits_t *
    551  1.19  christos getkey_storedkey(const char *target, struct keygen *kg, size_t keylen)
    552   1.5     elric {
    553   1.5     elric 	return bits_dup(kg->kg_key);
    554   1.1     elric }
    555   1.1     elric 
    556   1.5     elric /*ARGSUSED*/
    557   1.5     elric static bits_t *
    558  1.19  christos getkey_randomkey(const char *target, struct keygen *kg, size_t keylen, int hard)
    559   1.1     elric {
    560  1.12        tv 	return bits_getrandombits(keylen, hard);
    561   1.1     elric }
    562   1.1     elric 
    563  1.22     elric static char *
    564  1.22     elric maybe_getpass(char *prompt)
    565  1.22     elric {
    566  1.22     elric 	char	 buf[1024];
    567  1.46     alnsn 	char	*p = NULL;
    568  1.46     alnsn 	char	*tmp, *pass;
    569  1.22     elric 
    570  1.22     elric 	switch (pflag) {
    571  1.22     elric 	case PFLAG_GETPASS:
    572  1.46     alnsn 		p = getpass_r(prompt, buf, sizeof(buf));
    573  1.46     alnsn 		break;
    574  1.46     alnsn 
    575  1.46     alnsn 	case PFLAG_GETPASS_ECHO:
    576  1.46     alnsn 		p = getpassfd(prompt, buf, sizeof(buf), NULL,
    577  1.46     alnsn 		    GETPASS_ECHO|GETPASS_ECHO_NL|GETPASS_NEED_TTY, 0);
    578  1.22     elric 		break;
    579  1.22     elric 
    580  1.22     elric 	case PFLAG_STDIN:
    581  1.22     elric 		p = fgets(buf, sizeof(buf), stdin);
    582  1.22     elric 		if (p) {
    583  1.22     elric 			tmp = strchr(p, '\n');
    584  1.22     elric 			if (tmp)
    585  1.22     elric 				*tmp = '\0';
    586  1.22     elric 		}
    587  1.22     elric 		break;
    588  1.22     elric 
    589  1.22     elric 	default:
    590  1.22     elric 		errx(EXIT_FAILURE, "pflag set inappropriately?");
    591  1.22     elric 	}
    592  1.22     elric 
    593  1.22     elric 	if (!p)
    594  1.22     elric 		err(EXIT_FAILURE, "failed to read passphrase");
    595  1.22     elric 
    596  1.46     alnsn 	pass = estrdup(p);
    597  1.48     alnsn 	explicit_memset(buf, 0, sizeof(buf));
    598  1.46     alnsn 
    599  1.46     alnsn 	return pass;
    600  1.22     elric }
    601  1.22     elric 
    602   1.5     elric /*ARGSUSED*/
    603  1.29     elric /*
    604  1.10       dan  * XXX take, and pass through, a compat flag that indicates whether we
    605  1.10       dan  * provide backwards compatibility with a previous bug.  The previous
    606  1.10       dan  * behaviour is indicated by the keygen method pkcs5_pbkdf2, and a
    607  1.10       dan  * non-zero compat flag. The new default, and correct keygen method is
    608  1.10       dan  * called pcks5_pbkdf2/sha1.  When the old method is removed, so will
    609  1.10       dan  * be the compat argument.
    610  1.10       dan  */
    611   1.5     elric static bits_t *
    612  1.19  christos getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen,
    613  1.19  christos     int compat)
    614   1.1     elric {
    615   1.5     elric 	bits_t		*ret;
    616  1.25  dholland 	char		*passp;
    617   1.5     elric 	char		 buf[1024];
    618   1.5     elric 	u_int8_t	*tmp;
    619   1.1     elric 
    620  1.46     alnsn 	snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
    621  1.46     alnsn 	    pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
    622  1.25  dholland 	passp = maybe_getpass(buf);
    623  1.25  dholland 	if (pkcs5_pbkdf2(&tmp, BITS2BYTES(keylen), (uint8_t *)passp,
    624  1.25  dholland 	    strlen(passp),
    625   1.5     elric 	    bits_getbuf(kg->kg_salt), BITS2BYTES(bits_len(kg->kg_salt)),
    626  1.10       dan 	    kg->kg_iterations, compat)) {
    627   1.5     elric 		warnx("failed to generate PKCS#5 PBKDF2 key");
    628   1.5     elric 		return NULL;
    629   1.5     elric 	}
    630   1.5     elric 
    631   1.5     elric 	ret = bits_new(tmp, keylen);
    632   1.9        cb 	kg->kg_key = bits_dup(ret);
    633  1.48     alnsn 	explicit_memset(passp, 0, strlen(passp));
    634  1.22     elric 	free(passp);
    635   1.5     elric 	free(tmp);
    636   1.1     elric 	return ret;
    637   1.1     elric }
    638   1.1     elric 
    639  1.53       nia #ifdef HAVE_ARGON2
    640  1.53       nia static bits_t *
    641  1.53       nia getkey_argon2id(const char *target, struct keygen *kg, size_t keylen)
    642  1.53       nia {
    643  1.53       nia 	bits_t *ret;
    644  1.53       nia 	char *passp;
    645  1.53       nia 	char buf[1024];
    646  1.53       nia 	uint8_t	raw[256];
    647  1.63  christos 	int error;
    648  1.53       nia 
    649  1.53       nia 	snprintf(buf, sizeof(buf), "%s's passphrase%s:", target,
    650  1.53       nia 	    pflag & PFLAG_GETPASS_ECHO ? " (echo)" : "");
    651  1.53       nia 	passp = maybe_getpass(buf);
    652  1.63  christos 	if ((error = argon2_hash(kg->kg_iterations, kg->kg_memory,
    653  1.53       nia 	    kg->kg_parallelism,
    654  1.53       nia 	    passp, strlen(passp),
    655  1.53       nia 	    bits_getbuf(kg->kg_salt),
    656  1.53       nia 	    BITS2BYTES(bits_len(kg->kg_salt)),
    657  1.53       nia 	    raw, sizeof(raw),
    658  1.53       nia 	    NULL, 0,
    659  1.53       nia 	    Argon2_id, kg->kg_version)) != ARGON2_OK) {
    660  1.63  christos 		warnx("failed to generate Argon2id key, error code %d", error);
    661  1.53       nia 		return NULL;
    662  1.53       nia 	}
    663  1.53       nia 
    664  1.53       nia 	ret = bits_new(raw, keylen);
    665  1.53       nia 	kg->kg_key = bits_dup(ret);
    666  1.53       nia 	explicit_memset(passp, 0, strlen(passp));
    667  1.53       nia 	explicit_memset(raw, 0, sizeof(raw));
    668  1.53       nia 	free(passp);
    669  1.53       nia 	return ret;
    670  1.53       nia }
    671  1.53       nia #endif
    672  1.53       nia 
    673   1.5     elric /*ARGSUSED*/
    674  1.23     elric static bits_t *
    675  1.23     elric getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen)
    676  1.23     elric {
    677  1.23     elric 	FILE	*f;
    678  1.23     elric 	bits_t	*ret;
    679  1.52  riastrad 	int	status;
    680  1.23     elric 
    681  1.52  riastrad 	if ((f = popen(string_tocharstar(kg->kg_cmd), "r")) == NULL)
    682  1.52  riastrad 		errx(1, "command failed");
    683  1.52  riastrad 	if ((ret = bits_fget(f, keylen)) == NULL)
    684  1.52  riastrad 		errx(1, "command output too short");
    685  1.52  riastrad 	if ((status = pclose(f)) != 0)
    686  1.52  riastrad 		err(1, "command failed with status %d", status);
    687  1.23     elric 
    688  1.23     elric 	return ret;
    689  1.23     elric }
    690  1.23     elric 
    691  1.23     elric /*ARGSUSED*/
    692   1.1     elric static int
    693   1.3     elric unconfigure(int argc, char **argv, struct params *inparams, int flags)
    694   1.1     elric {
    695   1.1     elric 	int	fd;
    696   1.1     elric 	int	ret;
    697   1.1     elric 	char	buf[MAXPATHLEN] = "";
    698   1.1     elric 
    699   1.1     elric 	/* only complain about additional arguments, if called from main() */
    700   1.1     elric 	if (flags == CONFIG_FLAGS_FROMMAIN && argc != 1)
    701   1.1     elric 		usage();
    702   1.1     elric 
    703   1.1     elric 	/* if called from do_all(), then ensure that 2 or 3 args exist */
    704   1.1     elric 	if (flags == CONFIG_FLAGS_FROMALL && (argc < 2 || argc > 3))
    705   1.1     elric 		return -1;
    706   1.1     elric 
    707  1.32     pooka 	fd = opendisk1(*argv, O_RDWR, buf, sizeof(buf), 1, prog_open);
    708   1.1     elric 	if (fd == -1) {
    709  1.17    cbiere 		int saved_errno = errno;
    710  1.17    cbiere 
    711   1.5     elric 		warn("can't open cgd \"%s\", \"%s\"", *argv, buf);
    712   1.1     elric 
    713   1.1     elric 		/* this isn't fatal with nflag != 0 */
    714   1.1     elric 		if (!nflag)
    715  1.17    cbiere 			return saved_errno;
    716   1.1     elric 	}
    717   1.1     elric 
    718   1.1     elric 	VPRINTF(1, ("%s (%s): clearing\n", *argv, buf));
    719   1.1     elric 
    720   1.1     elric 	if (nflag)
    721   1.1     elric 		return 0;
    722   1.1     elric 
    723   1.3     elric 	ret = unconfigure_fd(fd);
    724  1.32     pooka 	(void)prog_close(fd);
    725   1.3     elric 	return ret;
    726   1.3     elric }
    727   1.3     elric 
    728   1.3     elric static int
    729   1.3     elric unconfigure_fd(int fd)
    730   1.3     elric {
    731   1.3     elric 	struct	cgd_ioctl ci;
    732   1.3     elric 
    733  1.32     pooka 	if (prog_ioctl(fd, CGDIOCCLR, &ci) == -1) {
    734  1.17    cbiere 		warn("ioctl");
    735   1.3     elric 		return -1;
    736   1.1     elric 	}
    737   1.1     elric 
    738   1.1     elric 	return 0;
    739   1.1     elric }
    740   1.1     elric 
    741   1.5     elric /*ARGSUSED*/
    742   1.1     elric static int
    743   1.3     elric configure(int argc, char **argv, struct params *inparams, int flags)
    744   1.1     elric {
    745   1.5     elric 	struct params	*p;
    746  1.22     elric 	struct keygen	*kg;
    747   1.5     elric 	int		 fd;
    748  1.22     elric 	int		 loop = 0;
    749   1.5     elric 	int		 ret;
    750   1.5     elric 	char		 cgdname[PATH_MAX];
    751  1.38  christos 	char		 devicename[PATH_MAX];
    752  1.39  christos 	const char	*dev = NULL;	/* XXX: gcc */
    753  1.36   mlelstv 
    754  1.44       kre 	if (argc < 2 || argc > 3) {
    755  1.44       kre 		/* print usage and exit, only if called from main() */
    756  1.44       kre 		if (flags == CONFIG_FLAGS_FROMMAIN) {
    757  1.44       kre 			warnx("wrong number of args");
    758  1.44       kre 			usage();
    759  1.44       kre 		}
    760  1.44       kre 		return -1;
    761  1.44       kre 	}
    762  1.44       kre 
    763  1.42       kre 	if ((
    764  1.42       kre 	  fd = opendisk1(*argv, O_RDWR, cgdname, sizeof(cgdname), 1, prog_open)
    765  1.42       kre 	    ) != -1) {
    766  1.42       kre 		struct cgd_user cgu;
    767  1.42       kre 
    768  1.42       kre 		cgu.cgu_unit = -1;
    769  1.42       kre 		if (prog_ioctl(fd, CGDIOCGET, &cgu) != -1 && cgu.cgu_dev != 0) {
    770  1.42       kre 			warnx("device %s already in use", *argv);
    771  1.43       kre 			prog_close(fd);
    772  1.42       kre 			return -1;
    773  1.42       kre 		}
    774  1.43       kre 		prog_close(fd);
    775  1.42       kre 	}
    776  1.42       kre 
    777  1.44       kre 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    778  1.44       kre 	if (dev == NULL) {
    779  1.44       kre 		warnx("getfsspecname failed: %s", devicename);
    780  1.44       kre 		return -1;
    781  1.36   mlelstv 	}
    782   1.1     elric 
    783  1.34  christos 	if (argc == 2) {
    784  1.40  christos 		char pfile[MAXPATHLEN];
    785  1.36   mlelstv 
    786  1.36   mlelstv 		/* make string writable for basename */
    787  1.40  christos 		strlcpy(pfile, dev, sizeof(pfile));
    788  1.40  christos 		p = params_cget(basename(pfile));
    789  1.44       kre 	} else
    790  1.17    cbiere 		p = params_cget(argv[2]);
    791   1.1     elric 
    792   1.5     elric 	if (!p)
    793   1.5     elric 		return -1;
    794   1.2     elric 
    795   1.3     elric 	/*
    796   1.5     elric 	 * over-ride with command line specifications and fill in default
    797   1.5     elric 	 * values.
    798   1.3     elric 	 */
    799   1.3     elric 
    800   1.5     elric 	p = params_combine(p, inparams);
    801   1.5     elric 	ret = params_filldefaults(p);
    802   1.5     elric 	if (ret) {
    803   1.5     elric 		params_free(p);
    804   1.5     elric 		return ret;
    805   1.5     elric 	}
    806   1.5     elric 
    807   1.5     elric 	if (!params_verify(p)) {
    808   1.5     elric 		warnx("params invalid");
    809   1.5     elric 		return -1;
    810   1.5     elric 	}
    811   1.3     elric 
    812   1.3     elric 	/*
    813   1.3     elric 	 * loop over configuring the disk and checking to see if it
    814   1.3     elric 	 * verifies properly.  We open and close the disk device each
    815   1.3     elric 	 * time, because if the user passes us the block device we
    816   1.3     elric 	 * need to flush the buffer cache.
    817  1.22     elric 	 *
    818  1.22     elric 	 * We only loop if one of the verification methods prompts for
    819  1.22     elric 	 * a password.
    820   1.3     elric 	 */
    821   1.3     elric 
    822  1.47     alnsn 	for (kg = p->keygen;
    823  1.47     alnsn 	    (pflag & PFLAG_GETPASS_MASK) && kg;
    824  1.47     alnsn 	    kg = kg->next)
    825  1.53       nia 		if (kg->kg_method == KEYGEN_ARGON2ID ||
    826  1.53       nia 		    kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1 ||
    827  1.53       nia 		    kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD) {
    828  1.22     elric 			loop = 1;
    829  1.22     elric 			break;
    830  1.22     elric 		}
    831  1.22     elric 
    832   1.3     elric 	for (;;) {
    833  1.59  riastrad 		struct sharedkeyhits skh;
    834  1.59  riastrad 		struct sharedkey *sk, *sk1;
    835  1.59  riastrad 		int all_verified;
    836  1.59  riastrad 
    837  1.59  riastrad 		SLIST_INIT(&skh);
    838  1.59  riastrad 
    839   1.3     elric 		fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    840   1.3     elric 		if (fd == -1)
    841   1.3     elric 			return -1;
    842   1.3     elric 
    843   1.5     elric 		if (p->key)
    844   1.5     elric 			bits_free(p->key);
    845   1.5     elric 
    846  1.59  riastrad 		p->key = getkey(argv[1], p->keygen, p->keylen, &skh);
    847   1.5     elric 		if (!p->key)
    848   1.3     elric 			goto bail_err;
    849   1.3     elric 
    850  1.36   mlelstv 		ret = configure_params(fd, cgdname, dev, p);
    851   1.3     elric 		if (ret)
    852   1.3     elric 			goto bail_err;
    853   1.3     elric 
    854   1.5     elric 		ret = verify(p, fd);
    855  1.49       kre 		if (ret == -1) {
    856  1.49       kre 			(void)unconfigure_fd(fd);
    857   1.3     elric 			goto bail_err;
    858  1.49       kre 		}
    859  1.59  riastrad 		if (ret == 0) {		/* success */
    860  1.59  riastrad 			SLIST_FOREACH(sk, &skh, used)
    861  1.59  riastrad 				sk->verified = 1;
    862   1.3     elric 			break;
    863  1.59  riastrad 		}
    864   1.2     elric 
    865  1.19  christos 		(void)unconfigure_fd(fd);
    866  1.32     pooka 		(void)prog_close(fd);
    867  1.22     elric 
    868  1.59  riastrad 		/*
    869  1.60  riastrad 		 * For shared keys: If the shared keys were all
    870  1.60  riastrad 		 * verified already, assume something is wrong with the
    871  1.60  riastrad 		 * disk and give up.  If not, flush the cache of the
    872  1.60  riastrad 		 * ones that have not been verified in case we can try
    873  1.60  riastrad 		 * again with passphrase re-entry.
    874  1.59  riastrad 		 */
    875  1.60  riastrad 		if (!SLIST_EMPTY(&skh)) {
    876  1.60  riastrad 			all_verified = 1;
    877  1.60  riastrad 			SLIST_FOREACH_SAFE(sk, &skh, used, sk1) {
    878  1.60  riastrad 				all_verified &= sk->verified;
    879  1.60  riastrad 				if (!sk->verified) {
    880  1.60  riastrad 					LIST_REMOVE(sk, list);
    881  1.60  riastrad 					free(sk);
    882  1.60  riastrad 				}
    883  1.59  riastrad 			}
    884  1.60  riastrad 			if (all_verified)
    885  1.60  riastrad 				loop = 0;
    886  1.59  riastrad 		}
    887  1.59  riastrad 
    888  1.22     elric 		if (!loop) {
    889  1.22     elric 			warnx("verification failed permanently");
    890  1.22     elric 			goto bail_err;
    891  1.22     elric 		}
    892  1.22     elric 
    893  1.22     elric 		warnx("verification failed, please reenter passphrase");
    894   1.3     elric 	}
    895   1.2     elric 
    896   1.5     elric 	params_free(p);
    897  1.32     pooka 	(void)prog_close(fd);
    898   1.3     elric 	return 0;
    899  1.50       kre 
    900  1.50       kre  bail_err:;
    901   1.5     elric 	params_free(p);
    902  1.32     pooka 	(void)prog_close(fd);
    903   1.3     elric 	return -1;
    904   1.1     elric }
    905   1.1     elric 
    906   1.1     elric static int
    907   1.1     elric configure_stdin(struct params *p, int argc, char **argv)
    908   1.1     elric {
    909  1.36   mlelstv 	int		 fd;
    910  1.36   mlelstv 	int		 ret;
    911  1.36   mlelstv 	char		 cgdname[PATH_MAX];
    912  1.38  christos 	char		 devicename[PATH_MAX];
    913  1.36   mlelstv 	const char	*dev;
    914   1.1     elric 
    915   1.1     elric 	if (argc < 3 || argc > 4)
    916   1.1     elric 		usage();
    917   1.1     elric 
    918  1.38  christos 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
    919  1.36   mlelstv 	if (dev == NULL) {
    920  1.38  christos 		warnx("getfsspecname failed: %s", devicename);
    921  1.36   mlelstv 		return -1;
    922  1.36   mlelstv 	}
    923  1.36   mlelstv 
    924   1.5     elric 	p->algorithm = string_fromcharstar(argv[2]);
    925  1.17    cbiere 	if (argc > 3) {
    926  1.19  christos 		size_t keylen;
    927  1.17    cbiere 
    928  1.19  christos 		if (parse_size_t(argv[3], &keylen) == -1) {
    929  1.17    cbiere 			warn("failed to parse key length");
    930  1.17    cbiere 			return -1;
    931  1.17    cbiere 		}
    932  1.17    cbiere 		p->keylen = keylen;
    933  1.17    cbiere 	}
    934   1.1     elric 
    935   1.1     elric 	ret = params_filldefaults(p);
    936   1.1     elric 	if (ret)
    937   1.1     elric 		return ret;
    938   1.1     elric 
    939   1.2     elric 	fd = opendisk_werror(argv[0], cgdname, sizeof(cgdname));
    940   1.2     elric 	if (fd == -1)
    941   1.2     elric 		return -1;
    942   1.2     elric 
    943   1.5     elric 	p->key = bits_fget(stdin, p->keylen);
    944   1.5     elric 	if (!p->key) {
    945   1.5     elric 		warnx("failed to read key from stdin");
    946   1.1     elric 		return -1;
    947   1.5     elric 	}
    948   1.1     elric 
    949  1.36   mlelstv 	return configure_params(fd, cgdname, dev, p);
    950   1.1     elric }
    951   1.1     elric 
    952   1.1     elric static int
    953  1.17    cbiere opendisk_werror(const char *cgd, char *buf, size_t buflen)
    954   1.2     elric {
    955   1.2     elric 	int	fd;
    956   1.2     elric 
    957  1.50       kre 	VPRINTF(3, ("opendisk_werror(%s, %s, %zu) called.\n", cgd,buf,buflen));
    958   1.5     elric 
    959   1.2     elric 	/* sanity */
    960   1.2     elric 	if (!cgd || !buf)
    961   1.2     elric 		return -1;
    962   1.2     elric 
    963   1.2     elric 	if (nflag) {
    964  1.17    cbiere 		if (strlcpy(buf, cgd, buflen) >= buflen)
    965  1.17    cbiere 			return -1;
    966   1.2     elric 		return 0;
    967   1.2     elric 	}
    968   1.2     elric 
    969  1.32     pooka 	fd = opendisk1(cgd, O_RDWR, buf, buflen, 0, prog_open);
    970   1.2     elric 	if (fd == -1)
    971   1.5     elric 		warnx("can't open cgd \"%s\", \"%s\"", cgd, buf);
    972   1.5     elric 
    973   1.2     elric 	return fd;
    974   1.2     elric }
    975   1.2     elric 
    976   1.2     elric static int
    977   1.2     elric configure_params(int fd, const char *cgd, const char *dev, struct params *p)
    978   1.1     elric {
    979   1.1     elric 	struct cgd_ioctl ci;
    980   1.1     elric 
    981   1.1     elric 	/* sanity */
    982   1.1     elric 	if (!cgd || !dev)
    983   1.1     elric 		return -1;
    984   1.1     elric 
    985  1.19  christos 	(void)memset(&ci, 0x0, sizeof(ci));
    986  1.16  christos 	ci.ci_disk = dev;
    987  1.16  christos 	ci.ci_alg = string_tocharstar(p->algorithm);
    988  1.16  christos 	ci.ci_ivmethod = string_tocharstar(p->ivmeth);
    989  1.16  christos 	ci.ci_key = bits_getbuf(p->key);
    990   1.1     elric 	ci.ci_keylen = p->keylen;
    991   1.1     elric 	ci.ci_blocksize = p->bsize;
    992   1.1     elric 
    993  1.20    martin 	VPRINTF(1, ("    with alg %s keylen %zu blocksize %zu ivmethod %s\n",
    994   1.5     elric 	    string_tocharstar(p->algorithm), p->keylen, p->bsize,
    995   1.5     elric 	    string_tocharstar(p->ivmeth)));
    996   1.5     elric 	VPRINTF(2, ("key: "));
    997   1.5     elric 	VERBOSE(2, bits_fprint(stdout, p->key));
    998   1.5     elric 	VPRINTF(2, ("\n"));
    999   1.1     elric 
   1000   1.1     elric 	if (nflag)
   1001   1.1     elric 		return 0;
   1002   1.1     elric 
   1003  1.32     pooka 	if (prog_ioctl(fd, CGDIOCSET, &ci) == -1) {
   1004  1.17    cbiere 		int saved_errno = errno;
   1005  1.17    cbiere 		warn("ioctl");
   1006  1.17    cbiere 		return saved_errno;
   1007   1.1     elric 	}
   1008   1.1     elric 
   1009   1.1     elric 	return 0;
   1010   1.1     elric }
   1011   1.1     elric 
   1012   1.3     elric /*
   1013   1.3     elric  * verify returns 0 for success, -1 for unrecoverable error, or 1 for retry.
   1014   1.3     elric  */
   1015   1.3     elric 
   1016   1.3     elric #define SCANSIZE	8192
   1017   1.3     elric 
   1018   1.3     elric static int
   1019   1.3     elric verify(struct params *p, int fd)
   1020   1.3     elric {
   1021   1.3     elric 
   1022   1.3     elric 	switch (p->verify_method) {
   1023   1.3     elric 	case VERIFY_NONE:
   1024   1.3     elric 		return 0;
   1025   1.3     elric 	case VERIFY_DISKLABEL:
   1026   1.5     elric 		return verify_disklabel(fd);
   1027   1.5     elric 	case VERIFY_FFS:
   1028   1.5     elric 		return verify_ffs(fd);
   1029   1.9        cb 	case VERIFY_REENTER:
   1030   1.9        cb 		return verify_reenter(p);
   1031  1.37   mlelstv 	case VERIFY_MBR:
   1032  1.37   mlelstv 		return verify_mbr(fd);
   1033  1.37   mlelstv 	case VERIFY_GPT:
   1034  1.37   mlelstv 		return verify_gpt(fd);
   1035  1.63  christos #ifdef HAVE_ZFS
   1036  1.63  christos 	case VERIFY_ZFS:
   1037  1.63  christos 		return verify_zfs(fd);
   1038  1.63  christos #endif
   1039   1.3     elric 	default:
   1040   1.5     elric 		warnx("unimplemented verification method");
   1041   1.3     elric 		return -1;
   1042   1.3     elric 	}
   1043   1.5     elric }
   1044   1.5     elric 
   1045   1.5     elric static int
   1046   1.5     elric verify_disklabel(int fd)
   1047   1.5     elric {
   1048   1.5     elric 	struct	disklabel l;
   1049  1.17    cbiere 	ssize_t	ret;
   1050   1.5     elric 	char	buf[SCANSIZE];
   1051   1.3     elric 
   1052   1.3     elric 	/*
   1053   1.3     elric 	 * we simply scan the first few blocks for a disklabel, ignoring
   1054   1.3     elric 	 * any MBR/filecore sorts of logic.  MSDOS and RiscOS can't read
   1055   1.3     elric 	 * a cgd, anyway, so it is unlikely that there will be non-native
   1056   1.3     elric 	 * partition information.
   1057   1.3     elric 	 */
   1058   1.3     elric 
   1059  1.37   mlelstv 	ret = prog_pread(fd, buf, SCANSIZE, 0);
   1060  1.17    cbiere 	if (ret < 0) {
   1061   1.5     elric 		warn("can't read disklabel area");
   1062   1.3     elric 		return -1;
   1063   1.3     elric 	}
   1064   1.3     elric 
   1065   1.3     elric 	/* now scan for the disklabel */
   1066   1.3     elric 
   1067  1.17    cbiere 	return disklabel_scan(&l, buf, (size_t)ret);
   1068   1.3     elric }
   1069   1.3     elric 
   1070  1.37   mlelstv static int
   1071  1.37   mlelstv verify_mbr(int fd)
   1072  1.37   mlelstv {
   1073  1.37   mlelstv 	struct mbr_sector mbr;
   1074  1.37   mlelstv 	ssize_t	ret;
   1075  1.37   mlelstv 	char	buf[SCANSIZE];
   1076  1.37   mlelstv 
   1077  1.37   mlelstv 	/*
   1078  1.37   mlelstv 	 * we read the first blocks to avoid sector size issues and
   1079  1.37   mlelstv 	 * verify the MBR in the beginning
   1080  1.37   mlelstv 	 */
   1081  1.37   mlelstv 
   1082  1.37   mlelstv 	ret = prog_pread(fd, buf, SCANSIZE, 0);
   1083  1.37   mlelstv 	if (ret < 0) {
   1084  1.37   mlelstv 		warn("can't read mbr area");
   1085  1.37   mlelstv 		return -1;
   1086  1.37   mlelstv 	}
   1087  1.37   mlelstv 
   1088  1.37   mlelstv 	memcpy(&mbr, buf, sizeof(mbr));
   1089  1.37   mlelstv 	if (le16toh(mbr.mbr_magic) != MBR_MAGIC)
   1090  1.49       kre 		return 1;
   1091  1.37   mlelstv 
   1092  1.37   mlelstv 	return 0;
   1093  1.37   mlelstv }
   1094  1.37   mlelstv 
   1095  1.37   mlelstv static uint32_t crc32_tab[] = {
   1096  1.37   mlelstv 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
   1097  1.37   mlelstv 	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
   1098  1.37   mlelstv 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
   1099  1.37   mlelstv 	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
   1100  1.37   mlelstv 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
   1101  1.37   mlelstv 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
   1102  1.37   mlelstv 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
   1103  1.37   mlelstv 	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
   1104  1.37   mlelstv 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
   1105  1.37   mlelstv 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
   1106  1.37   mlelstv 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
   1107  1.37   mlelstv 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
   1108  1.37   mlelstv 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
   1109  1.37   mlelstv 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
   1110  1.37   mlelstv 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
   1111  1.37   mlelstv 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
   1112  1.37   mlelstv 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
   1113  1.37   mlelstv 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
   1114  1.37   mlelstv 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
   1115  1.37   mlelstv 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
   1116  1.37   mlelstv 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
   1117  1.37   mlelstv 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
   1118  1.37   mlelstv 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
   1119  1.37   mlelstv 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
   1120  1.37   mlelstv 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
   1121  1.37   mlelstv 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
   1122  1.37   mlelstv 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
   1123  1.37   mlelstv 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
   1124  1.37   mlelstv 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
   1125  1.37   mlelstv 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
   1126  1.37   mlelstv 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
   1127  1.37   mlelstv 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
   1128  1.37   mlelstv 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
   1129  1.37   mlelstv 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
   1130  1.37   mlelstv 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
   1131  1.37   mlelstv 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
   1132  1.37   mlelstv 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
   1133  1.37   mlelstv 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
   1134  1.37   mlelstv 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
   1135  1.37   mlelstv 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
   1136  1.37   mlelstv 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
   1137  1.37   mlelstv 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
   1138  1.37   mlelstv 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
   1139  1.37   mlelstv };
   1140  1.37   mlelstv 
   1141  1.37   mlelstv static uint32_t
   1142  1.37   mlelstv crc32(const void *buf, size_t size)
   1143  1.37   mlelstv {
   1144  1.37   mlelstv 	const uint8_t *p;
   1145  1.37   mlelstv 	uint32_t crc;
   1146  1.37   mlelstv 
   1147  1.37   mlelstv 	p = buf;
   1148  1.37   mlelstv 	crc = ~0U;
   1149  1.37   mlelstv 
   1150  1.37   mlelstv 	while (size--)
   1151  1.37   mlelstv 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
   1152  1.37   mlelstv 
   1153  1.37   mlelstv 	return crc ^ ~0U;
   1154  1.37   mlelstv }
   1155  1.37   mlelstv 
   1156  1.37   mlelstv static int
   1157  1.37   mlelstv verify_gpt(int fd)
   1158  1.37   mlelstv {
   1159  1.37   mlelstv 	struct	 gpt_hdr hdr;
   1160  1.37   mlelstv 	ssize_t	 ret;
   1161  1.37   mlelstv 	char	 buf[SCANSIZE];
   1162  1.37   mlelstv 	unsigned blksize;
   1163  1.37   mlelstv 	size_t	 off;
   1164  1.37   mlelstv 
   1165  1.37   mlelstv 	/*
   1166  1.37   mlelstv 	 * we read the first blocks to avoid sector size issues and
   1167  1.37   mlelstv 	 * verify the GPT header.
   1168  1.37   mlelstv 	 */
   1169  1.37   mlelstv 
   1170  1.37   mlelstv 	ret = prog_pread(fd, buf, SCANSIZE, 0);
   1171  1.37   mlelstv 	if (ret < 0) {
   1172  1.37   mlelstv 		warn("can't read gpt area");
   1173  1.37   mlelstv 		return -1;
   1174  1.37   mlelstv 	}
   1175  1.37   mlelstv 
   1176  1.50       kre 	for (blksize = DEV_BSIZE;
   1177  1.50       kre              (off = (blksize * GPT_HDR_BLKNO)) <= SCANSIZE - sizeof(hdr);
   1178  1.37   mlelstv              blksize <<= 1) {
   1179  1.37   mlelstv 
   1180  1.37   mlelstv 		memcpy(&hdr, &buf[off], sizeof(hdr));
   1181  1.50       kre 		if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) == 0
   1182  1.50       kre 		    && le32toh(hdr.hdr_revision) == GPT_HDR_REVISION
   1183  1.50       kre 		    && le32toh(hdr.hdr_size) == GPT_HDR_SIZE) {
   1184  1.37   mlelstv 
   1185  1.37   mlelstv 			hdr.hdr_crc_self = 0;
   1186  1.37   mlelstv 			if (crc32(&hdr, sizeof(hdr))) {
   1187  1.63  christos 				return 0;
   1188  1.37   mlelstv 			}
   1189  1.37   mlelstv 		}
   1190  1.37   mlelstv 	}
   1191  1.37   mlelstv 
   1192  1.63  christos 	return 1;
   1193  1.63  christos }
   1194  1.63  christos 
   1195  1.63  christos #ifdef HAVE_ZFS
   1196  1.63  christos 
   1197  1.63  christos #define ZIO_CHECKSUM_BE(zcp)					\
   1198  1.63  christos {								\
   1199  1.63  christos 	(zcp)->zc_word[0] = BE_64((zcp)->zc_word[0]);		\
   1200  1.63  christos 	(zcp)->zc_word[1] = BE_64((zcp)->zc_word[1]);		\
   1201  1.63  christos 	(zcp)->zc_word[2] = BE_64((zcp)->zc_word[2]);		\
   1202  1.63  christos 	(zcp)->zc_word[3] = BE_64((zcp)->zc_word[3]);		\
   1203  1.63  christos }
   1204  1.63  christos 
   1205  1.63  christos static int
   1206  1.63  christos verify_zfs(int fd)
   1207  1.63  christos {
   1208  1.63  christos 	off_t vdev_size;
   1209  1.63  christos 	int rv = 1;
   1210  1.63  christos 
   1211  1.63  christos 	if (prog_ioctl(fd, DIOCGMEDIASIZE, &vdev_size) == -1) {
   1212  1.63  christos 		warn("%s: ioctl", __func__);
   1213  1.63  christos 		return rv;
   1214  1.63  christos 	}
   1215  1.63  christos 
   1216  1.63  christos 	vdev_phys_t *vdev_phys = emalloc(sizeof(*vdev_phys));
   1217  1.63  christos 	for (size_t i = 0; i < VDEV_LABELS; i++) {
   1218  1.63  christos 		off_t vdev_phys_off = (i < VDEV_LABELS / 2 ?
   1219  1.63  christos 		    i * sizeof(vdev_label_t) :
   1220  1.63  christos 		    vdev_size - (VDEV_LABELS - i) * sizeof(vdev_label_t))
   1221  1.63  christos 		    + offsetof(vdev_label_t, vl_vdev_phys);
   1222  1.63  christos 
   1223  1.63  christos 		ssize_t ret = prog_pread(fd, vdev_phys, sizeof(*vdev_phys),
   1224  1.63  christos 		    vdev_phys_off);
   1225  1.63  christos 		if (ret == -1) {
   1226  1.63  christos 			warn("%s: read failed", __func__);
   1227  1.63  christos 			goto out;
   1228  1.63  christos 		}
   1229  1.63  christos 		if ((size_t)ret < sizeof(*vdev_phys)) {
   1230  1.63  christos 			warnx("%s: incomplete block", __func__);
   1231  1.63  christos 			goto out;
   1232  1.63  christos 		}
   1233  1.63  christos 
   1234  1.63  christos 		bool byteswap;
   1235  1.63  christos 		switch (vdev_phys->vp_zbt.zec_magic) {
   1236  1.63  christos 		case BSWAP_64(ZEC_MAGIC):
   1237  1.63  christos 			byteswap = true;
   1238  1.63  christos 			break;
   1239  1.63  christos 		case ZEC_MAGIC:
   1240  1.63  christos 			byteswap = false;
   1241  1.63  christos 			break;
   1242  1.63  christos 		default:
   1243  1.63  christos 			goto out;
   1244  1.63  christos 		}
   1245  1.63  christos 
   1246  1.63  christos 		zio_cksum_t cksum_found = vdev_phys->vp_zbt.zec_cksum;
   1247  1.63  christos 		if (byteswap) {
   1248  1.63  christos 			ZIO_CHECKSUM_BSWAP(&cksum_found);
   1249  1.63  christos 		}
   1250  1.63  christos 
   1251  1.63  christos 		ZIO_SET_CHECKSUM(&vdev_phys->vp_zbt.zec_cksum,
   1252  1.63  christos 		    vdev_phys_off, 0, 0, 0);
   1253  1.63  christos 		if (byteswap) {
   1254  1.63  christos 			ZIO_CHECKSUM_BSWAP(&vdev_phys->vp_zbt.zec_cksum);
   1255  1.63  christos 		}
   1256  1.63  christos 
   1257  1.63  christos 		SHA256_CTX ctx;
   1258  1.63  christos 		zio_cksum_t cksum_real;
   1259  1.63  christos 
   1260  1.63  christos 		SHA256Init(&ctx);
   1261  1.63  christos 		SHA256Update(&ctx, (uint8_t *)vdev_phys, sizeof *vdev_phys);
   1262  1.63  christos 		SHA256Final(&cksum_real, &ctx);
   1263  1.63  christos 
   1264  1.63  christos 		/*
   1265  1.63  christos 		 * For historical reasons the on-disk sha256 checksums are
   1266  1.63  christos 		 * always in big endian format.
   1267  1.63  christos 		 * (see cddl/osnet/dist/uts/common/fs/zfs/sha256.c)
   1268  1.63  christos 		 */
   1269  1.63  christos 		ZIO_CHECKSUM_BE(&cksum_real);
   1270  1.63  christos 
   1271  1.63  christos 		if (!ZIO_CHECKSUM_EQUAL(cksum_found, cksum_real)) {
   1272  1.63  christos 			warnx("%s: checksum mismatch on vdev label %zu",
   1273  1.63  christos 			    __func__, i);
   1274  1.63  christos 			warnx("%s: found %#jx, %#jx, %#jx, %#jx", __func__,
   1275  1.63  christos 			    (uintmax_t)cksum_found.zc_word[0],
   1276  1.63  christos 			    (uintmax_t)cksum_found.zc_word[1],
   1277  1.63  christos 			    (uintmax_t)cksum_found.zc_word[2],
   1278  1.63  christos 			    (uintmax_t)cksum_found.zc_word[3]);
   1279  1.63  christos 			warnx("%s: expected %#jx, %#jx, %#jx, %#jx", __func__,
   1280  1.63  christos 			    (uintmax_t)cksum_real.zc_word[0],
   1281  1.63  christos 			    (uintmax_t)cksum_real.zc_word[1],
   1282  1.63  christos 			    (uintmax_t)cksum_real.zc_word[2],
   1283  1.63  christos 			    (uintmax_t)cksum_real.zc_word[3]);
   1284  1.63  christos 			goto out;
   1285  1.63  christos 		}
   1286  1.63  christos 	}
   1287  1.63  christos 	rv = 0;
   1288  1.63  christos out:
   1289  1.63  christos 	free(vdev_phys);
   1290  1.63  christos 	return rv;
   1291  1.37   mlelstv }
   1292  1.37   mlelstv 
   1293  1.63  christos #endif
   1294  1.63  christos 
   1295   1.7      fvdl static off_t sblock_try[] = SBLOCKSEARCH;
   1296   1.7      fvdl 
   1297   1.1     elric static int
   1298   1.5     elric verify_ffs(int fd)
   1299   1.5     elric {
   1300  1.19  christos 	size_t	i;
   1301   1.5     elric 
   1302   1.7      fvdl 	for (i = 0; sblock_try[i] != -1; i++) {
   1303  1.19  christos 		union {
   1304  1.19  christos 		    char	buf[SBLOCKSIZE];
   1305  1.19  christos 		    struct	fs fs;
   1306  1.19  christos 		} u;
   1307  1.17    cbiere 		ssize_t ret;
   1308  1.17    cbiere 
   1309  1.32     pooka 		ret = prog_pread(fd, &u, sizeof(u), sblock_try[i]);
   1310  1.17    cbiere 		if (ret < 0) {
   1311   1.7      fvdl 			warn("pread");
   1312  1.17    cbiere 			break;
   1313  1.19  christos 		} else if ((size_t)ret < sizeof(u)) {
   1314  1.17    cbiere 			warnx("pread: incomplete block");
   1315  1.17    cbiere 			break;
   1316   1.7      fvdl 		}
   1317  1.19  christos 		switch (u.fs.fs_magic) {
   1318   1.7      fvdl 		case FS_UFS1_MAGIC:
   1319   1.7      fvdl 		case FS_UFS2_MAGIC:
   1320  1.61       chs 		case FS_UFS2EA_MAGIC:
   1321   1.7      fvdl 		case FS_UFS1_MAGIC_SWAPPED:
   1322   1.7      fvdl 		case FS_UFS2_MAGIC_SWAPPED:
   1323  1.61       chs 		case FS_UFS2EA_MAGIC_SWAPPED:
   1324   1.7      fvdl 			return 0;
   1325   1.7      fvdl 		default:
   1326   1.7      fvdl 			continue;
   1327   1.7      fvdl 		}
   1328   1.5     elric 	}
   1329  1.17    cbiere 
   1330  1.17    cbiere 	return 1;	/* failure */
   1331   1.9        cb }
   1332   1.9        cb 
   1333   1.9        cb static int
   1334   1.9        cb verify_reenter(struct params *p)
   1335   1.9        cb {
   1336   1.9        cb 	struct keygen *kg;
   1337  1.53       nia 	bits_t *orig_key, *key = NULL;
   1338   1.9        cb 	int ret;
   1339   1.9        cb 
   1340   1.9        cb 	ret = 0;
   1341   1.9        cb 	for (kg = p->keygen; kg && !ret; kg = kg->next) {
   1342  1.53       nia 		if (kg->kg_method != KEYGEN_ARGON2ID &&
   1343  1.53       nia 		    kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1 &&
   1344  1.53       nia 		    kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD)
   1345   1.9        cb 			continue;
   1346   1.9        cb 
   1347   1.9        cb 		orig_key = kg->kg_key;
   1348   1.9        cb 		kg->kg_key = NULL;
   1349   1.9        cb 
   1350  1.53       nia 		switch (kg->kg_method) {
   1351  1.53       nia #ifdef HAVE_ARGON2
   1352  1.53       nia 		case KEYGEN_ARGON2ID:
   1353  1.53       nia 			key = getkey_argon2id("re-enter device", kg,
   1354  1.53       nia 				bits_len(orig_key));
   1355  1.53       nia 			break;
   1356  1.53       nia #endif
   1357  1.53       nia 		case KEYGEN_PKCS5_PBKDF2_SHA1:
   1358  1.53       nia 			key = getkey_pkcs5_pbkdf2("re-enter device", kg,
   1359  1.53       nia 				bits_len(orig_key), 0);
   1360  1.53       nia 			break;
   1361  1.53       nia 		case KEYGEN_PKCS5_PBKDF2_OLD:
   1362  1.53       nia 			key = getkey_pkcs5_pbkdf2("re-enter device", kg,
   1363  1.53       nia 				bits_len(orig_key), 1);
   1364  1.53       nia 			break;
   1365  1.53       nia 		default:
   1366  1.53       nia 			warnx("unsupported keygen method");
   1367  1.53       nia 			kg->kg_key = orig_key;
   1368  1.53       nia 			return -1;
   1369  1.53       nia 		}
   1370  1.50       kre 
   1371   1.9        cb 		ret = !bits_match(key, orig_key);
   1372   1.9        cb 
   1373   1.9        cb 		bits_free(key);
   1374   1.9        cb 		bits_free(kg->kg_key);
   1375   1.9        cb 		kg->kg_key = orig_key;
   1376   1.9        cb 	}
   1377   1.9        cb 
   1378   1.9        cb 	return ret;
   1379   1.5     elric }
   1380   1.5     elric 
   1381   1.5     elric static int
   1382  1.57  riastrad generate(struct params *p, int argc, char **argv, const char *outfile,
   1383  1.57  riastrad     const char *Pfile)
   1384   1.1     elric {
   1385   1.1     elric 	int	 ret;
   1386   1.1     elric 
   1387   1.1     elric 	if (argc < 1 || argc > 2)
   1388   1.1     elric 		usage();
   1389   1.1     elric 
   1390   1.5     elric 	p->algorithm = string_fromcharstar(argv[0]);
   1391  1.17    cbiere 	if (argc > 1) {
   1392  1.19  christos 		size_t keylen;
   1393  1.17    cbiere 
   1394  1.19  christos 		if (parse_size_t(argv[1], &keylen) == -1) {
   1395  1.17    cbiere 			warn("Failed to parse key length");
   1396  1.17    cbiere 			return -1;
   1397  1.17    cbiere 		}
   1398  1.17    cbiere 		p->keylen = keylen;
   1399  1.17    cbiere 	}
   1400   1.5     elric 
   1401   1.5     elric 	ret = params_filldefaults(p);
   1402   1.1     elric 	if (ret)
   1403   1.1     elric 		return ret;
   1404   1.5     elric 
   1405  1.57  riastrad 	if (Pfile) {
   1406  1.57  riastrad 		struct params *pp;
   1407  1.57  riastrad 
   1408  1.57  riastrad 		pp = params_cget(Pfile);
   1409  1.57  riastrad 		if (pp == NULL)
   1410  1.57  riastrad 			return -1;
   1411  1.57  riastrad 		if (!params_verify(pp)) {
   1412  1.57  riastrad 			params_free(pp);
   1413  1.57  riastrad 			warnx("invalid parameters file \"%s\"", Pfile);
   1414  1.57  riastrad 			return -1;
   1415  1.57  riastrad 		}
   1416  1.57  riastrad 		p = params_combine(pp, p);
   1417  1.57  riastrad 		keygen_stripstored(&p->keygen);
   1418  1.57  riastrad 		if (!p->keygen) {
   1419  1.57  riastrad 			warnx("no keygen in parameters file \"%s\"", Pfile);
   1420  1.57  riastrad 			return -1;
   1421  1.57  riastrad 		}
   1422  1.57  riastrad 	} else {
   1423  1.57  riastrad 		if (!p->keygen) {
   1424  1.57  riastrad 			p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1425  1.57  riastrad 			if (!p->keygen)
   1426  1.57  riastrad 				return -1;
   1427  1.57  riastrad 		}
   1428  1.57  riastrad 
   1429  1.57  riastrad 		if (keygen_filldefaults(p->keygen, p->keylen)) {
   1430  1.57  riastrad 			warnx("Failed to generate defaults for keygen");
   1431   1.5     elric 			return -1;
   1432  1.57  riastrad 		}
   1433   1.5     elric 	}
   1434   1.5     elric 
   1435  1.57  riastrad 	if (Sflag) {
   1436  1.57  riastrad 		if (Pfile)
   1437  1.57  riastrad 			ret = keygen_tweakshared(p->keygen);
   1438  1.57  riastrad 		else
   1439  1.57  riastrad 			ret = keygen_makeshared(p->keygen);
   1440  1.57  riastrad 		if (ret)
   1441  1.57  riastrad 			return ret;
   1442   1.5     elric 	}
   1443   1.5     elric 
   1444   1.5     elric 	if (!params_verify(p)) {
   1445   1.5     elric 		warnx("invalid parameters generated");
   1446   1.5     elric 		return -1;
   1447   1.5     elric 	}
   1448   1.5     elric 
   1449   1.5     elric 	return params_cput(p, outfile);
   1450   1.5     elric }
   1451   1.5     elric 
   1452   1.5     elric static int
   1453  1.58  riastrad generate_convert(struct params *p, int argc, char **argv, const char *outfile,
   1454  1.58  riastrad     const char *Pfile)
   1455   1.5     elric {
   1456   1.5     elric 	struct params	*oldp;
   1457   1.5     elric 	struct keygen	*kg;
   1458  1.58  riastrad 	int		 ret;
   1459   1.5     elric 
   1460   1.5     elric 	if (argc != 1)
   1461   1.5     elric 		usage();
   1462   1.5     elric 
   1463   1.5     elric 	oldp = params_cget(*argv);
   1464   1.5     elric 	if (!oldp)
   1465   1.5     elric 		return -1;
   1466   1.5     elric 
   1467   1.5     elric 	/* for sanity, we ensure that none of the keygens are randomkey */
   1468   1.5     elric 	for (kg=p->keygen; kg; kg=kg->next)
   1469  1.30     elric 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1470  1.30     elric 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1471  1.30     elric 			warnx("can't preserve randomly generated key");
   1472   1.5     elric 			goto bail;
   1473  1.30     elric 		}
   1474   1.5     elric 	for (kg=oldp->keygen; kg; kg=kg->next)
   1475  1.30     elric 		if ((kg->kg_method == KEYGEN_RANDOMKEY) ||
   1476  1.30     elric 		    (kg->kg_method == KEYGEN_URANDOMKEY)) {
   1477  1.30     elric 			warnx("can't preserve randomly generated key");
   1478   1.5     elric 			goto bail;
   1479  1.30     elric 		}
   1480   1.5     elric 
   1481   1.5     elric 	if (!params_verify(oldp)) {
   1482   1.5     elric 		warnx("invalid old parameters file \"%s\"", *argv);
   1483   1.5     elric 		return -1;
   1484   1.1     elric 	}
   1485   1.1     elric 
   1486  1.59  riastrad 	oldp->key = getkey("old file", oldp->keygen, oldp->keylen, NULL);
   1487   1.5     elric 
   1488   1.5     elric 	/* we copy across the non-keygen info, here. */
   1489   1.5     elric 
   1490   1.5     elric 	string_free(p->algorithm);
   1491   1.5     elric 	string_free(p->ivmeth);
   1492   1.5     elric 
   1493   1.5     elric 	p->algorithm = string_dup(oldp->algorithm);
   1494   1.5     elric 	p->ivmeth = string_dup(oldp->ivmeth);
   1495   1.5     elric 	p->keylen = oldp->keylen;
   1496   1.5     elric 	p->bsize = oldp->bsize;
   1497   1.5     elric 	if (p->verify_method == VERIFY_UNKNOWN)
   1498   1.5     elric 		p->verify_method = oldp->verify_method;
   1499   1.5     elric 
   1500   1.5     elric 	params_free(oldp);
   1501   1.1     elric 
   1502  1.58  riastrad 	if (Pfile) {
   1503  1.58  riastrad 		struct params *pp;
   1504  1.58  riastrad 
   1505  1.58  riastrad 		pp = params_cget(Pfile);
   1506  1.58  riastrad 		if (pp == NULL)
   1507  1.58  riastrad 			return -1;
   1508  1.58  riastrad 		if (!params_verify(pp)) {
   1509  1.58  riastrad 			params_free(pp);
   1510  1.58  riastrad 			warnx("invalid parameters file \"%s\"", Pfile);
   1511  1.58  riastrad 			return -1;
   1512  1.58  riastrad 		}
   1513  1.58  riastrad 		p = params_combine(pp, p);
   1514  1.58  riastrad 		keygen_stripstored(&p->keygen);
   1515  1.58  riastrad 		if (!p->keygen) {
   1516  1.58  riastrad 			warnx("no keygen in parameters file \"%s\"", Pfile);
   1517   1.1     elric 			return -1;
   1518  1.58  riastrad 		}
   1519  1.58  riastrad 	} else {
   1520  1.58  riastrad 		if (!p->keygen) {
   1521  1.58  riastrad 			p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
   1522  1.58  riastrad 			if (!p->keygen)
   1523  1.58  riastrad 				return -1;
   1524  1.58  riastrad 		}
   1525  1.58  riastrad 		(void)params_filldefaults(p);
   1526  1.58  riastrad 		(void)keygen_filldefaults(p->keygen, p->keylen);
   1527   1.5     elric 	}
   1528  1.58  riastrad 
   1529  1.58  riastrad 	if (Sflag) {
   1530  1.58  riastrad 		if (Pfile)
   1531  1.58  riastrad 			ret = keygen_tweakshared(p->keygen);
   1532  1.58  riastrad 		else
   1533  1.58  riastrad 			ret = keygen_makeshared(p->keygen);
   1534  1.58  riastrad 		if (ret)
   1535  1.58  riastrad 			return ret;
   1536  1.58  riastrad 	}
   1537  1.58  riastrad 
   1538  1.59  riastrad 	p->key = getkey("new file", p->keygen, p->keylen, NULL);
   1539   1.5     elric 
   1540   1.5     elric 	kg = keygen_generate(KEYGEN_STOREDKEY);
   1541   1.5     elric 	kg->kg_key = bits_xor(p->key, oldp->key);
   1542   1.5     elric 	keygen_addlist(&p->keygen, kg);
   1543   1.5     elric 
   1544   1.5     elric 	if (!params_verify(p)) {
   1545   1.5     elric 		warnx("can't generate new parameters file");
   1546   1.5     elric 		return -1;
   1547   1.1     elric 	}
   1548   1.1     elric 
   1549   1.5     elric 	return params_cput(p, outfile);
   1550  1.50       kre  bail:;
   1551   1.5     elric 	params_free(oldp);
   1552   1.5     elric 	return -1;
   1553   1.1     elric }
   1554   1.1     elric 
   1555   1.1     elric static int
   1556  1.19  christos /*ARGSUSED*/
   1557   1.1     elric do_all(const char *cfile, int argc, char **argv,
   1558   1.3     elric        int (*conf)(int, char **, struct params *, int))
   1559   1.1     elric {
   1560   1.1     elric 	FILE		 *f;
   1561   1.1     elric 	size_t		  len;
   1562   1.1     elric 	size_t		  lineno;
   1563   1.1     elric 	int		  my_argc;
   1564   1.1     elric 	int		  ret;
   1565   1.1     elric 	const char	 *fn;
   1566   1.1     elric 	char		 *line;
   1567   1.1     elric 	char		**my_argv;
   1568   1.1     elric 
   1569   1.1     elric 	if (argc > 0)
   1570   1.1     elric 		usage();
   1571   1.1     elric 
   1572   1.1     elric 	if (!cfile[0])
   1573   1.1     elric 		fn = CGDCONFIG_CFILE;
   1574   1.1     elric 	else
   1575   1.1     elric 		fn = cfile;
   1576   1.1     elric 
   1577   1.1     elric 	f = fopen(fn, "r");
   1578  1.50       kre 	if (f == NULL) {
   1579   1.5     elric 		warn("could not open config file \"%s\"", fn);
   1580   1.1     elric 		return -1;
   1581   1.1     elric 	}
   1582   1.1     elric 
   1583   1.1     elric 	ret = 0;
   1584   1.1     elric 	lineno = 0;
   1585   1.1     elric 	for (;;) {
   1586   1.1     elric 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
   1587   1.1     elric 		if (!line)
   1588   1.1     elric 			break;
   1589   1.1     elric 		if (!*line)
   1590   1.1     elric 			continue;
   1591   1.1     elric 
   1592   1.1     elric 		my_argv = words(line, &my_argc);
   1593   1.3     elric 		ret = conf(my_argc, my_argv, NULL, CONFIG_FLAGS_FROMALL);
   1594   1.1     elric 		if (ret) {
   1595   1.5     elric 			warnx("action failed on \"%s\" line %lu", fn,
   1596   1.1     elric 			    (u_long)lineno);
   1597   1.1     elric 			break;
   1598   1.1     elric 		}
   1599   1.1     elric 		words_free(my_argv, my_argc);
   1600   1.1     elric 	}
   1601   1.1     elric 	return ret;
   1602   1.1     elric }
   1603  1.13     elric 
   1604  1.34  christos static const char *
   1605  1.34  christos iv_method(int mode)
   1606  1.34  christos {
   1607  1.34  christos 
   1608  1.34  christos 	switch (mode) {
   1609  1.34  christos 	case CGD_CIPHER_CBC_ENCBLKNO8:
   1610  1.34  christos 		return "encblkno8";
   1611  1.34  christos 	case CGD_CIPHER_CBC_ENCBLKNO1:
   1612  1.34  christos 		return "encblkno1";
   1613  1.34  christos 	default:
   1614  1.34  christos 		return "unknown";
   1615  1.34  christos 	}
   1616  1.34  christos }
   1617  1.34  christos 
   1618  1.35  christos 
   1619  1.35  christos static void
   1620  1.62  riastrad show(const char *dev)
   1621  1.62  riastrad {
   1622  1.35  christos 	char path[64];
   1623  1.35  christos 	struct cgd_user cgu;
   1624  1.35  christos 	int fd;
   1625  1.35  christos 
   1626  1.35  christos 	fd = opendisk(dev, O_RDONLY, path, sizeof(path), 0);
   1627  1.35  christos 	if (fd == -1) {
   1628  1.35  christos 		warn("open: %s", dev);
   1629  1.35  christos 		return;
   1630  1.35  christos 	}
   1631  1.35  christos 
   1632  1.35  christos 	cgu.cgu_unit = -1;
   1633  1.35  christos 	if (prog_ioctl(fd, CGDIOCGET, &cgu) == -1) {
   1634  1.35  christos 		close(fd);
   1635  1.35  christos 		err(1, "CGDIOCGET");
   1636  1.35  christos 	}
   1637  1.35  christos 
   1638  1.35  christos 	printf("%s: ", dev);
   1639  1.35  christos 
   1640  1.35  christos 	if (cgu.cgu_dev == 0) {
   1641  1.35  christos 		printf("not in use");
   1642  1.35  christos 		goto out;
   1643  1.35  christos 	}
   1644  1.35  christos 
   1645  1.35  christos 	dev = devname(cgu.cgu_dev, S_IFBLK);
   1646  1.62  riastrad 	if (dev != NULL) {
   1647  1.35  christos 		printf("%s ", dev);
   1648  1.62  riastrad 	} else {
   1649  1.62  riastrad 		printf("dev %llu,%llu ",
   1650  1.62  riastrad 		    (unsigned long long)major(cgu.cgu_dev),
   1651  1.35  christos 		    (unsigned long long)minor(cgu.cgu_dev));
   1652  1.62  riastrad 	}
   1653  1.35  christos 
   1654  1.35  christos 	if (verbose)
   1655  1.35  christos 		printf("%s ", cgu.cgu_alg);
   1656  1.35  christos 	if (verbose > 1) {
   1657  1.35  christos 		printf("keylen %d ", cgu.cgu_keylen);
   1658  1.35  christos 		printf("blksize %zd ", cgu.cgu_blocksize);
   1659  1.35  christos 		printf("%s ", iv_method(cgu.cgu_mode));
   1660  1.35  christos 	}
   1661  1.35  christos 
   1662  1.50       kre  out:;
   1663  1.35  christos 	putchar('\n');
   1664  1.35  christos 	close(fd);
   1665  1.35  christos }
   1666  1.35  christos 
   1667  1.34  christos static int
   1668  1.34  christos do_list(int argc, char **argv)
   1669  1.34  christos {
   1670  1.34  christos 
   1671  1.34  christos 	if (argc != 0 && argc != 1)
   1672  1.34  christos 		usage();
   1673  1.34  christos 
   1674  1.35  christos 	if (argc) {
   1675  1.35  christos 		show(argv[0]);
   1676  1.35  christos 		return 0;
   1677  1.35  christos 	}
   1678  1.34  christos 
   1679  1.35  christos 	DIR *dirp;
   1680  1.35  christos 	struct dirent *dp;
   1681  1.35  christos 	__BITMAP_TYPE(, uint32_t, 65536) bm;
   1682  1.35  christos 
   1683  1.35  christos 	__BITMAP_ZERO(&bm);
   1684  1.35  christos 
   1685  1.35  christos 	if ((dirp = opendir(_PATH_DEV)) == NULL)
   1686  1.35  christos 		err(1, "opendir: %s", _PATH_DEV);
   1687  1.35  christos 
   1688  1.35  christos 	while ((dp = readdir(dirp)) != NULL) {
   1689  1.35  christos 		char *ep;
   1690  1.35  christos 		if (strncmp(dp->d_name, "rcgd", 4) != 0)
   1691  1.35  christos 			continue;
   1692  1.35  christos 		errno = 0;
   1693  1.35  christos 		int n = (int)strtol(dp->d_name + 4, &ep, 0);
   1694  1.35  christos 		if (ep == dp->d_name + 4 || errno != 0) {
   1695  1.35  christos 			warnx("bad name %s", dp->d_name);
   1696  1.35  christos 			continue;
   1697  1.34  christos 		}
   1698  1.35  christos 		*ep = '\0';
   1699  1.35  christos 		if (__BITMAP_ISSET(n, &bm))
   1700  1.35  christos 			continue;
   1701  1.35  christos 		__BITMAP_SET(n, &bm);
   1702  1.35  christos 		show(dp->d_name + 1);
   1703  1.34  christos 	}
   1704  1.34  christos 
   1705  1.35  christos 	closedir(dirp);
   1706  1.34  christos 	return 0;
   1707  1.34  christos }
   1708  1.34  christos 
   1709  1.54  riastrad static int
   1710  1.55  riastrad printkey(const char *dev, const char *paramsfile, const char *fmt, ...)
   1711  1.54  riastrad {
   1712  1.55  riastrad 	va_list va;
   1713  1.54  riastrad 	struct params *p;
   1714  1.54  riastrad 	const uint8_t *raw;
   1715  1.54  riastrad 	size_t nbits, nbytes;
   1716  1.54  riastrad 	size_t nb64;
   1717  1.54  riastrad 	char *b64;
   1718  1.54  riastrad 	int ret;
   1719  1.54  riastrad 
   1720  1.55  riastrad 	p = params_cget(paramsfile);
   1721  1.54  riastrad 	if (p == NULL)
   1722  1.54  riastrad 		return -1;
   1723  1.54  riastrad 	if (!params_verify(p)) {
   1724  1.55  riastrad 		warnx("invalid parameters file \"%s\"", paramsfile);
   1725  1.54  riastrad 		return -1;
   1726  1.54  riastrad 	}
   1727  1.59  riastrad 	p->key = getkey(dev, p->keygen, p->keylen, NULL);
   1728  1.54  riastrad 	raw = bits_getbuf(p->key);
   1729  1.54  riastrad 	nbits = bits_len(p->key);
   1730  1.54  riastrad 	assert(nbits <= INT_MAX - 7);
   1731  1.54  riastrad 	nbytes = BITS2BYTES(nbits);
   1732  1.54  riastrad 	assert(nbytes <= 3*(INT_MAX/4) - 2);
   1733  1.54  riastrad 
   1734  1.54  riastrad 	nb64 = 4*((nbytes + 2)/3);
   1735  1.54  riastrad 	b64 = emalloc(nb64 + 2);
   1736  1.54  riastrad 	ret = __b64_ntop(raw, nbytes, b64, nb64 + 1);
   1737  1.54  riastrad 	assert(ret == (int)nb64);
   1738  1.54  riastrad 	b64[nb64] = '\n';
   1739  1.54  riastrad 	b64[nb64 + 1] = '\0';
   1740  1.54  riastrad 
   1741  1.55  riastrad 	va_start(va, fmt);
   1742  1.55  riastrad 	vprintf(fmt, va);
   1743  1.55  riastrad 	va_end(va);
   1744  1.54  riastrad 	if (fwrite(b64, nb64 + 1, 1, stdout) != 1)
   1745  1.54  riastrad 		err(1, "fwrite");
   1746  1.54  riastrad 	fflush(stdout);
   1747  1.54  riastrad 	return ferror(stdout);
   1748  1.54  riastrad }
   1749  1.54  riastrad 
   1750  1.55  riastrad static int
   1751  1.55  riastrad printkey1(int argc, char **argv, struct params *inparams, int flags)
   1752  1.55  riastrad {
   1753  1.55  riastrad 	char devicename[PATH_MAX], paramsfilebuf[PATH_MAX];
   1754  1.55  riastrad 	const char *dev, *paramsfile;
   1755  1.55  riastrad 
   1756  1.55  riastrad 	assert(flags == CONFIG_FLAGS_FROMALL);
   1757  1.55  riastrad 
   1758  1.55  riastrad 	if (argc < 2 || argc > 3)
   1759  1.55  riastrad 		return -1;
   1760  1.55  riastrad 
   1761  1.55  riastrad 	dev = getfsspecname(devicename, sizeof(devicename), argv[1]);
   1762  1.55  riastrad 	if (dev == NULL) {
   1763  1.55  riastrad 		warnx("getfsspecname failed: %s", devicename);
   1764  1.55  riastrad 		return -1;
   1765  1.55  riastrad 	}
   1766  1.55  riastrad 
   1767  1.55  riastrad 	if (argc == 2) {
   1768  1.55  riastrad 		strlcpy(paramsfilebuf, dev, sizeof(paramsfilebuf));
   1769  1.55  riastrad 		paramsfile = basename(paramsfilebuf);
   1770  1.55  riastrad 	} else {
   1771  1.55  riastrad 		paramsfile = argv[2];
   1772  1.55  riastrad 	}
   1773  1.55  riastrad 
   1774  1.55  riastrad 	return printkey(dev, paramsfile, "%s: ", dev);
   1775  1.55  riastrad }
   1776  1.55  riastrad 
   1777  1.55  riastrad static int
   1778  1.55  riastrad do_printkey(int argc, char **argv)
   1779  1.55  riastrad {
   1780  1.55  riastrad 
   1781  1.55  riastrad 	if (argc != 1)
   1782  1.55  riastrad 		usage();
   1783  1.55  riastrad 	return printkey("key", argv[0], "");
   1784  1.55  riastrad }
   1785  1.55  riastrad 
   1786  1.13     elric static void
   1787  1.13     elric eliminate_cores(void)
   1788  1.13     elric {
   1789  1.13     elric 	struct rlimit	rlp;
   1790  1.13     elric 
   1791  1.13     elric 	rlp.rlim_cur = 0;
   1792  1.13     elric 	rlp.rlim_max = 0;
   1793  1.17    cbiere 	if (setrlimit(RLIMIT_CORE, &rlp) == -1)
   1794  1.13     elric 		err(EXIT_FAILURE, "Can't disable cores");
   1795  1.13     elric }
   1796