libzfs: add keylocation=https://, backed by fetch(3) or libcurl

Add support for http and https to the keylocation properly to
allow encryption keys to be fetched from the specified URL.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Issue #9543
Closes #9947
Closes #11956
This commit is contained in:
наб
2021-05-13 06:21:35 +02:00
committed by Tony Hutter
parent 9b185de6fa
commit 9cbc2ed20f
31 changed files with 585 additions and 55 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ libzfs_la_LIBADD = \
$(abs_top_builddir)/lib/libnvpair/libnvpair.la \
$(abs_top_builddir)/lib/libuutil/libuutil.la
libzfs_la_LIBADD += -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LTLIBINTL)
libzfs_la_LIBADD += -lm $(LIBCRYPTO_LIBS) $(ZLIB_LIBS) $(LIBFETCH_LIBS) $(LTLIBINTL)
libzfs_la_LDFLAGS = -pthread
+53 -20
View File
@@ -551,10 +551,6 @@
<parameter type-id='e1c52942'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='unlink' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='os/linux/smb.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='a84c031d' size-in-bits='2040' id='11641789'>
@@ -1373,7 +1369,7 @@
<typedef-decl name='zpool_handle_t' type-id='67002a8a' id='b1efc708'/>
<typedef-decl name='libzfs_handle_t' type-id='c8a9d9d8' id='95942d0c'/>
<typedef-decl name='zfs_iter_f' type-id='5571cde4' id='d8e49ab9'/>
<class-decl name='libzfs_handle' size-in-bits='20224' is-struct='yes' visibility='default' id='c8a9d9d8'>
<class-decl name='libzfs_handle' size-in-bits='20352' is-struct='yes' visibility='default' id='c8a9d9d8'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='libzfs_error' type-id='95e97e5e' visibility='default'/>
</data-member>
@@ -1434,6 +1430,12 @@
<data-member access='public' layout-offset-in-bits='20160'>
<var-decl name='libzfs_max_nvlist' type-id='9c313c2d' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='20224'>
<var-decl name='libfetch' type-id='eaa32e2f' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='20288'>
<var-decl name='libfetch_load_error' type-id='26a90f95' visibility='default'/>
</data-member>
</class-decl>
<class-decl name='zfs_handle' size-in-bits='4928' is-struct='yes' visibility='default' id='f6ee4445'>
<data-member access='public' layout-offset-in-bits='0'>
@@ -3190,6 +3192,19 @@
<function-decl name='__ctype_b_loc' visibility='default' binding='global' size-in-bits='64'>
<return type-id='c59e1ef0'/>
</function-decl>
<function-decl name='dlopen' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='95e97e5e'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='dlsym' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='1b7446cd'/>
<parameter type-id='9d26089a'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='dlerror' visibility='default' binding='global' size-in-bits='64'>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='PKCS5_PBKDF2_HMAC_SHA1' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='95e97e5e'/>
@@ -3231,6 +3246,11 @@
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='fdopen' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='80f4b756'/>
<return type-id='822cd80b'/>
</function-decl>
<function-decl name='printf' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter is-variadic='yes'/>
@@ -3243,6 +3263,12 @@
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='asprintf' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='8c85230f'/>
<parameter type-id='9d26089a'/>
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='fputc' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='822cd80b'/>
@@ -3262,6 +3288,10 @@
<parameter type-id='e75a27e9'/>
<return type-id='b59d7dce'/>
</function-decl>
<function-decl name='rewind' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='822cd80b'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='ferror' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
@@ -3285,6 +3315,10 @@
<parameter type-id='b59d7dce'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='strdup' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='strerror' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<return type-id='26a90f95'/>
@@ -3317,6 +3351,10 @@
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='unlink' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-type size-in-bits='64' id='ee076206'>
<return type-id='48b5725f'/>
</function-type>
@@ -4425,12 +4463,6 @@
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='asprintf' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='8c85230f'/>
<parameter type-id='9d26089a'/>
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='strtol' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='9d26089a'/>
<parameter type-id='8c85230f'/>
@@ -4452,10 +4484,6 @@
<parameter type-id='b59d7dce'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='strdup' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='strrchr' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='95e97e5e'/>
@@ -4620,11 +4648,6 @@
<parameter type-id='4051f5e7'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='fdopen' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='80f4b756'/>
<return type-id='822cd80b'/>
</function-decl>
<function-decl name='pipe2' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='7292109c'/>
<parameter type-id='95e97e5e'/>
@@ -6705,6 +6728,12 @@
<parameter type-id='95e97e5e'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='avl_insert' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='a3681dea'/>
<parameter type-id='eaa32e2f'/>
<parameter type-id='fba6cb51'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='nvlist_lookup_boolean' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
@@ -7235,6 +7264,10 @@
<function-decl name='__ctype_toupper_loc' visibility='default' binding='global' size-in-bits='64'>
<return type-id='24f95ba5'/>
</function-decl>
<function-decl name='dlclose' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='eaa32e2f'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='regcomp' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5c53ba29'/>
<parameter type-id='9d26089a'/>
+186
View File
@@ -26,6 +26,16 @@
#include <signal.h>
#include <errno.h>
#include <openssl/evp.h>
#if LIBFETCH_DYNAMIC
#include <dlfcn.h>
#endif
#if LIBFETCH_IS_FETCH
#include <sys/param.h>
#include <stdio.h>
#include <fetch.h>
#elif LIBFETCH_IS_LIBCURL
#include <curl/curl.h>
#endif
#include <libzfs.h>
#include "libzfs_impl.h"
#include "zfeature_common.h"
@@ -59,9 +69,13 @@ static int caught_interrupt;
static int get_key_material_file(libzfs_handle_t *, const char *, const char *,
zfs_keyformat_t, boolean_t, uint8_t **, size_t *);
static int get_key_material_https(libzfs_handle_t *, const char *, const char *,
zfs_keyformat_t, boolean_t, uint8_t **, size_t *);
static zfs_uri_handler_t uri_handlers[] = {
{ "file", get_key_material_file },
{ "https", get_key_material_https },
{ "http", get_key_material_https },
{ NULL, NULL }
};
@@ -483,6 +497,178 @@ get_key_material_file(libzfs_handle_t *hdl, const char *uri,
return (ret);
}
static int
get_key_material_https(libzfs_handle_t *hdl, const char *uri,
const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey,
uint8_t **restrict buf, size_t *restrict len_out)
{
int ret = 0;
FILE *key = NULL;
boolean_t is_http = strncmp(uri, "http:", strlen("http:")) == 0;
if (strlen(uri) < (is_http ? 7 : 8)) {
ret = EINVAL;
goto end;
}
#if LIBFETCH_DYNAMIC
#define LOAD_FUNCTION(func) \
__typeof__(func) *func = dlsym(hdl->libfetch, #func);
if (hdl->libfetch == NULL)
hdl->libfetch = dlopen(LIBFETCH_SONAME, RTLD_LAZY);
if (hdl->libfetch == NULL) {
hdl->libfetch = (void *)-1;
char *err = dlerror();
if (err)
hdl->libfetch_load_error = strdup(err);
}
if (hdl->libfetch == (void *)-1) {
ret = ENOSYS;
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Couldn't load %s: %s"),
LIBFETCH_SONAME, hdl->libfetch_load_error ?: "(?)");
goto end;
}
boolean_t ok;
#if LIBFETCH_IS_FETCH
LOAD_FUNCTION(fetchGetURL);
char *fetchLastErrString = dlsym(hdl->libfetch, "fetchLastErrString");
ok = fetchGetURL && fetchLastErrString;
#elif LIBFETCH_IS_LIBCURL
LOAD_FUNCTION(curl_easy_init);
LOAD_FUNCTION(curl_easy_setopt);
LOAD_FUNCTION(curl_easy_perform);
LOAD_FUNCTION(curl_easy_cleanup);
LOAD_FUNCTION(curl_easy_strerror);
LOAD_FUNCTION(curl_easy_getinfo);
ok = curl_easy_init && curl_easy_setopt && curl_easy_perform &&
curl_easy_cleanup && curl_easy_strerror && curl_easy_getinfo;
#endif
if (!ok) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"keylocation=%s back-end %s missing symbols."),
is_http ? "http://" : "https://", LIBFETCH_SONAME);
ret = ENOSYS;
goto end;
}
#endif
#if LIBFETCH_IS_FETCH
key = fetchGetURL(uri, "");
if (key == NULL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Couldn't GET %s: %s"),
uri, fetchLastErrString);
ret = ENETDOWN;
}
#elif LIBFETCH_IS_LIBCURL
CURL *curl = curl_easy_init();
if (curl == NULL) {
ret = ENOTSUP;
goto end;
}
int kfd = -1;
#ifdef O_TMPFILE
kfd = open(getenv("TMPDIR") ?: "/tmp",
O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, 0600);
if (kfd != -1)
goto kfdok;
#endif
char *path;
if (asprintf(&path,
"%s/libzfs-XXXXXXXX.https", getenv("TMPDIR") ?: "/tmp") == -1) {
ret = ENOMEM;
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s"),
strerror(ret));
goto end;
}
kfd = mkostemps(path, strlen(".https"), O_CLOEXEC);
if (kfd == -1) {
ret = errno;
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Couldn't create temporary file %s: %s"),
path, strerror(ret));
free(path);
goto end;
}
(void) unlink(path);
free(path);
kfdok:
if ((key = fdopen(kfd, "r+")) == NULL) {
ret = errno;
free(path);
(void) close(kfd);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Couldn't reopen temporary file: %s"), strerror(ret));
goto end;
}
char errbuf[CURL_ERROR_SIZE] = "";
char *cainfo = getenv("SSL_CA_CERT_FILE"); /* matches fetch(3) */
char *capath = getenv("SSL_CA_CERT_PATH"); /* matches fetch(3) */
char *clcert = getenv("SSL_CLIENT_CERT_FILE"); /* matches fetch(3) */
char *clkey = getenv("SSL_CLIENT_KEY_FILE"); /* matches fetch(3) */
(void) curl_easy_setopt(curl, CURLOPT_URL, uri);
(void) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
(void) curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L);
(void) curl_easy_setopt(curl, CURLOPT_WRITEDATA, key);
(void) curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
if (cainfo != NULL)
(void) curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo);
if (capath != NULL)
(void) curl_easy_setopt(curl, CURLOPT_CAPATH, capath);
if (clcert != NULL)
(void) curl_easy_setopt(curl, CURLOPT_SSLCERT, clcert);
if (clkey != NULL)
(void) curl_easy_setopt(curl, CURLOPT_SSLKEY, clkey);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Failed to connect to %s: %s"),
uri, strlen(errbuf) ? errbuf : curl_easy_strerror(res));
ret = ENETDOWN;
} else {
long resp = 200;
(void) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp);
if (resp < 200 || resp >= 300) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Couldn't GET %s: %ld"),
uri, resp);
ret = ENOENT;
} else
rewind(key);
}
curl_easy_cleanup(curl);
#else
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"No keylocation=%s back-end."), is_http ? "http://" : "https://");
ret = ENOSYS;
#endif
end:
if (ret == 0)
ret = get_key_material_raw(key, keyformat, buf, len_out);
if (key != NULL)
fclose(key);
return (ret);
}
/*
* Attempts to fetch key material, no matter where it might live. The key
* material is allocated and returned in km_out. *can_retry_out will be set
+8
View File
@@ -44,6 +44,9 @@
#include <strings.h>
#include <unistd.h>
#include <math.h>
#if LIBFETCH_DYNAMIC
#include <dlfcn.h>
#endif
#include <sys/stat.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
@@ -1101,6 +1104,11 @@ libzfs_fini(libzfs_handle_t *hdl)
libzfs_core_fini();
regfree(&hdl->libzfs_urire);
fletcher_4_fini();
#if LIBFETCH_DYNAMIC
if (hdl->libfetch != (void *)-1 && hdl->libfetch != NULL)
(void) dlclose(hdl->libfetch);
free(hdl->libfetch_load_error);
#endif
free(hdl);
}