mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
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:
@@ -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
@@ -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'/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user