예제 #1
0
/* Process a line of configuration file or a command-line option. */
static void
dooption(struct bsdtar *bsdtar, const char * conf_opt,
    const char * conf_arg, int fromconffile)
{
	struct stat st;
	char *eptr;

	if (strcmp(conf_opt, "aggressive-networking") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_aggressive_networking_set)
			goto optset;

		tarsnap_opt_aggressive_networking = 1;
		bsdtar->option_aggressive_networking_set = 1;
	} else if (strcmp(conf_opt, "cachedir") == 0) {
		if (bsdtar->cachedir != NULL)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if ((bsdtar->cachedir = strdup(conf_arg)) == NULL)
			bsdtar_errc(bsdtar, 1, errno, "Out of memory");
	} else if (strcmp(conf_opt, "checkpoint-bytes") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (tarsnap_opt_checkpointbytes != (uint64_t)(-1))
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (humansize_parse(conf_arg, &tarsnap_opt_checkpointbytes))
			bsdtar_errc(bsdtar, 1, 0,
			    "Cannot parse #bytes per checkpoint: %s",
			    conf_arg);
		if (tarsnap_opt_checkpointbytes < 1000000)
			bsdtar_errc(bsdtar, 1, 0,
			    "checkpoint-bytes value must be at least 1M");
	} else if (strcmp(conf_opt, "disk-pause") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_disk_pause_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		bsdtar->disk_pause = strtol(conf_arg, NULL, 0);
		bsdtar->option_disk_pause_set = 1;
	} else if (strcmp(conf_opt, "exclude") == 0) {
		if (bsdtar->option_no_config_exclude_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (exclude(bsdtar, conf_arg))
			bsdtar_errc(bsdtar, 1, 0,
			    "Couldn't exclude %s", conf_arg);
	} else if (strcmp(conf_opt, "humanize-numbers") == 0) {
		if (bsdtar->option_humanize_numbers_set)
			goto optset;

		tarsnap_opt_humanize_numbers = 1;
		bsdtar->option_humanize_numbers_set = 1;
	} else if (strcmp(conf_opt, "include") == 0) {
		if (bsdtar->option_no_config_include_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (include(bsdtar, conf_arg))
			bsdtar_errc(bsdtar, 1, 0,
			    "Failed to add %s to inclusion list", conf_arg);
	} else if (strcmp(conf_opt, "insane-filesystems") == 0) {
		if (bsdtar->option_insane_filesystems_set)
			goto optset;

		bsdtar->option_insane_filesystems = 1;
		bsdtar->option_insane_filesystems_set = 1;
	} else if (strcmp(conf_opt, "keyfile") == 0) {
		if (bsdtar->have_keys)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (load_keys(bsdtar, conf_arg) == 0)
			bsdtar->have_keys = 1;
		else {
			if (fromconffile && bsdtar->option_dryrun)
				bsdtar->config_file_keyfile_failed = 1;
			else {
				bsdtar_errc(bsdtar, 1, errno,
				    "Cannot read key file: %s", conf_arg);
			}
		}
	} else if (strcmp(conf_opt, "lowmem") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_cachecrunch_set)
			goto optset;

		bsdtar->cachecrunch = 1;
		bsdtar->option_cachecrunch_set = 1;
	} else if (strcmp(conf_opt, "maxbw") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_maxbw_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (humansize_parse(conf_arg, &tarsnap_opt_maxbytesout))
			bsdtar_errc(bsdtar, 1, 0,
			    "Cannot parse bandwidth limit: %s", conf_arg);
		bsdtar->option_maxbw_set = 1;
	} else if (strcmp(conf_opt, "maxbw-rate") == 0) {
		dooption(bsdtar, "maxbw-rate-down", conf_arg, fromconffile);
		dooption(bsdtar, "maxbw-rate-up", conf_arg, fromconffile);
	} else if (strcmp(conf_opt, "maxbw-rate-down") == 0) {
		if (bsdtar->option_maxbw_rate_down_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		bsdtar->bwlimit_rate_down = strtod(conf_arg, &eptr);
		if ((*eptr != '\0') ||
		    (bsdtar->bwlimit_rate_down < 8000) ||
		    (bsdtar->bwlimit_rate_down > 1000000000.))
			bsdtar_errc(bsdtar, 1, 0,
			    "Invalid bandwidth rate limit: %s", conf_arg);
		bsdtar->option_maxbw_rate_down_set = 1;
	} else if (strcmp(conf_opt, "maxbw-rate-up") == 0) {
		if (bsdtar->option_maxbw_rate_up_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		bsdtar->bwlimit_rate_up = strtod(conf_arg, &eptr);
		if ((*eptr != '\0') ||
		    (bsdtar->bwlimit_rate_up < 8000) ||
		    (bsdtar->bwlimit_rate_up > 1000000000.))
			bsdtar_errc(bsdtar, 1, 0,
			    "Invalid bandwidth rate limit: %s", conf_arg);
		bsdtar->option_maxbw_rate_up_set = 1;
	} else if (strcmp(conf_opt, "nodump") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_nodump_set)
			goto optset;

		bsdtar->option_honor_nodump = 1;
		bsdtar->option_nodump_set = 1;
	} else if (strcmp(conf_opt, "normalmem") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_cachecrunch_set)
			goto optset;

		bsdtar->option_cachecrunch_set = 1;
	} else if (strcmp(conf_opt, "no-aggressive-networking") == 0) {
		if (bsdtar->option_aggressive_networking_set)
			goto optset;

		bsdtar->option_aggressive_networking_set = 1;
	} else if (strcmp(conf_opt, "no-config-exclude") == 0) {
		if (bsdtar->option_no_config_exclude)
			goto optset;

		bsdtar->option_no_config_exclude = 1;
	} else if (strcmp(conf_opt, "no-config-include") == 0) {
		if (bsdtar->option_no_config_include)
			goto optset;

		bsdtar->option_no_config_include = 1;
	} else if (strcmp(conf_opt, "no-disk-pause") == 0) {
		if (bsdtar->option_disk_pause_set)
			goto optset;

		bsdtar->option_disk_pause_set = 1;
	} else if (strcmp(conf_opt, "no-humanize-numbers") == 0) {
		if (bsdtar->option_humanize_numbers_set)
			goto optset;

		bsdtar->option_humanize_numbers_set = 1;
	} else if (strcmp(conf_opt, "no-insane-filesystems") == 0) {
		if (bsdtar->option_insane_filesystems_set)
			goto optset;

		bsdtar->option_insane_filesystems_set = 1;
	} else if (strcmp(conf_opt, "no-maxbw") == 0) {
		if (bsdtar->option_maxbw_set)
			goto optset;

		bsdtar->option_maxbw_set = 1;
	} else if (strcmp(conf_opt, "no-maxbw-rate-down") == 0) {
		if (bsdtar->option_maxbw_rate_down_set)
			goto optset;

		bsdtar->option_maxbw_rate_down_set = 1;
	} else if (strcmp(conf_opt, "no-maxbw-rate-up") == 0) {
		if (bsdtar->option_maxbw_rate_up_set)
			goto optset;

		bsdtar->option_maxbw_rate_up_set = 1;
	} else if (strcmp(conf_opt, "no-nodump") == 0) {
		if (bsdtar->option_nodump_set)
			goto optset;

		bsdtar->option_nodump_set = 1;
	} else if (strcmp(conf_opt, "no-print-stats") == 0) {
		if (bsdtar->option_print_stats_set)
			goto optset;

		bsdtar->option_print_stats_set = 1;
	} else if (strcmp(conf_opt, "no-quiet") == 0) {
		if (bsdtar->option_quiet_set)
			goto optset;

		bsdtar->option_quiet_set = 1;
	} else if (strcmp(conf_opt, "no-retry-forever") == 0) {
		if (bsdtar->option_retry_forever_set)
			goto optset;

		bsdtar->option_retry_forever_set = 1;
	} else if (strcmp(conf_opt, "no-snaptime") == 0) {
		if (bsdtar->option_snaptime_set)
			goto optset;

		bsdtar->option_snaptime_set = 1;
	} else if (strcmp(conf_opt, "no-store-atime") == 0) {
		if (bsdtar->option_store_atime_set)
			goto optset;

		bsdtar->option_store_atime_set = 1;
	} else if (strcmp(conf_opt, "no-totals") == 0) {
		if (bsdtar->option_totals_set)
			goto optset;

		bsdtar->option_totals_set = 1;
	} else if (strcmp(conf_opt, "print-stats") == 0) {
		if ((bsdtar->mode != 'c') && (bsdtar->mode != 'd'))
			goto badmode;
		if (bsdtar->option_print_stats_set)
			goto optset;

		bsdtar->option_print_stats = 1;
		bsdtar->option_print_stats_set = 1;
	} else if (strcmp(conf_opt, "quiet") == 0) {
		if (bsdtar->option_quiet_set)
			goto optset;

		bsdtar->option_quiet = 1;
		bsdtar->option_quiet_set = 1;
	} else if (strcmp(conf_opt, "retry-forever") == 0) {
		if (bsdtar->option_retry_forever_set)
			goto optset;

		tarsnap_opt_retry_forever = 1;
		bsdtar->option_retry_forever_set = 1;
	} else if (strcmp(conf_opt, "snaptime") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_snaptime_set)
			goto optset;
		if (conf_arg == NULL)
			goto needarg;

		if (stat(conf_arg, &st) != 0)
			bsdtar_errc(bsdtar, 1, 0,
			    "Can't stat file %s", conf_arg);
		bsdtar->snaptime = st.st_ctime;
		bsdtar->option_snaptime_set = 1;
	} else if (strcmp(conf_opt, "store-atime") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_store_atime_set)
			goto optset;

		bsdtar->option_store_atime = 1;
		bsdtar->option_store_atime_set = 1;
	} else if (strcmp(conf_opt, "totals") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_totals_set)
			goto optset;

		bsdtar->option_totals = 1;
		bsdtar->option_totals_set = 1;
	} else if (strcmp(conf_opt, "verylowmem") == 0) {
		if (bsdtar->mode != 'c')
			goto badmode;
		if (bsdtar->option_cachecrunch_set)
			goto optset;

		bsdtar->cachecrunch = 2;
		bsdtar->option_cachecrunch_set = 1;
	} else {
		goto badopt;
	}
	return;

