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
|
||||
|
||||
|
||||
+6881
-4681
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -1083,6 +1086,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