diff --git a/.github/workflows/zfs-tests-functional.yml b/.github/workflows/zfs-tests-functional.yml index 79973123fd41..d2b5764dbf80 100644 --- a/.github/workflows/zfs-tests-functional.yml +++ b/.github/workflows/zfs-tests-functional.yml @@ -26,7 +26,7 @@ jobs: xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \ libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \ libpam0g-dev pamtester python-dev python-setuptools python-cffi \ - python3 python3-dev python3-setuptools python3-cffi + python3 python3-dev python3-setuptools python3-cffi libcurl4-openssl-dev - name: Autogen.sh run: | sh autogen.sh diff --git a/.github/workflows/zfs-tests-sanity.yml b/.github/workflows/zfs-tests-sanity.yml index df089c81f4ce..9e2ed1b2f7cf 100644 --- a/.github/workflows/zfs-tests-sanity.yml +++ b/.github/workflows/zfs-tests-sanity.yml @@ -22,7 +22,7 @@ jobs: xfslibs-dev libattr1-dev libacl1-dev libudev-dev libdevmapper-dev \ libssl-dev libffi-dev libaio-dev libelf-dev libmount-dev \ libpam0g-dev pamtester python-dev python-setuptools python-cffi \ - python3 python3-dev python3-setuptools python3-cffi + python3 python3-dev python3-setuptools python3-cffi libcurl4-openssl-dev - name: Autogen.sh run: | sh autogen.sh diff --git a/config/Substfiles.am b/config/Substfiles.am index 63697bfa2b6a..911903e10e69 100644 --- a/config/Substfiles.am +++ b/config/Substfiles.am @@ -15,7 +15,9 @@ subst_sed_cmd = \ -e 's|@PYTHON[@]|$(PYTHON)|g' \ -e 's|@PYTHON_SHEBANG[@]|$(PYTHON_SHEBANG)|g' \ -e 's|@DEFAULT_INIT_NFS_SERVER[@]|$(DEFAULT_INIT_NFS_SERVER)|g' \ - -e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g' + -e 's|@DEFAULT_INIT_SHELL[@]|$(DEFAULT_INIT_SHELL)|g' \ + -e 's|@LIBFETCH_DYNAMIC[@]|$(LIBFETCH_DYNAMIC)|g' \ + -e 's|@LIBFETCH_SONAME[@]|$(LIBFETCH_SONAME)|g' SUBSTFILES = CLEANFILES = $(SUBSTFILES) diff --git a/config/user-libfetch.m4 b/config/user-libfetch.m4 new file mode 100644 index 000000000000..f5149fc1a5d7 --- /dev/null +++ b/config/user-libfetch.m4 @@ -0,0 +1,71 @@ +dnl # +dnl # Check for a libfetch - either fetch(3) or libcurl. +dnl # +dnl # There are two configuration dimensions: +dnl # * fetch(3) vs libcurl +dnl # * static vs dynamic +dnl # +dnl # fetch(3) is only dynamic. +dnl # We use sover 6, which first appeared in FreeBSD 8.0-RELEASE. +dnl # +dnl # libcurl development packages include curl-config(1) – we want: +dnl # * HTTPS support +dnl # * version at least 7.16 (October 2006), for sover 4 +dnl # * to decide if it's static or not +dnl # +AC_DEFUN([ZFS_AC_CONFIG_USER_LIBFETCH], [ + AC_MSG_CHECKING([for libfetch]) + LIBFETCH_LIBS= + LIBFETCH_IS_FETCH=0 + LIBFETCH_IS_LIBCURL=0 + LIBFETCH_DYNAMIC=0 + LIBFETCH_SONAME= + have_libfetch= + + saved_libs="$LIBS" + LIBS="$LIBS -lfetch" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include + ]], [fetchGetURL("", "");])], [ + have_libfetch=1 + LIBFETCH_IS_FETCH=1 + LIBFETCH_DYNAMIC=1 + LIBFETCH_SONAME='"libfetch.so.6"' + LIBFETCH_LIBS="-ldl" + AC_MSG_RESULT([fetch(3)]) + ], []) + LIBS="$saved_libs" + + if test -z "$have_libfetch"; then + if curl-config --protocols 2>/dev/null | grep -q HTTPS && + test "$(printf "%u" "0x$(curl-config --vernum)")" -ge "$(printf "%u" "0x071000")"; then + have_libfetch=1 + LIBFETCH_IS_LIBCURL=1 + if test "$(curl-config --built-shared)" = "yes"; then + LIBFETCH_DYNAMIC=1 + LIBFETCH_SONAME='"libcurl.so.4"' + LIBFETCH_LIBS="-ldl" + AC_MSG_RESULT([libcurl]) + else + LIBFETCH_LIBS="$(curl-config --libs)" + AC_MSG_RESULT([libcurl (static)]) + fi + + CCFLAGS="$CCFLAGS $(curl-config --cflags)" + fi + fi + + if test -z "$have_libfetch"; then + AC_MSG_RESULT([none]) + fi + + AC_SUBST([LIBFETCH_LIBS]) + AC_SUBST([LIBFETCH_DYNAMIC]) + AC_SUBST([LIBFETCH_SONAME]) + AC_DEFINE_UNQUOTED([LIBFETCH_IS_FETCH], [$LIBFETCH_IS_FETCH], [libfetch is fetch(3)]) + AC_DEFINE_UNQUOTED([LIBFETCH_IS_LIBCURL], [$LIBFETCH_IS_LIBCURL], [libfetch is libcurl]) + AC_DEFINE_UNQUOTED([LIBFETCH_DYNAMIC], [$LIBFETCH_DYNAMIC], [whether the chosen libfetch is to be loaded at run-time]) + AC_DEFINE_UNQUOTED([LIBFETCH_SONAME], [$LIBFETCH_SONAME], [soname of chosen libfetch]) +]) diff --git a/config/user.m4 b/config/user.m4 index e799faffb61c..670820b37715 100644 --- a/config/user.m4 +++ b/config/user.m4 @@ -22,6 +22,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [ ZFS_AC_CONFIG_USER_LIBCRYPTO ZFS_AC_CONFIG_USER_LIBAIO ZFS_AC_CONFIG_USER_LIBATOMIC + ZFS_AC_CONFIG_USER_LIBFETCH ZFS_AC_CONFIG_USER_CLOCK_GETTIME ZFS_AC_CONFIG_USER_PAM ZFS_AC_CONFIG_USER_RUNSTATEDIR diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index c545c8838e30..416282f009de 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -56,6 +56,11 @@ install() { # Fallback: Guess the path and include all matches dracut_install /usr/lib/gcc/*/*/libgcc_s.so* fi + if [ @LIBFETCH_DYNAMIC@ != 0 ]; then + for d in $libdirs; do + [ -e "$d"/@LIBFETCH_SONAME@ ] && dracut_install "$d"/@LIBFETCH_SONAME@ + done + fi dracut_install @mounthelperdir@/mount.zfs dracut_install @udevdir@/vdev_id dracut_install awk diff --git a/contrib/dracut/90zfs/zfs-env-bootfs.service.in b/contrib/dracut/90zfs/zfs-env-bootfs.service.in index 2bc43482c187..e143cb5ec1ed 100644 --- a/contrib/dracut/90zfs/zfs-env-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-env-bootfs.service.in @@ -8,7 +8,7 @@ Before=zfs-import.target [Service] Type=oneshot -ExecStart=/bin/sh -c "systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')" +ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')" [Install] WantedBy=zfs-import.target diff --git a/contrib/dracut/90zfs/zfs-load-key.sh.in b/contrib/dracut/90zfs/zfs-load-key.sh.in index 9b7716ae9e25..6f7f268f9bff 100755 --- a/contrib/dracut/90zfs/zfs-load-key.sh.in +++ b/contrib/dracut/90zfs/zfs-load-key.sh.in @@ -43,13 +43,14 @@ if [ "$(zpool list -H -o feature@encryption "$(echo "${BOOTFS}" | awk -F/ '{prin [ "$KEYSTATUS" = "unavailable" ] || exit 0 # if key is stored in a file, do not prompt if ! [ "${KEYLOCATION}" = "prompt" ]; then + if ! [ "${KEYLOCATION#https://}" = "${KEYLOCATION}" ]; then + systemctl start network-online.target + fi zfs load-key "${ENCRYPTIONROOT}" else # decrypt them - TRY_COUNT=5 - while [ $TRY_COUNT -gt 0 ]; do + for _ in 1 2 3 4 5; do systemd-ask-password "Encrypted ZFS password for ${BOOTFS}" --no-tty | zfs load-key "${ENCRYPTIONROOT}" && break - TRY_COUNT=$((TRY_COUNT - 1)) done fi fi diff --git a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in index 0d45f71eadce..bdc246943208 100644 --- a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in @@ -10,5 +10,5 @@ ConditionKernelCommandLine=bootfs.rollback # ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"' RemainAfterExit=yes diff --git a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in index 11513ba27b01..6ea13850c3a7 100644 --- a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in @@ -10,5 +10,5 @@ ConditionKernelCommandLine=bootfs.snapshot # ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"' RemainAfterExit=yes diff --git a/contrib/initramfs/hooks/zfs.in b/contrib/initramfs/hooks/zfs.in index 0a9cc87720ad..414852625650 100755 --- a/contrib/initramfs/hooks/zfs.in +++ b/contrib/initramfs/hooks/zfs.in @@ -63,6 +63,14 @@ mkdir -p "$DESTDIR/etc/" # multi-arch installations. cp --target-directory="$DESTDIR" --parents $(find /lib/ -type f -name libgcc_s.so.1) +if [ @LIBFETCH_DYNAMIC@ != 0 ] +then + for l in $(find /lib/ -name @LIBFETCH_SONAME@) + do + copy_exec "$l" + done +fi + for ii in $COPY_EXEC_LIST do copy_exec "$ii" diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs index b7e9e57035f3..d74b2062ad7c 100644 --- a/contrib/initramfs/scripts/zfs +++ b/contrib/initramfs/scripts/zfs @@ -406,28 +406,25 @@ decrypt_fs() KEYSTATUS="$(get_fs_value "${ENCRYPTIONROOT}" keystatus)" # Continue only if the key needs to be loaded [ "$KEYSTATUS" = "unavailable" ] || return 0 - TRY_COUNT=3 - # If key is stored in a file, do not prompt + # Do not prompt if key is stored noninteractively, if ! [ "${KEYLOCATION}" = "prompt" ]; then $ZFS load-key "${ENCRYPTIONROOT}" # Prompt with plymouth, if active - elif [ -e /bin/plymouth ] && /bin/plymouth --ping 2>/dev/null; then + elif /bin/plymouth --ping 2>/dev/null; then echo "plymouth" > /run/zfs_console_askpwd_cmd - while [ $TRY_COUNT -gt 0 ]; do + for _ in 1 2 3; do plymouth ask-for-password --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}" | \ $ZFS load-key "${ENCRYPTIONROOT}" && break - TRY_COUNT=$((TRY_COUNT - 1)) done # Prompt with systemd, if active elif [ -e /run/systemd/system ]; then echo "systemd-ask-password" > /run/zfs_console_askpwd_cmd - while [ $TRY_COUNT -gt 0 ]; do + for _ in 1 2 3; do systemd-ask-password "Encrypted ZFS password for ${ENCRYPTIONROOT}" --no-tty | \ $ZFS load-key "${ENCRYPTIONROOT}" && break - TRY_COUNT=$((TRY_COUNT - 1)) done # Prompt with ZFS tty, otherwise diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index 4f44909bf22c..a2389daea46a 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -69,6 +69,8 @@ struct libzfs_handle { boolean_t libzfs_prop_debug; regex_t libzfs_urire; uint64_t libzfs_max_nvlist; + void *libfetch; + char *libfetch_load_error; }; struct zfs_handle { diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am index 1a7698b4760e..31267fd9a5e9 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 935c0419c4bd..4530f5676ff3 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -6,6 +6,7 @@ + @@ -422,39 +423,40 @@ - + + - + - + - + - + - + - + - + - + - + - + - + @@ -559,333 +561,358 @@ - + - + - + - - - + + - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + - + - + - + - + - + - + - + - + - + - + - - - - - - + + + + + + - - + + - - + + + - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - - + + - - + + - - - + + + - + - + - + - + - + - + - + - + - + - - + + - - - - - - - + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - + + + + + + + + + @@ -893,34 +920,34 @@ - - + + - + - + - + - + - + - + - + - + - + @@ -930,2335 +957,3544 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + - - + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + + + + + + + + - - + + + + + - - + + + - - + + + - - + + + + - - + + + + - - + + + - - + + + - - + + + - - + + + + - - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + - - + + + + + - - + + + - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - + + + + + - - - - - + + + - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - - + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + - - - - + + + - - - + + + + + + + - - - + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + - - + + + - - + + - - + + + - - + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + + + + - - + + + - - + + + - - + + + - - + + + + - - + + + + + + - - + + + + - - + + + - - + + + + - - + + + - - + + + - - + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + - - + + + - - + + + - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + - - + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + - - + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + + - - + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - + + + + - - - - - - - + + + + + + + + + + + + - - - - - + + + + + - - + + + - - + + + - - + + + + + - - + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + - - + + + + + - - + + + + + + - - + + + - - + + + + + - + - + - + - + - + - + - - + + - + - - + + - - + + - - + + - - - - + + + + + + + + + + + + + + + + - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + - - - + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - + + + + - - - + + + - - - + + + + - - - + + + + - - - + + + - - - - + + + - - - - + + + + - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + - - + + + + + + + + - - - - - - - - - - - - - + - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - + + + + + + - - - - + + + - - - - - - - - + + + - + + + + + + + + + + + + + @@ -3282,987 +4518,2176 @@ - - - - - - + + + + + - - - - - + + + - - - - - + + + - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - - - - + + + - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - + + + + - - - - - + + + - - - - - - - + + - - - + + + + + - - - - - - + + + - - - - - - + + + + + + - - - + + + + - - - - - + + + + + - - - - + + + + - - - + + + + + + - - - + + + + - - - + + - - - - - - + + + + + + + + + + + + + - - - - - - - + + + + - - - + + + - - - + + + - - - - + + + - - - - - - + + + - - - - + + + + - - - - - + + + + + + + + + + + + - - - - - - + + + + - - - - - + + + + + + - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - + + + + - - - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + - + - - - - - + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + - - + + + + - - + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + + - - + + + + + - - + + + + + - - + + + + - - + + + - - + + + + - - + + + - - + + + + - - + + + + + + + + + + - - + + + + + - - + + + + - - + + + + - - + + + + + + - - + + + + - - + + + + + + + + + + + + + + - - + + + + + + + - - + + + + - - + + + + + - - + + + + + + + - - + + + + + + + - - + + + + + - - + + + + + - - + + + + + + + + + + + + + - - + + + + + + - - + + + + - - + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + - - + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + - + - + - - - - + - - - - + - - - - + - + - - + + + + + + + + - + + + + + + + + + + + + + - - - - - - - - - - - - - + - + - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + + + - - + + - - + + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + - - - - - - + + + + + - - - - + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + + - - + + + + + + - - + + + - - + + + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + - - + + - - + + - - + + + + + + - - + + - - + + - - + + - - + + - - + + + - - + + - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + - - + + + - - - - - - - + + + - - + + - - - + + + - - + + - - - - - - - - - - - - - - + + + - - - - - + + + - - - + + + - - - - - - + + + - + + + + + + + - + - - + + - - + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + @@ -4271,852 +6696,650 @@ - + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + - - - - - + + + + - - - - - - + + + - - - - - + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - + + + + + + + + + + + + + + + + + + + - - + + - - + + - - - - + + + + + + - - + + + - - + + + - - - - - - + + + + + - + - + + + + - + + + + - + - + - + - - - - + - + + + + - + - - + + - - + + - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + - - + + + + - - + + + + + - - + + + - - + + + + + + + + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - + - - + + - + - + - + - + - - + + - - + + - - + + - - - - - - - - - - - - + + + + + + - - - - - + + + + + - - + + - - + + - - - - - + + + + + - - - - + + + + + + + + + - - + + + + - - - - - + + + + + - - + + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - - - + + + + - - + + - - - - - + + + + - - - - + + + - - - + + + - - - + + + + - - - + + + + - - - + + + - - + + - - - - - - - + + + - - + + + - - - - - - - - - - - - - - - - + + - - - + + + - - - - + + + + - - - + + + + + + + - - + + + - + - + - + - + @@ -5151,15 +7374,33 @@ - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + @@ -5173,959 +7414,924 @@ - + - - - - - - - - - - - - - - - - - - - + + + + + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - - - - - - - - - - - - + - + - + - - + + - + - + - + - - + + - + - + - + - - + + - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - + + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - + + + - - - + + + + + + + + + - - - - - + + + + + + + + + + + - - - - - + + + + + - - - - - - - + + + + - - - - - - - - + + + + + + + + + + + - - - + + + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + + - - - - - + + + + + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - + + + + - - - - - + + + + + - - - + + + + + - - - - - + + + + - - - - - + + + + + - - + + - - - - + + + + - - - + + + + + + + + + + + + + + + + + - - - + + + + + + + + + - - - + + + + + + + + + - - - - + + + + + + + + - - - + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + + + - - - + + + + + + + + + + + + - - - + + + + - - - - - - - - - - + + + + + - - - - + + + + - - - - + + + - - - - - + + - - - - + + - - - - - - - - - - - + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + - - + + + - - + + + + - - + + + - - + + + - - + + + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - - + + - - - + + + - - - + + + - - - + + + - - + + - - - + + + - - - + + + - - - + + + - - + + + + + - - - - - - - + + + + + - - - - - + + + + - - - - + + + - - - - - + + + - - - - - + + - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - + + + + + + - - - + + + + + + - - - + + + + + - - - - + + + + - - - + + + + - - - - - - + + + + + - + + + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - + + + - - + + - - + + - + + + + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index 5fb93d265965..d9ced2499ee6 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -26,6 +26,16 @@ #include #include #include +#if LIBFETCH_DYNAMIC +#include +#endif +#if LIBFETCH_IS_FETCH +#include +#include +#include +#elif LIBFETCH_IS_LIBCURL +#include +#endif #include #include "libzfs_impl.h" #include "zfeature_common.h" @@ -59,9 +69,12 @@ 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 }, { NULL, NULL } }; @@ -483,6 +496,177 @@ 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; + + if (strlen(uri) < 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=https:// back-end %s missing symbols."), + 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=https:// back-end.")); + 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 7840e3590a57..fdb574651d71 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -44,6 +44,9 @@ #include #include #include +#if LIBFETCH_DYNAMIC +#include +#endif #include #include #include @@ -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); } diff --git a/man/man8/zfsprops.8 b/man/man8/zfsprops.8 index 9ae77e7bfeb0..14308cd5b686 100644 --- a/man/man8/zfsprops.8 +++ b/man/man8/zfsprops.8 @@ -1085,7 +1085,7 @@ encryption suite cannot be changed after dataset creation, the keyformat can be with .Nm zfs Cm change-key . .It Xo -.Sy keylocation Ns = Ns Sy prompt Ns | Ns Sy file:// Ns Em +.Sy keylocation Ns = Ns Sy prompt Ns | Ns Sy file:// Ns Em Ns | Ns Sy https:// Ns Em
.Xc Controls where the user's encryption key will be loaded from by default for commands such as @@ -1109,7 +1109,22 @@ to access the encrypted data (see for details). This setting will also allow the key to be passed in via STDIN, but users should be careful not to place keys which should be kept secret on the command line. If a file URI is selected, the key will be loaded from the -specified absolute file path. +specified absolute file path. If an HTTPS URL is selected, it will be GETted +using +.Xr fetch 3 , +libcurl, or nothing, depending on compile-time configuration and run-time +availability. The +.Ev SSL_CA_CERT_FILE +environment variable can be set to set the location +of the concatenated certificate store. The +.Ev SSL_CA_CERT_PATH +environment variable can be set to override the location +of the directory containing the certificate authority bundle. The +.Ev SSL_CLIENT_CERT_FILE +and +.Ev SSL_CLIENT_KEY_FILE +environment variables can be set to configure the path +to the client certificate and its key. .It Sy pbkdf2iters Ns = Ns Ar iterations Controls the number of PBKDF2 iterations that a .Sy passphrase diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 402d749c1aeb..4c50feadbc43 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -583,7 +583,7 @@ zfs_prop_init(void) "ENCROOT"); zprop_register_string(ZFS_PROP_KEYLOCATION, "keylocation", "none", PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, - "prompt | ", "KEYLOCATION"); + "prompt | | ", "KEYLOCATION"); zprop_register_string(ZFS_PROP_REDACT_SNAPS, "redact_snaps", NULL, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "[,...]", @@ -936,6 +936,8 @@ zfs_prop_valid_keylocation(const char *str, boolean_t encrypted) return (B_TRUE); else if (strlen(str) > 8 && strncmp("file:///", str, 8) == 0) return (B_TRUE); + else if (strlen(str) > 8 && strncmp("https://", str, 8) == 0) + return (B_TRUE); return (B_FALSE); } diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index f1aa649cb060..f2757f1185be 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -198,7 +198,8 @@ tags = ['functional', 'cli_root', 'zfs_inherit'] [tests/functional/cli_root/zfs_load-key] tests = ['zfs_load-key', 'zfs_load-key_all', 'zfs_load-key_file', - 'zfs_load-key_location', 'zfs_load-key_noop', 'zfs_load-key_recursive'] + 'zfs_load-key_https', 'zfs_load-key_location', 'zfs_load-key_noop', + 'zfs_load-key_recursive'] tags = ['functional', 'cli_root', 'zfs_load-key'] [tests/functional/cli_root/zfs_mount] diff --git a/tests/runfiles/sanity.run b/tests/runfiles/sanity.run index b1d2c73de959..ad4495144cda 100644 --- a/tests/runfiles/sanity.run +++ b/tests/runfiles/sanity.run @@ -146,7 +146,8 @@ tags = ['functional', 'cli_root', 'zfs_inherit'] [tests/functional/cli_root/zfs_load-key] tests = ['zfs_load-key', 'zfs_load-key_all', 'zfs_load-key_file', - 'zfs_load-key_location', 'zfs_load-key_noop', 'zfs_load-key_recursive'] + 'zfs_load-key_https', 'zfs_load-key_location', 'zfs_load-key_noop', + 'zfs_load-key_recursive'] tags = ['functional', 'cli_root', 'zfs_load-key'] [tests/functional/cli_root/zfs_mount] diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/Makefile.am index 03c2916387ef..7dfec435ce7f 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/Makefile.am @@ -5,6 +5,7 @@ dist_pkgdata_SCRIPTS = \ zfs_load-key.ksh \ zfs_load-key_all.ksh \ zfs_load-key_file.ksh \ + zfs_load-key_https.ksh \ zfs_load-key_location.ksh \ zfs_load-key_noop.ksh \ zfs_load-key_recursive.ksh diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup.ksh index 79cd6e9f908e..d397bcf4e9f0 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup.ksh @@ -26,5 +26,7 @@ # . $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib +cleanup_https default_cleanup diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/setup.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/setup.ksh index 6a9af3bc28c3..6cc5528ce5d7 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/setup.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/setup.ksh @@ -26,7 +26,10 @@ # . $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib DISK=${DISKS%% *} -default_setup $DISK +default_setup_noexit $DISK +setup_https +log_pass diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg index 2f01aac7c0a2..cc1e3b330543 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg @@ -27,3 +27,31 @@ export HEXKEY="000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" export HEXKEY1="201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A090807060504030201" export RAWKEY="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" export RAWKEY1="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + +export SSL_CA_CERT_FILE="/$TESTPOOL/snakeoil.crt" +export HTTPS_PORT_FILE="/$TESTPOOL/snakeoil.port" +export HTTPS_HOSTNAME="localhost" +export HTTPS_PORT= +export HTTPS_BASE_URL= + +function get_https_port +{ + if [ -z "$HTTPS_PORT" ]; then + read -r HTTPS_PORT < "$HTTPS_PORT_FILE" || return + fi + + echo "$HTTPS_PORT" +} + +function get_https_base_url +{ + if [ -z "$HTTPS_BASE_URL" ]; then + HTTPS_BASE_URL="https://$HTTPS_HOSTNAME:$(get_https_port)" || { + typeset ret=$? + HTTPS_BASE_URL= + return $ret + } + fi + + echo "$HTTPS_BASE_URL" +} diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all.ksh index 5e331fd1200d..96710bf9a800 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all.ksh @@ -39,6 +39,8 @@ function cleanup { datasetexists $TESTPOOL/$TESTFS1 && \ log_must zfs destroy $TESTPOOL/$TESTFS1 + datasetexists $TESTPOOL/$TESTFS2 && \ + log_must zfs destroy $TESTPOOL/$TESTFS2 datasetexists $TESTPOOL/zvol && log_must zfs destroy $TESTPOOL/zvol poolexists $TESTPOOL1 && log_must destroy_pool $TESTPOOL1 } @@ -50,6 +52,9 @@ log_must eval "echo $PASSPHRASE1 > /$TESTPOOL/pkey" log_must zfs create -o encryption=on -o keyformat=passphrase \ -o keylocation=file:///$TESTPOOL/pkey $TESTPOOL/$TESTFS1 +log_must zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=$(get_https_base_url)/PASSPHRASE $TESTPOOL/$TESTFS2 + log_must zfs create -V 64M -o encryption=on -o keyformat=passphrase \ -o keylocation=file:///$TESTPOOL/pkey $TESTPOOL/zvol @@ -60,6 +65,9 @@ log_must zpool create -O encryption=on -O keyformat=passphrase \ log_must zfs unmount $TESTPOOL/$TESTFS1 log_must zfs unload-key $TESTPOOL/$TESTFS1 +log_must zfs unmount $TESTPOOL/$TESTFS2 +log_must zfs unload-key $TESTPOOL/$TESTFS2 + log_must zfs unload-key $TESTPOOL/zvol log_must zfs unmount $TESTPOOL1 @@ -70,8 +78,10 @@ log_must zfs load-key -a log_must key_available $TESTPOOL1 log_must key_available $TESTPOOL/zvol log_must key_available $TESTPOOL/$TESTFS1 +log_must key_available $TESTPOOL/$TESTFS2 log_must zfs mount $TESTPOOL1 log_must zfs mount $TESTPOOL/$TESTFS1 +log_must zfs mount $TESTPOOL/$TESTFS2 log_pass "'zfs load-key -a' loads keys for all datasets" diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib index d9066f9cbf57..f7461437c615 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib @@ -99,3 +99,66 @@ function verify_origin return 0 } + +function setup_https +{ + log_must openssl req -x509 -newkey rsa:4096 -sha256 -days 1 -nodes -keyout "/$TESTPOOL/snakeoil.key" -out "$SSL_CA_CERT_FILE" -subj "/CN=$HTTPS_HOSTNAME" + + python3 -uc " +import http.server, ssl, sys, os, time, random + +sys.stdin.close() + +httpd, err, port = None, None, None +for i in range(1, 100): + port = random.randint(0xC000, 0xFFFF) # ephemeral range + try: + httpd = http.server.HTTPServer(('$HTTPS_HOSTNAME', port), http.server.SimpleHTTPRequestHandler) + break + except: + err = sys.exc_info()[1] + time.sleep(i / 100) +if not httpd: + raise err + +with open('$HTTPS_PORT_FILE', 'w') as portf: + print(port, file=portf) + +httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, keyfile='/$TESTPOOL/snakeoil.key', certfile='$SSL_CA_CERT_FILE', ssl_version=ssl.PROTOCOL_TLS) + +os.chdir('$STF_SUITE/tests/functional/cli_root/zfs_load-key') + +with open('/$TESTPOOL/snakeoil.pid', 'w') as pidf: + if os.fork() != 0: + os._exit(0) + print(os.getpid(), file=pidf) + +sys.stdout.close() +sys.stderr.close() +try: + sys.stdout = sys.stderr = open('/tmp/ZTS-snakeoil.log', 'w', buffering=1) # line +except: + sys.stdout = sys.stderr = open('/dev/null', 'w') + +print('{} start on {}'.format(os.getpid(), port)) +httpd.serve_forever() +" || log_fail + + typeset https_pid= + for d in $(seq 0 0.1 5); do + read -r https_pid 2>/dev/null < "/$TESTPOOL/snakeoil.pid" && [ -n "$https_pid" ] && break + sleep "$d" + done + [ -z "$https_pid" ] && log_fail "Couldn't start HTTPS server" + log_note "Started HTTPS server as $https_pid on port $(get_https_port)" +} + +function cleanup_https +{ + typeset https_pid= + read -r https_pid 2>/dev/null < "/$TESTPOOL/snakeoil.pid" || return 0 + + log_must kill "$https_pid" + cat /tmp/ZTS-snakeoil.log + rm -f "/$TESTPOOL/snakeoil.pid" "/tmp/ZTS-snakeoil.log" +} diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_https.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_https.ksh new file mode 100755 index 000000000000..cac9c4140322 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_https.ksh @@ -0,0 +1,78 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib + +# +# DESCRIPTION: +# 'zfs load-key' should load a dataset's key from an https:// URL, +# but fail to do so if the domain doesn't exist or the file 404s. +# +# STRATEGY: +# 1. Try to create a dataset pointing to an RFC6761-guaranteed unresolvable domain, +# one to the sshd port (which will be either unoccupied (ECONNREFUSED) +# or have sshd on it ("wrong version number")). +# and one pointing to an URL that will always 404. +# 2. Create encrypted datasets with keylocation=https://address +# 3. Unmount the datasets and unload their keys +# 4. Attempt to load the keys +# 5. Verify the keys are loaded +# 6. Attempt to mount the datasets +# + +verify_runnable "both" + +function cleanup +{ + for fs in "$TESTFS1" "$TESTFS2" "$TESTFS3"; do + datasetexists $TESTPOOL/$fs && \ + log_must zfs destroy $TESTPOOL/$fs + done +} +log_onexit cleanup + +log_assert "'zfs load-key' should load a key from a file" + +log_mustnot zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=https://invalid./where-ever $TESTPOOL/$TESTFS1 + +log_mustnot zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=https://$HTTPS_HOSTNAME:22 $TESTPOOL/$TESTFS1 + +log_mustnot zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=$(get_https_base_url)/ENOENT $TESTPOOL/$TESTFS1 + +log_must zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=$(get_https_base_url)/PASSPHRASE $TESTPOOL/$TESTFS1 + +log_must zfs create -o encryption=on -o keyformat=hex \ + -o keylocation=$(get_https_base_url)/HEXKEY $TESTPOOL/$TESTFS2 + +log_must zfs create -o encryption=on -o keyformat=raw \ + -o keylocation=$(get_https_base_url)/RAWKEY $TESTPOOL/$TESTFS3 + +for fs in "$TESTFS1" "$TESTFS2" "$TESTFS3"; do + log_must zfs unmount $TESTPOOL/$fs + log_must zfs unload-key $TESTPOOL/$fs +done +for fs in "$TESTFS1" "$TESTFS2" "$TESTFS3"; do + log_must zfs load-key $TESTPOOL/$fs + log_must key_available $TESTPOOL/$fs + log_must zfs mount $TESTPOOL/$fs +done + +log_pass "'zfs load-key' loads a key from a file" diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location.ksh index d0b1cdb20ec7..2b0a6a292eed 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location.ksh @@ -70,4 +70,9 @@ log_must eval "echo $PASSPHRASE | zfs load-key -L prompt $TESTPOOL/$TESTFS1" log_must key_available $TESTPOOL/$TESTFS1 log_must verify_keylocation $TESTPOOL/$TESTFS1 "file://$key_location" +log_must zfs unload-key $TESTPOOL/$TESTFS1 +log_must zfs load-key -L $(get_https_base_url)/PASSPHRASE $TESTPOOL/$TESTFS1 +log_must key_available $TESTPOOL/$TESTFS1 +log_must verify_keylocation $TESTPOOL/$TESTFS1 "file://$key_location" + log_pass "'zfs load-key -L' overrides keylocation with provided value" diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive.ksh index 7385b69cf5fe..0435383ad0c5 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive.ksh @@ -52,15 +52,21 @@ log_must zfs create -o encryption=on -o keyformat=passphrase \ log_must zfs create -o keyformat=passphrase \ -o keylocation=file:///$TESTPOOL/pkey $TESTPOOL/$TESTFS1/child +log_must zfs create -o keyformat=passphrase \ + -o keylocation=$(get_https_base_url)/PASSPHRASE $TESTPOOL/$TESTFS1/child/child + log_must zfs unmount $TESTPOOL/$TESTFS1 +log_must zfs unload-key $TESTPOOL/$TESTFS1/child/child log_must zfs unload-key $TESTPOOL/$TESTFS1/child log_must zfs unload-key $TESTPOOL/$TESTFS1 log_must zfs load-key -r $TESTPOOL log_must key_available $TESTPOOL/$TESTFS1 log_must key_available $TESTPOOL/$TESTFS1/child +log_must key_available $TESTPOOL/$TESTFS1/child/child log_must zfs mount $TESTPOOL/$TESTFS1 log_must zfs mount $TESTPOOL/$TESTFS1/child +log_must zfs mount $TESTPOOL/$TESTFS1/child/child log_pass "'zfs load-key -r' recursively loads keys" diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation.ksh index 0d2e7ab8f298..7a6bf75dace2 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation.ksh @@ -46,11 +46,12 @@ function cleanup { datasetexists $TESTPOOL/$TESTFS1 && \ log_must zfs destroy -r $TESTPOOL/$TESTFS1 + cleanup_https } log_onexit cleanup -log_assert "Key location can only be 'prompt' or a file path for encryption" \ - "roots, and 'none' for unencrypted volumes" +log_assert "Key location can only be 'prompt', 'file://', or 'https://'" \ + "for encryption roots, and 'none' for unencrypted volumes" log_must eval "echo $PASSPHRASE > /$TESTPOOL/pkey" @@ -64,19 +65,15 @@ log_must zfs create -o encryption=on -o keyformat=passphrase \ -o keylocation=file:///$TESTPOOL/pkey $TESTPOOL/$TESTFS1 log_mustnot zfs set keylocation=none $TESTPOOL/$TESTFS1 -if true; then - log_mustnot zfs set keylocation=/$TESTPOOL/pkey $TESTPOOL/$TESTFS1 -else - ### SOON: ### - # file:///$TESTPOOL/pkey and /$TESTPOOL/pkey are equivalent on FreeBSD - # thanks to libfetch. Eventually we want to make the other platforms - # work this way as well, either by porting libfetch or by other means. - log_must zfs set keylocation=/$TESTPOOL/pkey $TESTPOOL/$TESTFS1 -fi +log_mustnot zfs set keylocation=/$TESTPOOL/pkey $TESTPOOL/$TESTFS1 log_must zfs set keylocation=file:///$TESTPOOL/pkey $TESTPOOL/$TESTFS1 log_must verify_keylocation $TESTPOOL/$TESTFS1 "file:///$TESTPOOL/pkey" +setup_https +log_must zfs set keylocation=$(get_https_base_url)/PASSPHRASE $TESTPOOL/$TESTFS1 +log_must verify_keylocation $TESTPOOL/$TESTFS1 "$(get_https_base_url)/PASSPHRASE" + log_must zfs set keylocation=prompt $TESTPOOL/$TESTFS1 log_must verify_keylocation $TESTPOOL/$TESTFS1 "prompt" @@ -97,5 +94,5 @@ log_mustnot zfs set keylocation=/$TESTPOOL/pkey $TESTPOOL/$TESTFS1/child log_must verify_keylocation $TESTPOOL/$TESTFS1/child "none" -log_pass "Key location can only be 'prompt' or a file path for encryption" \ - "roots, and 'none' for unencrypted volumes" +log_pass "Key location can only be 'prompt', 'file://', or 'https://'" \ + "for encryption roots, and 'none' for unencrypted volumes"