badmode:
	/* Option not relevant in this mode. */
	if (fromconffile == 0) {
		bsdtar_errc(bsdtar, 1, 0,
		    "Option --%s is not permitted in mode %s",
		    conf_opt, bsdtar->modestr);
	}
	return;

optset:
	/* Option specified multiple times. */
	if (fromconffile == 0) {
		usage(bsdtar);
	}
	return;

needarg:
	/* Option needs an argument. */
	bsdtar_errc(bsdtar, 1, 0,
	    "Argument required for configuration file option: %s", conf_opt);

badopt:
	/* No such option. */
	bsdtar_errc(bsdtar, 1, 0,
	    "Unrecognized configuration file option: \"%s\"", conf_opt);
}
예제 #2
0
파일: keyregen.c 프로젝트: zg/tarsnap
int
main(int argc, char **argv)
{
	struct register_internal C;
	const char * keyfilename;
	const char * oldkeyfilename;
	int passphrased;
	uint64_t maxmem;
	double maxtime;
	const char * ch;

	WARNP_INIT;

	/*
	 * We have no username, machine name, key filename, or old key
	 * filename yet.
	 */
	C.user = C.name = NULL;
	keyfilename = NULL;
	oldkeyfilename = NULL;

	/*
	 * So far we're not using a passphrase, have unlimited RAM, and allow
	 * up to 1 second of CPU time.
	 */
	passphrased = 0;
	maxmem = 0;
	maxtime = 1.0;

	/* Parse arguments. */
	while ((ch = GETOPT(argc, argv)) != NULL) {
		GETOPT_SWITCH(ch) {
		GETOPT_OPTARG("--user"):
			if (C.user != NULL)
				usage();
			C.user = optarg;
			break;
		GETOPT_OPTARG("--machine"):
			if (C.name != NULL)
				usage();
			C.name = optarg;
			break;
		GETOPT_OPTARG("--keyfile"):
			if (keyfilename != NULL)
				usage();
			keyfilename = optarg;
			break;
		GETOPT_OPTARG("--oldkey"):
			if (oldkeyfilename != NULL)
				usage();
			oldkeyfilename = optarg;
			break;
		GETOPT_OPTARG("--passphrase-mem"):
			if (maxmem != 0)
				usage();
			if (humansize_parse(optarg, &maxmem)) {
				warnp("Cannot parse --passphrase-mem"
				    " argument: %s", optarg);
				exit(1);
			}
			break;
		GETOPT_OPTARG("--passphrase-time"):
			if (maxtime != 1.0)
				usage();
			maxtime = strtod(optarg, NULL);
			if ((maxtime < 0.05) || (maxtime > 86400)) {
				warn0("Invalid --passphrase-time argument: %s",
				    optarg);
				exit(1);
			}
			break;
		GETOPT_OPT("--passphrased"):
			if (passphrased != 0)
				usage();
			passphrased = 1;
			break;
		GETOPT_OPT("--version"):
			fprintf(stderr, "tarsnap-keyregen %s\n",
			    PACKAGE_VERSION);
			exit(0);
		GETOPT_MISSING_ARG:
			warn0("Missing argument to %s\n", ch);
			/* FALLTHROUGH */
		GETOPT_DEFAULT:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	/* We should have processed all the arguments. */
	if (argc != 0)
		usage();

	/*
	 * We must have a user name, machine name, key file, and old key
	 * file specified.
	 */
	if ((C.user == NULL) || (C.name == NULL) ||
	    (keyfilename == NULL) || (oldkeyfilename == NULL))
		usage();

	/*
	 * It doesn't make sense to specify --passphrase-mem or
	 * --passphrase-time if we're not using a passphrase.
	 */
	if (((maxmem != 0) || (maxtime != 1.0)) && (passphrased == 0))
		usage();

	/*
	 * Use shared code between keygen and keyregen for the actual
	 * processing.
	 */
	if (keygen_actual(&C, keyfilename, passphrased, maxmem, maxtime,
	    oldkeyfilename) != 0)
		goto err0;

	/* Success! */
	return (0);

err0:
	/* Failure! */
	return (1);
}
예제 #3
0
파일: keygen.c 프로젝트: lornix/tarsnap
int
main(int argc, char **argv)
{
	struct register_internal C;
	const char * keyfilename;
	FILE * keyfile;
	NETPACKET_CONNECTION * NPC;
	int passphrased;
	uint64_t maxmem;
	double maxtime;
	char * passphrase;

	WARNP_INIT;

	/* We have no username, machine name, or key filename yet. */
	C.user = C.name = NULL;
	keyfilename = NULL;

	/*
	 * So far we're not using a passphrase, have unlimited RAM, and allow
	 * up to 1 second of CPU time.
	 */
	passphrased = 0;
	maxmem = 0;
	maxtime = 1.0;

	/* Parse arguments. */
	while (--argc > 0) {
		argv++;

		if (strcmp(argv[0], "--user") == 0) {
			if ((C.user != NULL) || (argc < 2))
				usage();
			C.user = argv[1];
			argv++; argc--;
		} else if (strcmp(argv[0], "--machine") == 0) {
			if ((C.name != NULL) || (argc < 2))
				usage();
			C.name = argv[1];
			argv++; argc--;
		} else if (strcmp(argv[0], "--keyfile") == 0) {
			if ((keyfilename != NULL) || (argc < 2))
				usage();
			keyfilename = argv[1];
			argv++; argc--;
		} else if (strcmp(argv[0], "--passphrase-mem") == 0) {
			if ((maxmem != 0) || (argc < 2))
				usage();
			if (humansize_parse(argv[1], &maxmem)) {
				warnp("Cannot parse --passphrase-mem"
				    " argument: %s", argv[1]);
				exit(1);
			}
			argv++; argc--;
		} else if (strcmp(argv[0], "--passphrase-time") == 0) {
			if ((maxtime != 1.0) || (argc < 2))
				usage();
			maxtime = strtod(argv[1], NULL);
			if ((maxtime < 0.05) || (maxtime > 86400)) {
				warn0("Invalid --passphrase-time argument: %s",
				    argv[1]);
				exit(1);
			}
			argv++; argc--;
		} else if (strcmp(argv[0], "--passphrased") == 0) {
			passphrased = 1;
		} else {
			usage();
		}
	}

	/* We must have a user name, machine name, and key file specified. */
	if ((C.user == NULL) || (C.name == NULL) || (keyfilename == NULL))
		usage();

	/*
	 * It doesn't make sense to specify --passphrase-mem or
	 * --passphrase-time if we're not using a passphrase.
	 */
	if (((maxmem != 0) || (maxtime != 1.0)) && (passphrased == 0))
		usage();

	/* Sanity-check the user name. */
	if (strlen(C.user) > 255) {
		fprintf(stderr, "User name too long: %s\n", C.user);
		exit(1);
	}
	if (strlen(C.user) == 0) {
		fprintf(stderr, "User name must be non-empty\n");
		exit(1);
	}

	/* Sanity-check the machine name. */
	if (strlen(C.name) > 255) {
		fprintf(stderr, "Machine name too long: %s\n", C.name);
		exit(1);
	}
	if (strlen(C.name) == 0) {
		fprintf(stderr, "Machine name must be non-empty\n");
		exit(1);
	}

	/* Get a password. */
	if (readpass(&C.passwd, "Enter tarsnap account password", NULL, 0)) {
		warnp("Error reading password");
		exit(1);
	}

	/*
	 * Create key file -- we do this now rather than later so that we
	 * avoid registering with the server if we won't be able to create
	 * the key file later.
	 */
	if ((keyfile = keyfile_write_open(keyfilename)) == NULL) {
		warnp("Cannot create %s", keyfilename);
		exit(1);
	}

	/* Initialize key cache. */
	if (crypto_keys_init()) {
		warnp("Key cache initialization failed");
		goto err1;
	}

	/* Generate keys. */
	if (crypto_keys_generate(CRYPTO_KEYMASK_USER)) {
		warnp("Error generating keys");
		goto err1;
	}

	/*
	 * We're not done, haven't answered a challenge, and don't have a
	 * machine number.
	 */
	C.done = 0;
	C.donechallenge = 0;
	C.machinenum = (uint64_t)(-1);

	/* Open netpacket connection. */
	if ((NPC = netpacket_open(USERAGENT)) == NULL)
		goto err2;

	/* Ask the netpacket layer to send a request and get a response. */
	if (netpacket_op(NPC, callback_register_send, &C))
		goto err2;

	/* Run event loop until an error occurs or we're done. */
	if (network_spin(&C.done))
		goto err2;

	/* Close netpacket connection. */
	if (netpacket_close(NPC))
		goto err2;

	/*
	 * If we didn't respond to a challenge, the server's response must
	 * have been a "no such user" error.
	 */
	if ((C.donechallenge == 0) && (C.status != 1)) {
		netproto_printerr(NETPROTO_STATUS_PROTERR);
		goto err1;
	}

	/* The machine number should be -1 iff the status is nonzero. */
	if (((C.machinenum == (uint64_t)(-1)) && (C.status == 0)) ||
	    ((C.machinenum != (uint64_t)(-1)) && (C.status != 0))) {
		netproto_printerr(NETPROTO_STATUS_PROTERR);
		goto err1;
	}

	/* Parse status returned by server. */
	switch (C.status) {
	case 0:
		/* Success! */
		break;
	case 1:
		warn0("No such user: %s", C.user);
		break;
	case 2:
		warn0("Incorrect password");
		break;
	case 3:
		warn0("Cannot register with server: "
		    "Account balance for user %s is not positive", C.user);
		break;
	default:
		netproto_printerr(NETPROTO_STATUS_PROTERR);
		goto err2;
	}

	/* Shut down the network event loop. */
	network_fini();

	/* Exit with a code of 1 if we couldn't register. */
	if (C.machinenum == (uint64_t)(-1))
		goto err1;

	/* If the user wants to passphrase the keyfile, get the passphrase. */
	if (passphrased != 0) {
		if (readpass(&passphrase,
		    "Please enter passphrase for keyfile encryption",
		    "Please confirm passphrase for keyfile encryption", 1)) {
			warnp("Error reading password");
			goto err1;
		}
	} else {
		passphrase = NULL;
	}

	/* Write keys to file. */
	if (keyfile_write_file(keyfile, C.machinenum,
	    CRYPTO_KEYMASK_USER, passphrase, maxmem, maxtime))
		goto err1;

	/* Close the key file. */
	if (fclose(keyfile)) {
		warnp("Error closing key file");
		goto err1;
	}

	/* Success! */
	return (0);

err2:
	warnp("Error registering with server");
err1:
	unlink(keyfilename);
	exit(1);
}
예제 #4
0
int
main(int argc, char **argv)
{
	const char * newkeyfile = NULL;
	int keyswanted = 0;
	char * tok, * brkb = NULL, * eptr;
	long keynum;
	uint64_t machinenum = (uint64_t)(-1);
	uint64_t kfmachinenum;
	const char * missingkey;
	int passphrased = 0;
	uint64_t maxmem = 0;
	double maxtime = 1.0;
	char * passphrase;
	const char * print_key_id_file = NULL;
	const char * print_key_permissions_file = NULL;
	const char * ch;
	char * optarg_copy;	/* for strtok_r. */

	WARNP_INIT;

	/* Initialize key cache. */
	if (crypto_keys_init()) {
		warnp("Key cache initialization failed");
		exit(1);
	}

	/* Parse arguments. */
	while ((ch = GETOPT(argc, argv)) != NULL) {
		GETOPT_SWITCH(ch) {
		GETOPT_OPTARG("--outkeyfile"):
			if (newkeyfile != NULL)
				usage();
			newkeyfile = optarg;
			break;
		GETOPT_OPT("-r"):
			keyswanted |= CRYPTO_KEYMASK_READ;
			break;
		GETOPT_OPT("-w"):
			keyswanted |= CRYPTO_KEYMASK_WRITE;
			break;
		GETOPT_OPT("-d"):
			/*
			 * Deleting data requires both delete authorization
			 * and being able to read archives -- we need to be
			 * able to figure out which bits are part of the
			 * archive.
			 */
			keyswanted |= CRYPTO_KEYMASK_READ;
			keyswanted |= CRYPTO_KEYMASK_AUTH_DELETE;
			break;
		GETOPT_OPT("--nuke"):
			keyswanted |= CRYPTO_KEYMASK_AUTH_DELETE;
			break;
		GETOPT_OPTARG("--keylist"):
			/*
			 * This is a deliberately undocumented option used
			 * mostly for testing purposes; it allows a list of
			 * keys to be specified according to their numbers in
			 * crypto/crypto.h instead of using the predefined
			 * sets of "read", "write" and "delete" keys.
			 */
			if ((optarg_copy = strdup(optarg)) == NULL) {
				warn0("Out of memory");
				exit(0);
			}
			for (tok = strtok_r(optarg_copy, ",", &brkb);
			     tok;
			     tok = strtok_r(NULL, ",", &brkb)) {
				keynum = strtol(tok, &eptr, 0);
				if ((eptr == tok) ||
				    (keynum < 0) || (keynum > 31)) {
					warn0("Not a valid key number: %s",
					    tok);
					free(optarg_copy);
					exit(1);
				}
				keyswanted |= (uint32_t)(1) << keynum;
			}
			free(optarg_copy);
			break;
		GETOPT_OPTARG("--passphrase-mem"):
			if (maxmem != 0)
				usage();
			if (humansize_parse(optarg, &maxmem)) {
				warnp("Cannot parse --passphrase-mem"
				    " argument: %s", optarg);
				exit(1);
			}
			break;
		GETOPT_OPTARG("--passphrase-time"):
			if (maxtime != 1.0)
				usage();
			maxtime = strtod(optarg, NULL);
			if ((maxtime < 0.05) || (maxtime > 86400)) {
				warn0("Invalid --passphrase-time argument: %s",
				    optarg);
				exit(1);
			}
			break;
		GETOPT_OPT("--passphrased"):
			if (passphrased != 0)
				usage();
			passphrased = 1;
			break;
		GETOPT_OPTARG("--print-key-id"):
			if (print_key_id_file != NULL)
				usage();
			print_key_id_file = optarg;
			break;
		GETOPT_OPTARG("--print-key-permissions"):
			if (print_key_permissions_file != NULL)
				usage();
			print_key_permissions_file = optarg;
			break;
		GETOPT_MISSING_ARG:
			warn0("Missing argument to %s\n", ch);
			/* FALLTHROUGH */
		GETOPT_DEFAULT:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	/* We can't print ID and permissions at the same time. */
	if ((print_key_id_file != NULL) && (print_key_permissions_file != NULL))
		usage();

	if ((print_key_id_file != NULL) ||
	    (print_key_permissions_file != NULL)) {
		/* We can't combine printing info with generating a new key. */
		if (newkeyfile != NULL)
			usage();

		/* We should have processed all arguments. */
		if (argc != 0)
			usage();

		/* Print info. */
		if (print_key_id_file != NULL)
			print_id(print_key_id_file);
		if (print_key_permissions_file != NULL)
			print_permissions(print_key_permissions_file);
	}

	/* We should have an output key file. */
	if (newkeyfile == NULL)
		usage();

	/*
	 * It doesn't make sense to specify --passphrase-mem or
	 * --passphrase-time if we're not using a passphrase.
	 */
	if (((maxmem != 0) || (maxtime != 1.0)) && (passphrased == 0))
		usage();

	/* Warn the user if they're being silly. */
	if (keyswanted == 0) {
		warn0("None of {-r, -w, -d, --nuke} options are specified."
		    "  This will create a key file with no keys, which is"
		    " probably not what you intended.");
	}

	/* Read the specified key files. */
	while (argc-- > 0) {
		/*
		 * Suck in the key file.  We could mask this to only load the
		 * keys we want to copy, but there's no point really since we
		 * export keys selectively.
		 */
		if (keyfile_read(argv[0], &kfmachinenum, ~0)) {
			warnp("Cannot read key file: %s", argv[0]);
			exit(1);
		}

		/*
		 * Check that we're not using key files which belong to
		 * different machines.
		 */
		if (machinenum == (uint64_t)(-1)) {
			machinenum = kfmachinenum;
		} else if (machinenum != kfmachinenum) {
			warn0("Keys from %s do not belong to the "
			    "same machine as earlier keys", argv[0]);
			exit(1);
		}

		/* Move on to the next file. */
		argv++;
	}

	/* Make sure that we have the necessary keys. */
	if ((missingkey = crypto_keys_missing(keyswanted)) != NULL) {
		warn0("The %s key is required but not in any input key files",
		    missingkey);
		exit(1);
	}

	/* If the user wants to passphrase the keyfile, get the passphrase. */
	if (passphrased != 0) {
		if (readpass(&passphrase,
		    "Please enter passphrase for keyfile encryption",
		    "Please confirm passphrase for keyfile encryption", 1)) {
			warnp("Error reading password");
			exit(1);
		}
	} else {
		passphrase = NULL;
	}

	/* Write out new key file. */
	if (keyfile_write(newkeyfile, machinenum, keyswanted,
	    passphrase, maxmem, maxtime))
		exit(1);

	/* Success! */
	return (0);
}