Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
0
/*
 * 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);
}
Esempio n. 3
0
/*
 * 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);
}
Esempio n. 4
0
/*
 * 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);
}