/* * Function: be_get_zone_be_list * Description: Finds all the BEs for this zone on the system. * Parameters: * zone_be_name - The name of the BE to look up. * zone_be_container_ds - The dataset for the zone. * zbe_nodes - A reference pointer to the list of BEs. The list * structure will be allocated here and must * be freed by a call to be_free_list. If there are no * BEs found on the system this reference will be * set to NULL. * Return: * BE_SUCCESS - Success * be_errno_t - Failure * Scope: * Semi-private (library wide use only) */ int be_get_zone_be_list( /* LINTED */ char *zone_be_name, char *zone_be_container_ds, be_node_list_t **zbe_nodes) { zfs_handle_t *zhp = NULL; list_callback_data_t cb = { 0 }; int ret = BE_SUCCESS; if (zbe_nodes == NULL) return (BE_ERR_INVAL); if (!zfs_dataset_exists(g_zfs, zone_be_container_ds, ZFS_TYPE_FILESYSTEM)) { return (BE_ERR_BE_NOENT); } zone_be = B_TRUE; if ((zhp = zfs_open(g_zfs, zone_be_container_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { be_print_err(gettext("be_get_zone_be_list: failed to open " "the zone BE dataset %s: %s\n"), zone_be_container_ds, libzfs_error_description(g_zfs)); ret = zfs_err_to_be_err(g_zfs); goto cleanup; } (void) strcpy(be_container_ds, zone_be_container_ds); if (cb.be_nodes_head == NULL) { if ((cb.be_nodes_head = be_list_alloc(&ret, sizeof (be_node_list_t))) == NULL) { ZFS_CLOSE(zhp); goto cleanup; } cb.be_nodes = cb.be_nodes_head; } if (ret == 0) ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb); ZFS_CLOSE(zhp); *zbe_nodes = cb.be_nodes_head; cleanup: zone_be = B_FALSE; return (ret); }
/* * spec is a string like "A,B%C,D" * * <snaps>, where <snaps> can be: * <snap> (single snapshot) * <snap>%<snap> (range of snapshots, inclusive) * %<snap> (range of snapshots, starting with earliest) * <snap>% (range of snapshots, ending with last) * % (all snapshots) * <snaps>[,...] (comma separated list of the above) * * If a snapshot can not be opened, continue trying to open the others, but * return ENOENT at the end. */ int zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig, zfs_iter_f func, void *arg) { char *buf, *comma_separated, *cp; int err = 0; int ret = 0; buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig); cp = buf; while ((comma_separated = strsep(&cp, ",")) != NULL) { char *pct = strchr(comma_separated, '%'); if (pct != NULL) { snapspec_arg_t ssa = { 0 }; ssa.ssa_func = func; ssa.ssa_arg = arg; if (pct == comma_separated) ssa.ssa_seenfirst = B_TRUE; else ssa.ssa_first = comma_separated; *pct = '\0'; ssa.ssa_last = pct + 1; /* * If there is a lastname specified, make sure it * exists. */ if (ssa.ssa_last[0] != '\0') { char snapname[ZFS_MAXNAMELEN]; (void) snprintf(snapname, sizeof (snapname), "%s@%s", zfs_get_name(fs_zhp), ssa.ssa_last); if (!zfs_dataset_exists(fs_zhp->zfs_hdl, snapname, ZFS_TYPE_SNAPSHOT)) { ret = ENOENT; continue; } } err = zfs_iter_snapshots_sorted(fs_zhp, snapspec_cb, &ssa); if (ret == 0) ret = err; if (ret == 0 && (!ssa.ssa_seenfirst || (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) { ret = ENOENT; } } else { char snapname[ZFS_MAXNAMELEN]; zfs_handle_t *snap_zhp; (void) snprintf(snapname, sizeof (snapname), "%s@%s", zfs_get_name(fs_zhp), comma_separated); snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl, snapname); if (snap_zhp == NULL) { ret = ENOENT; continue; } err = func(snap_zhp, arg); if (ret == 0) ret = err; } } free(buf); return (ret); }
/* * Function: be_get_list_callback * Description: Callback function used by zfs_iter to look through all * the pools on the system looking for BEs. If a BE name was * specified only that BE's information will be collected and * returned. * Parameters: * zlp - handle to the first zfs dataset. (provided by the * zfs_iter_* call) * data - pointer to the callback data and where we'll pass * the BE information back. * Returns: * 0 - Success * be_errno_t - Failure * Scope: * Private */ static int be_get_list_callback(zpool_handle_t *zlp, void *data) { list_callback_data_t *cb = (list_callback_data_t *)data; char be_ds[MAXPATHLEN]; char *open_ds = NULL; char *rpool = NULL; zfs_handle_t *zhp = NULL; int ret = 0; cb->zpool_name = rpool = (char *)zpool_get_name(zlp); /* * Generate string for the BE container dataset */ be_make_container_ds(rpool, be_container_ds, sizeof (be_container_ds)); /* * If a BE name was specified we use it's root dataset in place of * the container dataset. This is because we only want to collect * the information for the specified BE. */ if (cb->be_name != NULL) { if (!be_valid_be_name(cb->be_name)) return (BE_ERR_INVAL); /* * Generate string for the BE root dataset */ be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds)); open_ds = be_ds; } else { open_ds = be_container_ds; } /* * Check if the dataset exists */ if (!zfs_dataset_exists(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) { /* * The specified dataset does not exist in this pool or * there are no valid BE's in this pool. Try the next zpool. */ zpool_close(zlp); return (0); } if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { be_print_err(gettext("be_get_list_callback: failed to open " "the BE dataset %s: %s\n"), open_ds, libzfs_error_description(g_zfs)); ret = zfs_err_to_be_err(g_zfs); zpool_close(zlp); return (ret); } /* * If a BE name was specified we iterate through the datasets * and snapshots for this BE only. Otherwise we will iterate * through the next level of datasets to find all the BE's * within the pool */ if (cb->be_name != NULL) { if (cb->be_nodes_head == NULL) { if ((cb->be_nodes_head = be_list_alloc(&ret, sizeof (be_node_list_t))) == NULL) { ZFS_CLOSE(zhp); zpool_close(zlp); return (ret); } cb->be_nodes = cb->be_nodes_head; } if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name, rpool, cb->current_be, be_ds)) != BE_SUCCESS) { ZFS_CLOSE(zhp); zpool_close(zlp); return (ret); } ret = zfs_iter_snapshots(zhp, be_add_children_callback, cb); } if (ret == 0) ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb); ZFS_CLOSE(zhp); zpool_close(zlp); return (ret); }
/* * zfs_crypto_zckey * * Called for creating new filesystems and clones and receiving. * * For encryption != off get the key material. */ int zfs_crypto_zckey(libzfs_handle_t *hdl, zfs_crypto_zckey_t cmd, nvlist_t *props, zfs_cmd_t *zc) { uint64_t crypt = ZIO_CRYPT_INHERIT, pcrypt = ZIO_CRYPT_DEFAULT; char *keysource = NULL; int ret = 0; int keystatus; zfs_handle_t *pzhp = NULL; boolean_t inherit_crypt = B_TRUE; boolean_t inherit_keysource = B_TRUE; boolean_t recv_existing = B_FALSE; boolean_t recv_clone = B_FALSE; boolean_t keysource_free = B_FALSE; zprop_source_t propsrctype = ZPROP_SRC_DEFAULT; char propsrc[ZFS_MAXNAMELEN]; char errbuf[1024]; char target[MAXNAMELEN]; char parent[MAXNAMELEN]; char *strval; zfs_cmd_target_dsname(zc, cmd, target, sizeof (target)); if (zfs_parent_name(target, parent, sizeof (parent)) != 0) parent[0] = '\0'; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), target); if (props != NULL) { if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &strval) == 0) { (void) zfs_prop_string_to_index(ZFS_PROP_ENCRYPTION, strval, &crypt); inherit_crypt = B_FALSE; } else if (nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &crypt) == 0) { inherit_crypt = B_FALSE; } else { inherit_crypt = B_TRUE; } if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_KEYSOURCE), &keysource) == 0) { inherit_keysource = B_FALSE; } } if (cmd == ZFS_CRYPTO_CREATE) { pzhp = make_dataset_handle(hdl, parent); } else if (cmd == ZFS_CRYPTO_CLONE) { zfs_handle_t *szhp = make_dataset_handle(hdl, zc->zc_value); if (szhp == NULL) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent not found")); (void) zfs_error(hdl, EZFS_NOENT, errbuf); ret = -1; goto out; } crypt = zfs_prop_get_int(szhp, ZFS_PROP_ENCRYPTION); zfs_close(szhp); pzhp = make_dataset_handle(hdl, parent); } else if (cmd == ZFS_CRYPTO_RECV) { if (zfs_dataset_exists(hdl, target, ZFS_TYPE_DATASET)) { pzhp = make_dataset_handle(hdl, target); pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION); if (crypt != pcrypt && crypt != ZIO_CRYPT_INHERIT) { const char *stream_crypt_str = NULL; const char *pcrypt_str = NULL; (void) zfs_prop_index_to_string( ZFS_PROP_ENCRYPTION, pcrypt, &pcrypt_str); (void) zfs_prop_index_to_string( ZFS_PROP_ENCRYPTION, crypt, &stream_crypt_str); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "stream encryption '%s'(%llu) differs " "from receiving dataset value '%s'(%llu)"), stream_crypt_str, crypt, pcrypt_str, pcrypt); ret = -1; goto out; } inherit_crypt = B_TRUE; inherit_keysource = B_TRUE; recv_existing = B_TRUE; } else { if (strlen(zc->zc_string) != 0) { pzhp = make_dataset_handle(hdl, zc->zc_string); recv_clone = B_TRUE; } else { pzhp = make_dataset_handle(hdl, parent); } } } if (cmd != ZFS_CRYPTO_PCREATE) { if (pzhp == NULL) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent not found")); (void) zfs_error(hdl, EZFS_NOENT, errbuf); ret = -1; goto out; } pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION); } if (pcrypt != ZIO_CRYPT_OFF && crypt == ZIO_CRYPT_OFF) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " "encryption value. dataset must be encrypted.")); (void) zfs_error(hdl, EZFS_KEYERR, errbuf); ret = -1; goto out; } if (crypt == ZIO_CRYPT_INHERIT) { crypt = pcrypt; } /* * If we have nothing to do then bail out, but make one last check * that keysource wasn't specified when there is no crypto going on. */ if (crypt == ZIO_CRYPT_OFF && !inherit_keysource) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "keysource " "can not be specified when encryption is off.")); (void) zfs_error(hdl, EZFS_KEYERR, errbuf); ret = -1; goto out; } else if (crypt == ZIO_CRYPT_OFF) { ret = 0; goto out; } /* * Need to pass down the inherited crypt value so that * dsl_crypto_key_gen() can see the same that we saw. */ zc->zc_crypto.zic_crypt = crypt; zc->zc_crypto.zic_clone_newkey = hdl->libzfs_crypt.zc_clone_newkey; /* * Here we have encryption on so we need to find a valid keysource * property. * * Now lets see if we have an explicit setting for keysource and * we have validate it; otherwise, if we inherit then it is already * validated. */ if (!inherit_keysource) { if (!zfs_valid_keysource(keysource)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid keysource \"%s\""), keysource); (void) zfs_error(hdl, EZFS_KEYERR, errbuf); ret = -1; goto out; } /* * If keysource is local then encryption has to be as well * otherwise we could end up with the wrong sized keys. */ if (inherit_crypt) { VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION), crypt) == 0); VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_CHECKSUM), ZIO_CHECKSUM_SHA256_MAC) == 0); } } else { /* Get the already validated keysource from our parent */ keysource = zfs_alloc(hdl, ZFS_MAXNAMELEN); if (keysource == NULL) { ret = no_memory(hdl); goto out; } keysource_free = B_TRUE; if (pzhp != NULL && zfs_prop_get(pzhp, ZFS_PROP_KEYSOURCE, keysource, ZFS_MAXNAMELEN, &propsrctype, propsrc, sizeof (propsrc), FALSE) != 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "keysource must be provided.")); (void) zfs_error(hdl, EZFS_KEYERR, errbuf); ret = -1; goto out; } if (recv_existing) { (void) strlcpy(propsrc, target, sizeof (propsrc)); } else if (recv_clone) { (void) strlcpy(propsrc, zc->zc_string, sizeof (propsrc)); } else if (propsrctype == ZPROP_SRC_LOCAL || propsrctype == ZPROP_SRC_RECEIVED) { (void) strlcpy(propsrc, parent, sizeof (propsrc)); } else if (propsrctype == ZPROP_SRC_DEFAULT && pcrypt == ZIO_CRYPT_OFF) { /* * "Default" to "passphrase,prompt". The obvious * thing to do would be to set this in zfs_prop.c * as the property default. However that doesn't * work here because we don't want keysource set * for datasets that have encryption=off. If we * ever change the default to encryption=on then * the default of keysource can change too. * This is needed because of how inheritance happens * with defaulted properties, they show up as * "default" not "inherit" but we need "inherit" * to find the wrapping key if we are actually * inheriting keysource. */ inherit_keysource = B_FALSE; if (props == NULL) { VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0)); } (void) strlcpy(keysource, "passphrase,prompt", ZFS_MAXNAMELEN); VERIFY(nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_KEYSOURCE), keysource) == 0); VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION), crypt) == 0); VERIFY(nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_CHECKSUM), ZIO_CHECKSUM_SHA256_MAC) == 0); goto load_key; } else if (propsrctype == ZPROP_SRC_DEFAULT && pcrypt != ZIO_CRYPT_OFF) { abort(); #if 0 // FIXME } else if (strcmp(propsrc, ZONE_INVISIBLE_SOURCE) == 0) { /* * Assume key is available and handle failure ioctl * ENOKEY errors later. */ zc->zc_crypto.zic_cmd = ZFS_IOC_CRYPTO_KEY_INHERIT; (void) strlcpy(zc->zc_crypto.zic_inherit_dsname, propsrc, sizeof (zc->zc_crypto.zic_inherit_dsname)); ret = 0; goto out; #endif } else if (propsrctype != ZPROP_SRC_DEFAULT) { if (pzhp != NULL) zfs_close(pzhp); VERIFY((pzhp = make_dataset_handle(hdl, propsrc)) != 0); } keystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS); /* * AVAILABLE we are done other than filling in who we * are inheriting the wrapping key from. * * UNAVAILABLE we need to load the key of a higher level * dataset. */ if (keystatus == ZFS_CRYPT_KEY_AVAILABLE) { zc->zc_crypto.zic_cmd = ZFS_IOC_CRYPTO_KEY_INHERIT; (void) strlcpy(zc->zc_crypto.zic_inherit_dsname, propsrc, sizeof (zc->zc_crypto.zic_inherit_dsname)); ret = 0; goto out; } else if (keystatus == ZFS_CRYPT_KEY_UNAVAILABLE) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "zfs key -l %s required."), parent); (void) zfs_error(hdl, EZFS_KEYERR, errbuf); ret = -1; goto out; } } load_key: if (!zfs_can_prompt_if_needed(keysource)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "unable to prompt for key material keysource = \"%s\"\n"), keysource); errno = ENOTTY; return (-1); } ret = key_hdl_to_zc(hdl, NULL, keysource, crypt, zc, cmd); if (ret != 0) { ret = -1; (void) zfs_error(hdl, EZFS_KEYERR, errbuf); goto out; } zc->zc_crypto.zic_cmd = ZFS_IOC_CRYPTO_KEY_LOAD; ret = 0; out: if (pzhp) zfs_close(pzhp); if (keysource_free) free(keysource); return (ret); }