Print this page
@@ -75,10 +75,11 @@
static int zfs_do_send(int argc, char **argv);
static int zfs_do_receive(int argc, char **argv);
static int zfs_do_promote(int argc, char **argv);
static int zfs_do_allow(int argc, char **argv);
static int zfs_do_unallow(int argc, char **argv);
+static int zfs_do_key(int argc, char **argv);
/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
*/
@@ -114,11 +115,12 @@
HELP_SHARE,
HELP_SNAPSHOT,
HELP_UNMOUNT,
HELP_UNSHARE,
HELP_ALLOW,
- HELP_UNALLOW
+ HELP_UNALLOW,
+ HELP_KEY
} zfs_help_t;
typedef struct zfs_command {
const char *name;
int (*func)(int argc, char **argv);
@@ -160,10 +162,12 @@
{ "receive", zfs_do_receive, HELP_RECEIVE },
{ NULL },
{ "allow", zfs_do_allow, HELP_ALLOW },
{ NULL },
{ "unallow", zfs_do_unallow, HELP_UNALLOW },
+ { NULL },
+ { "key", zfs_do_key, HELP_KEY },
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
zfs_command_t *current_command;
@@ -248,10 +252,13 @@
"<filesystem|volume>\n"
"\tunallow [-r] -c [<perm|@setname>[,...]] "
"<filesystem|volume>\n"
"\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
"<filesystem|volume>\n"));
+ case HELP_KEY:
+ return (gettext("\tkey <-l | -u | -c [ -o <property=value>]> "
+ "<-a | filesystem>\n"));
}
abort();
/* NOTREACHED */
}
@@ -3059,11 +3066,13 @@
}
/*
* Ignore any filesystems which don't apply to us. This
* includes those with a legacy mountpoint, or those with
- * legacy share options.
+ * legacy share options. We also have to ignore those
+ * that are encrypted that don't currently have their
+ * key available.
*/
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
@@ -3128,11 +3137,27 @@
return (1);
} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
return (0);
}
+
/*
+ * Only need to check for ZFS_CRYPT_KEY_UNAVAILABLE since
+ * datasets that aren't encrypted have a keystatus of
+ * ZFS_CRYPT_KEY_UNDEFINED.
+ */
+ if (zfs_mount_crypto_check(zhp) != 0) {
+ if (!explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': "
+ "encryption key unavailable\n"), cmdname,
+ zfs_get_name(zhp));
+ return (1);
+ }
+
+ /*
* At this point, we have verified that the mountpoint and/or
* shareopts are appropriate for auto management. If the
* filesystem is already mounted or shared, return (failing
* for explicit requests); otherwise mount or share the
* filesystem.
@@ -3348,11 +3373,13 @@
/* check number of arguments */
if (do_all) {
zfs_handle_t **dslist = NULL;
size_t i, count = 0;
char *protocol = NULL;
+ char bypass[ZPOOL_MAXPROPLEN] = { 0 };
+
if (op == OP_MOUNT) {
types = ZFS_TYPE_FILESYSTEM;
} else if (argc > 0) {
if (strcmp(argv[0], "nfs") == 0 ||
strcmp(argv[0], "smb") == 0) {
@@ -3382,16 +3409,45 @@
return (0);
qsort(dslist, count, sizeof (void *), dataset_cmp);
for (i = 0; i < count; i++) {
+
if (verbose)
report_mount_progress(i, count);
- if (share_mount_one(dslist[i], op, flags, protocol,
- B_FALSE, options) != 0)
- ret = 1;
+ /*
+ * If bypass has a dataset value, then we need to skip
+ * any datasets that are underneath it.
+ */
+ if (bypass[0] != NULL) {
+ int len = strlen(bypass);
+ char *ds_name = (char *)zfs_get_name(dslist[i]);
+
+ if (strncmp(bypass, ds_name, len) == 0 &&
+ (strlen(ds_name) > len) &&
+ ds_name[len] == '/') {
+ zfs_close(dslist[i]);
+ continue;
+ } else
+ bypass[0] = '\0';
+ }
+
+ /*
+ * Check if the dataset has a key before loading, if
+ * no, then store it in 'bypass'.
+ */
+ if (zfs_mount_crypto_check(dslist[i])) {
+ (void) strlcpy(bypass, zfs_get_name(dslist[i]),
+ ZPOOL_MAXPROPLEN);
+ } else {
+ if (share_mount_one(dslist[i], op, flags,
+ protocol, B_FALSE, options) != 0) {
+ ret = 1;
+ }
+ }
+
zfs_close(dslist[i]);
}
free(dslist);
} else if (argc == 0) {
@@ -4077,10 +4133,207 @@
}
return (unshare_unmount_path(OP_MOUNT, argv[0], flags, B_TRUE));
}
+int
+zfs_do_key(int argc, char **argv)
+{
+ int error = 1, options = 0;
+ nvlist_t *props = NULL;
+ char c, *propname, *propval = NULL;
+ boolean_t load = B_FALSE, unload = B_FALSE, change = B_FALSE;
+ boolean_t do_all = B_FALSE;
+ char *strval;
+ zfs_handle_t **dslist = NULL, *zhp = NULL;
+ uint_t count;
+ zfs_prop_t zprop;
+
+ while ((c = getopt(argc, argv, "aluco:")) != -1) {
+ switch (c) {
+ case 'a':
+ do_all = B_TRUE;
+ break;
+
+ case 'l':
+ load = B_TRUE;
+ break;
+
+ case 'u':
+ unload = B_TRUE;
+ break;
+
+ case 'c':
+ change = B_TRUE;
+ break;
+
+ case 'o':
+ /* Key change is the only command that allows options */
+ if (change != B_TRUE) {
+ (void) fprintf(stderr, gettext("Property "
+ "options only allowed during key "
+ "change.\n"));
+ usage(B_FALSE);
+ goto error;
+ }
+
+ propname = optarg;
+ if ((propval = strchr(optarg, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -o option\n"));
+ goto error;
+ }
+
+ *propval = '\0';
+ propval++;
+
+ zprop = zfs_name_to_prop(propname);
+ switch (zprop) {
+ case ZFS_PROP_KEYSOURCE:
+ case ZFS_PROP_KEYSCOPE:
+ break;
+
+ default:
+ (void) fprintf(stderr, gettext("Invalid "
+ "property for key operation: '%s'\n"),
+ propname);
+ goto error;
+ };
+
+ if (props == NULL &&
+ nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ goto error;
+ }
+
+ if (nvlist_lookup_string(props, propname,
+ &strval) == 0) {
+ (void) fprintf(stderr, gettext("property '%s' "
+ "specified multiple times\n"), propname);
+ goto error;
+ }
+ if (nvlist_add_string(props, propname, propval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ goto error;
+ }
+
+ options += 2;
+ break;
+
+ case '?':
+ default:
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+
+ }
+ }
+
+ if (!change && props != NULL)
+ (void) fprintf(stderr, gettext("Properties are not allowed to "
+ "be used in this command.\n"));
+
+ if (((load || unload) && (argc > 3)) ||
+ (change && ((argc - options) > 3))) {
+ (void) fprintf(stderr,
+ gettext("too many arguments\n"));
+ usage(B_FALSE);
+ goto error;
+ } else if ((load || unload) && (argc < 3)) {
+ (void) fprintf(stderr, gettext("missing dataset "
+ "argument (specify -a for all)\n"));
+ usage(B_FALSE);
+ goto error;
+ } else if (change && ((argc - options) < 3)) {
+ (void) fprintf(stderr, gettext("missing dataset "
+ "argument\n"));
+ usage(B_FALSE);
+ goto error;
+ }
+
+ if (do_all == B_FALSE) {
+ zhp = zfs_open(g_zfs, argv[argc - 1],
+ ZFS_TYPE_FILESYSTEM|ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
+ goto error;
+
+ } else if (change) {
+ /* We don't support do_all in a change operation */
+
+ (void) fprintf(stderr, gettext("cannot use '-a' with "
+ "change operation.\n"));
+ usage(B_FALSE);
+ goto error;
+
+ } else {
+ get_all_datasets(ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+ &dslist, &count, B_FALSE);
+ if (count == 0)
+ return (0);
+
+ qsort(dslist, count, sizeof (void *), dataset_cmp);
+ }
+
+ if (load) {
+ if (do_all) {
+ int i;
+ zfs_crypt_t *cry = NULL;
+
+ cry = calloc(1, sizeof (zfs_crypt_t));
+ for (i = 0; i < count; i++) {
+ if (zfs_is_encrypted(dslist[i])) {
+ zfs_set_libzfs_cry(dslist[i], cry);
+ (void) zfs_load_key(dslist[i]);
+ bzero(cry, sizeof (zfs_crypt_t));
+ }
+ zfs_close(dslist[i]);
+ }
+
+ free(cry);
+ free(dslist);
+ error = 0;
+
+ } else
+ error = zfs_cmd_key_load(zhp);
+
+ } else if (unload) {
+ if (do_all) {
+ int i;
+
+ /* Do in reverse order so we can unmount easily */
+ for (i = count - 1; i > 0; i--) {
+ if (zfs_is_encrypted(dslist[i]))
+ (void) zfs_unload_key(dslist[i]);
+
+ zfs_close(dslist[i]);
+ }
+
+ free(dslist);
+ error = 0;
+
+ } else
+ error = zfs_cmd_key_unload(zhp);
+
+ } else if (change) {
+ error = zfs_cmd_key_change(zhp, props);
+
+ } else
+ usage(B_FALSE);
+
+ if (zhp != NULL)
+ zfs_close(zhp);
+
+error:
+ if (props != NULL) {
+ nvlist_free(props);
+ }
+ return (error);
+}
+
+
static int
volcheck(zpool_handle_t *zhp, void *data)
{
boolean_t isinit = *((boolean_t *)data);