diff options
author | наб <[email protected]> | 2021-05-13 06:21:35 +0200 |
---|---|---|
committer | Tony Hutter <[email protected]> | 2022-02-16 17:58:37 -0800 |
commit | 9cbc2ed20f710326d16e8fe7357999eaa3f90142 (patch) | |
tree | c02322a179938cb917608e5404e0f8eff85eaaca /lib | |
parent | 9b185de6fa9f1b3a7614448fe0116ed370ec7e2f (diff) |
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 <[email protected]>
Reviewed-by: Ryan Moeller <[email protected]>
Signed-off-by: Ahelenia Ziemiańska <[email protected]>
Issue #9543
Closes #9947
Closes #11956
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libzfs/Makefile.am | 2 | ||||
-rw-r--r-- | lib/libzfs/libzfs.abi | 73 | ||||
-rw-r--r-- | lib/libzfs/libzfs_crypto.c | 186 | ||||
-rw-r--r-- | lib/libzfs/libzfs_util.c | 8 |
4 files changed, 248 insertions, 21 deletions
diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am index 1a7698b47..31267fd9a 100644 --- a/lib/libzfs/Makefile.am +++ b/lib/libzfs/Makefile.am @@ -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 diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 82f8b7dc8..14e03ee28 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -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'/> diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index e31d4ce44..644dd2685 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -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 diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 6e57d8e42..7dd38bb3d 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -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); } |