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);