From c424a82f95f88ba69af94174d3c58bccd5134063 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 6 Oct 2023 09:17:39 -0400 Subject: [PATCH 01/54] Implement minimal dnssec/trust ad, initial code If linking to libssh2 then also link to resolv Add boolean option repo-sftp-require-trust-ad default false First cut at help text for option, !!! TBD noted for changes if needed before finalizing Update autoconf and meson build instructions for resolv --- meson.build | 1 + src/build/config/config.yaml | 8 +++ src/build/configure.ac | 10 ++++ src/build/help/help.xml | 11 ++++ src/config/config.auto.h | 3 +- src/config/parse.auto.c.inc | 87 ++++++++++++++++++++++++++++++ src/configure | 13 ++++- src/meson.build | 1 + src/storage/sftp/helper.c | 3 +- src/storage/sftp/storage.c | 70 ++++++++++++++++++++++++ src/storage/sftp/storage.h | 1 + test/src/command/test/build.c | 1 + test/src/module/storage/sftpTest.c | 2 + 13 files changed, 208 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 20bf84e013..d1e9280633 100644 --- a/meson.build +++ b/meson.build @@ -172,6 +172,7 @@ lib_ssh2 = dependency('libssh2', required: false) if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') + lib_resolv = cc.find_library('resolv') endif # Find optional zstd library diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index a8ff09b30f..8ea1fa9b4c 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2460,6 +2460,14 @@ option: command: repo-type depend: repo-sftp-host + repo-sftp-require-trust-ad: + section: global + group: repo + type: boolean + default: false + command: repo-type + depend: repo-sftp-host + repo-storage-verify-tls: section: global group: repo diff --git a/src/build/configure.ac b/src/build/configure.ac index 78e03d7bd5..2ba3f3a6d9 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -124,6 +124,16 @@ AC_CHECK_LIB( [AC_CHECK_HEADER(libssh2_sftp.h, [], [AC_MSG_ERROR([header file is required])])]) +# Check optional resolv library if we have libssh2 +# ---------------------------------------------------------------------------------------------------------------------------------- +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + AC_SUBST(LIBS, "${LIBS} -lresolv") +# AC_CHECK_LIB([resolv], [res_ninit], [], [AC_MSG_ERROR([library 'resolv' is required])]) +# AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) +fi + + # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- AC_CHECK_LIB( diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 8b9c94d7a5..d91108188c 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1059,6 +1059,17 @@ path + + SFTP Require Trust-Ad. + + +

!!! TBD - Perform a minimal host verification via DNSSEC. This verification assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. It queries the DNS server for the host and SSHFP records with RES_TRUSTAD (ad bit) set. If the response ad bit is not set, the host is not trusted. If the ad is is set a check will be made for a matching key in the SSHFP records.

+
+ + n + y +
+ SFTP repository host. diff --git a/src/config/config.auto.h b/src/config/config.auto.h index cb9204c01f..41a2aa0916 100644 --- a/src/config/config.auto.h +++ b/src/config/config.auto.h @@ -136,7 +136,7 @@ Option constants #define CFGOPT_TYPE "type" #define CFGOPT_VERBOSE "verbose" -#define CFG_OPTION_TOTAL 179 +#define CFG_OPTION_TOTAL 180 /*********************************************************************************************************************************** Option value constants @@ -528,6 +528,7 @@ typedef enum cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, cfgOptRepoSftpPublicKeyFile, + cfgOptRepoSftpRequireTrustAd, cfgOptRepoStorageCaFile, cfgOptRepoStorageCaPath, cfgOptRepoStorageHost, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 609baa1c24..51a795ed75 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8733,6 +8733,92 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-public-key-file ), // opt/repo-sftp-public-key-file // ----------------------------------------------------------------------------------------------------------------------------- + PARSE_RULE_OPTION // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_NAME("repo-sftp-require-trust-ad"), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTIONAL // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-require-trust-ad + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-require-trust-ad + ( // opt/repo-sftp-require-trust-ad + PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + ), // opt/repo-sftp-require-trust-ad + // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-storage-ca-file ( // opt/repo-storage-ca-file PARSE_RULE_OPTION_NAME("repo-storage-ca-file"), // opt/repo-storage-ca-file @@ -10988,6 +11074,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order cfgOptRepoSftpPublicKeyFile, // opt-resolve-order + cfgOptRepoSftpRequireTrustAd, // opt-resolve-order cfgOptRepoStorageCaFile, // opt-resolve-order cfgOptRepoStorageCaPath, // opt-resolve-order cfgOptRepoStorageHost, // opt-resolve-order diff --git a/src/configure b/src/configure index 958124800e..fde0453a3a 100755 --- a/src/configure +++ b/src/configure @@ -4185,6 +4185,17 @@ fi fi +# Check optional resolv library if we have libssh2 +# ---------------------------------------------------------------------------------------------------------------------------------- +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + LIBS="${LIBS} -lresolv" + +# AC_CHECK_LIB([resolv], [res_ninit], [], [AC_MSG_ERROR([library 'resolv' is required])]) +# AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) +fi + + # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZSTD_isError in -lzstd" >&5 @@ -5750,4 +5761,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 e9fe59c2eda5217a0f6476af90083fafb8b24f94 +# Generated from src/build/configure.ac sha1 692faa9c4a3f68029c6713122e78a7491631bfdc diff --git a/src/meson.build b/src/meson.build index 779e510a3b..3f8194eaa6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -277,6 +277,7 @@ executable( lib_lz4, lib_pq, lib_ssh2, + lib_resolv, lib_xml, lib_z, lib_zstd, diff --git a/src/storage/sftp/helper.c b/src/storage/sftp/helper.c index 7a1321a226..5723e07324 100644 --- a/src/storage/sftp/helper.c +++ b/src/storage/sftp/helper.c @@ -39,7 +39,8 @@ storageSftpHelper(const unsigned int repoIdx, const bool write, StoragePathExpre .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .knownHosts = knownHosts); + .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index c592c208e3..7de8b16905 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -17,6 +17,15 @@ SFTP Storage #include "storage/sftp/storage.intern.h" #include "storage/sftp/write.h" +#include + +// jrt !!! remove netdb.h, et al if not needed after testing/dev +// !!! jrt is this viable/acceptable +#ifndef __USE_MISC +#define __USE_MISC 1 +#endif +#include + /*********************************************************************************************************************************** Define PATH_MAX if it is not defined ***********************************************************************************************************************************/ @@ -24,6 +33,10 @@ Define PATH_MAX if it is not defined #define PATH_MAX (4 * 1024) #endif +#ifndef PACKET_SZ +#define PACKET_SZ 65535 +#endif + /*********************************************************************************************************************************** Object type ***********************************************************************************************************************************/ @@ -1064,6 +1077,58 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c FUNCTION_LOG_RETURN(BOOL, result); } +/*********************************************************************************************************************************** +Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the +hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated on the fact that +the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is secure. +***********************************************************************************************************************************/ +void +storageSftpTrustAd(const String *const host) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(STRING, host); + FUNCTION_LOG_END(); + + ASSERT(host != NULL); + + // Initialize the resolver + struct __res_state res_state; + memset(&res_state, 0, sizeof(res_state)); + + if ((res_state.options & RES_INIT) == 0 && res_ninit(&res_state ) == -1) + THROW_FMT(ServiceError, "unable to initialize resolver"); + + // Set the resolver to use TRUSTAD and return RRSIG records + res_state.options |= RES_USE_DNSSEC | RES_USE_EDNS0 | RES_TRUSTAD; + + unsigned char answer[PACKET_SZ]; + + // Query the server for the host + int len = res_nquery(&res_state, strZ(host), C_IN, T_A, answer, sizeof(answer)); + + if (len < 0) + { + res_nclose(&res_state); + + THROW_FMT(ServiceError, "res_nquery error '%s'", hstrerror(h_errno)); + } + + // Check the ad flag + HEADER *hdr = (HEADER *)answer; + if (hdr->ad != 1) + THROW_FMT(ServiceError, "RES_TRUSTAD not set in response"); + + // Parse the response + + ns_msg handle; + ns_initparse(answer, len, &handle); + + // Close the resolver + res_nclose(&res_state); + + FUNCTION_LOG_RETURN_VOID(); +} + /**********************************************************************************************************************************/ static const StorageInterface storageInterfaceSftp = { @@ -1098,6 +1163,7 @@ storageSftpNew( FUNCTION_LOG_PARAM(STRING_LIST, param.knownHosts); FUNCTION_LOG_PARAM(MODE, param.modeFile); FUNCTION_LOG_PARAM(MODE, param.modePath); + FUNCTION_LOG_PARAM(BOOL, param.trustAd); FUNCTION_LOG_PARAM(BOOL, param.write); FUNCTION_LOG_PARAM(FUNCTIONP, param.pathExpressionFunction); FUNCTION_LOG_END(); @@ -1315,6 +1381,10 @@ storageSftpNew( libssh2_knownhost_free(knownHostsList); } + if (param.trustAd) + storageSftpTrustAd(host); + + // Perform public key authorization, expand leading tilde key file paths if needed String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); String *const pubKeyPath = diff --git a/src/storage/sftp/storage.h b/src/storage/sftp/storage.h index 5d9a558824..abcc388f85 100644 --- a/src/storage/sftp/storage.h +++ b/src/storage/sftp/storage.h @@ -36,6 +36,7 @@ typedef struct StorageSftpNewParam StringId hostKeyCheckType; const String *hostFingerprint; const StringList *knownHosts; + const bool trustAd; } StorageSftpNewParam; #define storageSftpNewP(path, host, port, user, timeout, keyPriv, hostKeyHashType, ...) \ diff --git a/test/src/command/test/build.c b/test/src/command/test/build.c index 3e23524e7f..b090e885e6 100644 --- a/test/src/command/test/build.c +++ b/test/src/command/test/build.c @@ -556,6 +556,7 @@ testBldUnit(TestBuild *const this) " lib_lz4,\n" " lib_pq,\n" " lib_ssh2,\n" + " lib_resolv,\n" " lib_xml,\n" " lib_yaml,\n" " lib_z,\n" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 4846e417b4..a7a1886ff2 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1118,6 +1118,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; @@ -1134,6 +1135,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( From c86aca2f4bb5b9f757de780fac29e81db673a4a3 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Sun, 8 Oct 2023 09:40:47 -0400 Subject: [PATCH 02/54] Perform checklib for libresolv Update tests --- src/build/configure.ac | 5 +- src/configure | 57 +++++++++++++++++++++-- src/storage/sftp/storage.c | 2 +- test/src/module/storage/sftpTest.c | 74 ++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 8 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index 2ba3f3a6d9..514fef0776 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -128,9 +128,8 @@ AC_CHECK_LIB( # ---------------------------------------------------------------------------------------------------------------------------------- if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" then - AC_SUBST(LIBS, "${LIBS} -lresolv") -# AC_CHECK_LIB([resolv], [res_ninit], [], [AC_MSG_ERROR([library 'resolv' is required])]) -# AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) + AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) + AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) fi diff --git a/src/configure b/src/configure index fde0453a3a..b14aa9c680 100755 --- a/src/configure +++ b/src/configure @@ -4189,10 +4189,59 @@ fi # ---------------------------------------------------------------------------------------------------------------------------------- if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" then - LIBS="${LIBS} -lresolv" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +printf %s "checking for ns_initparse in -lresolv... " >&6; } +if test ${ac_cv_lib_resolv_ns_initparse+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char ns_initparse (); +int +main (void) +{ +return ns_initparse (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_resolv_ns_initparse=yes +else $as_nop + ac_cv_lib_resolv_ns_initparse=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_ns_initparse" >&5 +printf "%s\n" "$ac_cv_lib_resolv_ns_initparse" >&6; } +if test "x$ac_cv_lib_resolv_ns_initparse" = xyes +then : + printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h + + LIBS="-lresolv $LIBS" + +else $as_nop + as_fn_error $? "library 'resolv' is required" "$LINENO" 5 +fi + + ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" +if test "x$ac_cv_header_resolv_h" = xyes +then : + +else $as_nop + as_fn_error $? "header file is required" "$LINENO" 5 +fi -# AC_CHECK_LIB([resolv], [res_ninit], [], [AC_MSG_ERROR([library 'resolv' is required])]) -# AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) fi @@ -5761,4 +5810,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 692faa9c4a3f68029c6713122e78a7491631bfdc +# Generated from src/build/configure.ac sha1 75d6effef8179480c54966cbbfb9213f70e45c1e diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 7de8b16905..d651de663b 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1110,7 +1110,7 @@ storageSftpTrustAd(const String *const host) { res_nclose(&res_state); - THROW_FMT(ServiceError, "res_nquery error '%s'", hstrerror(h_errno)); + THROW_FMT(ServiceError, "res_nquery error '%s' for host '%s'", hstrerror(h_errno), strZ(host)); } // Check the ad flag diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index a7a1886ff2..6f3c45aa8b 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1106,6 +1106,80 @@ testRun(void) HRNLIBSSH2_MACRO_SHUTDOWN() }); + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + storageTest = NULL; + + TEST_ASSIGN( + storageTest, + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, + .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), + .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), + .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), + .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + "new storage (defaults)"); + TEST_RESULT_LOG( + "P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to " + "'/home/" TEST_USER "/.ssh/known_hosts'\n" + "P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'"); + + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file RSA, trustAd"); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]", + .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_ADDC, + .param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, + {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = 0}, + {.function = HRNLIBSSH2_SFTP_INIT}, + HRNLIBSSH2_MACRO_SHUTDOWN() + }); + argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptStanza, "test"); hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); From c2c9ff6e093fed9bb259a391dc2d12562b08f435 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Sun, 8 Oct 2023 22:23:33 -0400 Subject: [PATCH 03/54] Add libresolv harness files --- test/src/common/harnessLibResolv.c | 928 +++++++++++++++++++++++++++++ test/src/common/harnessLibResolv.h | 70 +++ 2 files changed, 998 insertions(+) create mode 100644 test/src/common/harnessLibResolv.c create mode 100644 test/src/common/harnessLibResolv.h diff --git a/test/src/common/harnessLibResolv.c b/test/src/common/harnessLibResolv.c new file mode 100644 index 0000000000..f16b3a5fb1 --- /dev/null +++ b/test/src/common/harnessLibResolv.c @@ -0,0 +1,928 @@ +/*********************************************************************************************************************************** +libresolv Test Harness +***********************************************************************************************************************************/ +#include "build.auto.h" + +#ifdef HAVE_LIBRESOLV + +#include +#include + +#include "common/type/json.h" +#include "common/type/string.h" +#include "common/type/variantList.h" + +#include "common/harnessLibResolv.h" +#include "common/harnessTest.h" + +/*********************************************************************************************************************************** +libresolv shim error prefix +***********************************************************************************************************************************/ +#define LIBRESOLV_ERROR_PREFIX "LIBRESOLV SHIM ERROR" + +/*********************************************************************************************************************************** +Script that defines how shim functions operate +***********************************************************************************************************************************/ +HrnLibResolv hrnLibResolvScript[1024]; +bool hrnLibResolvScriptDone = true; +unsigned int hrnLibResolvScriptIdx; + +// If there is a script failure change the behavior of cleanup functions to return immediately so the real error will be reported +// rather than a bogus scripting error during cleanup +bool hrnLibResolvScriptFail; +char hrnLibResolvScriptError[4096]; + +/*********************************************************************************************************************************** +Set libresolv script +***********************************************************************************************************************************/ +void +hrnLibResolvScriptSet(HrnLibResolv *hrnLibResolvScriptParam) +{ + if (!hrnLibResolvScriptDone) + THROW(AssertError, "previous libresolv script has not yet completed"); + + if (hrnLibResolvScriptParam[0].function == NULL) + THROW(AssertError, "libresolv script must have entries"); + + // Copy records into local storage + unsigned int copyIdx = 0; + + while (hrnLibResolvScriptParam[copyIdx].function != NULL) + { + hrnLibResolvScript[copyIdx] = hrnLibResolvScriptParam[copyIdx]; + copyIdx++; + } + + hrnLibResolvScript[copyIdx].function = NULL; + hrnLibResolvScriptDone = false; + hrnLibResolvScriptIdx = 0; +} + +/*********************************************************************************************************************************** +Run libresolv script +***********************************************************************************************************************************/ +static HrnLibResolv * +hrnLibResolvScriptRun(const char *const function, const VariantList *const param, const HrnLibResolv *const parent) +{ + // If an error has already been thrown then throw the same error again + if (hrnLibResolvScriptFail) + THROW(AssertError, hrnLibResolvScriptError); + + // Convert params to json for comparison and reporting + String *paramStr = NULL; + + if (param) + { + Variant *const varList = varNewVarLst(param); + + paramStr = jsonFromVar(varList); + varFree(varList); + } + else + paramStr = strNew(); + + // Ensure script has not ended + if (hrnLibResolvScriptDone) + { + snprintf( + hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), "libresolv script ended before %s (%s)", function, + strZ(paramStr)); + + TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); + hrnLibResolvScriptFail = true; + + THROW(AssertError, hrnLibResolvScriptError); + } + + // Get current script item + HrnLibResolv *result = &hrnLibResolvScript[hrnLibResolvScriptIdx]; + + // Check that expected function was called + if (strcmp(result->function, function) != 0) + { + snprintf( + hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), + "libresolv script [%u] expected function %s (%s) but got %s (%s)", hrnLibResolvScriptIdx, result->function, + result->param == NULL ? "" : result->param, function, strZ(paramStr)); + + TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); + hrnLibResolvScriptFail = true; + + THROW(AssertError, hrnLibResolvScriptError); + } + + // Check that parameters match + if ((param != NULL && result->param == NULL) || (param == NULL && result->param != NULL) || + (param != NULL && result->param != NULL && !strEqZ(paramStr, result->param))) + { + snprintf( + hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), + "libresolv script [%u] function '%s', expects param '%s' but got '%s'", + hrnLibResolvScriptIdx, result->function, result->param ? result->param : "NULL", param ? strZ(paramStr) : "NULL"); + + TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); + hrnLibResolvScriptFail = true; + + THROW(AssertError, hrnLibResolvScriptError); + } + + // Make sure the session matches with the parent as a sanity check + if (parent != NULL && result->session != parent->session) + { + snprintf( + hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), + "libresolv script [%u] function '%s', expects session '%u' but got '%u'", + hrnLibResolvScriptIdx, result->function, result->session, parent->session); + + TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); + hrnLibResolvScriptFail = true; + + THROW(AssertError, hrnLibResolvScriptError); + } + + // Sleep if requested + if (result->sleep > 0) + sleepMSec(result->sleep); + + hrnLibResolvScriptIdx++; + + if (hrnLibResolvScript[hrnLibResolvScriptIdx].function == NULL) + hrnLibResolvScriptDone = true; + + strFree(paramStr); + + return result; +} + +/*********************************************************************************************************************************** +Shim for res_nquery +***********************************************************************************************************************************/ +int +res_nquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) +{ + HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun( + HRNLIBRESOLV_RES_NQUERY, + varLstAdd( + varLstAdd( + varLstAdd( + varLstAdd( + varLstAdd( + varLstAdd( + varLstNew(), varNewStrZ(dname)), + varNewInt(class)), + varNewInt(type)), + varNewStrZ(answer)), + varNewUInt64(anslen)), + (HrnLibResolv *)statep); + + return hrnLibResolv->resultInt; +} + +#endif // HAVE_LIBRESOLV + // +// jrt remove all this +///*********************************************************************************************************************************** +//Shim for libresolv_init +//***********************************************************************************************************************************/ +//int +//libresolv_init(int flags) +//{ +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_INIT, varLstAdd(varLstNew(), varNewInt(flags)), NULL); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_addc +//***********************************************************************************************************************************/ +//int +//libresolv_knownhost_addc( +// LIBRESOLV_KNOWNHOSTS *hosts, const char *host, const char *salt, const char *key, size_t keylen, const char *comment, +// size_t commentlen, int typemask, struct libresolv_knownhost **store) +//{ +// // Avoid compiler complaining of unused param +// (void)store; +// +// if (hosts == NULL) +// { +// snprintf( +// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), +// "libresolv script function 'libresolv_knownhost_adddc', expects hosts to be not NULL"); +// THROW(AssertError, hrnLibResolvScriptError); +// } +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_KNOWNHOST_ADDC, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(host)), +// varNewStrZ(salt)), +// varNewStrZ(key)), +// varNewUInt64(keylen)), +// varNewStrZ(comment)), +// varNewUInt64(commentlen)), +// varNewInt(typemask)), +// (HrnLibResolv *)hosts); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_checkp +//***********************************************************************************************************************************/ +//int +//libresolv_knownhost_checkp( +// LIBRESOLV_KNOWNHOSTS *hosts, const char *host, int port, const char *key, size_t keylen, int typemask, +// struct libresolv_knownhost **knownhost) +//{ +// // Avoid compiler complaining of unused param +// (void)knownhost; +// +// if (hosts == NULL) +// { +// snprintf( +// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), +// "libresolv script function 'libresolv_knownhost_checkp', expects hosts to be not NULL"); +// THROW(AssertError, hrnLibResolvScriptError); +// } +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_KNOWNHOST_CHECKP, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(host)), +// varNewInt(port)), +// varNewStrZ(key)), +// varNewUInt64(keylen)), +// varNewInt(typemask)), +// (HrnLibResolv *)hosts); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_free +//***********************************************************************************************************************************/ +//void +//libresolv_knownhost_free(LIBRESOLV_KNOWNHOSTS *hosts) +//{ +// if (hosts == NULL) +// { +// snprintf( +// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), +// "libresolv script function 'libresolv_session_knownhost_free', expects hosts to be not NULL"); +// THROW(AssertError, hrnLibResolvScriptError); +// } +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_init +//***********************************************************************************************************************************/ +//LIBRESOLV_KNOWNHOSTS * +//libresolv_knownhost_init(LIBRESOLV_SESSION *session) +//{ +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_KNOWNHOST_INIT, NULL, (HrnLibResolv *)session); +// +// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_KNOWNHOSTS *)hrnLibResolv; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_readfile +//***********************************************************************************************************************************/ +//int +//libresolv_knownhost_readfile(LIBRESOLV_KNOWNHOSTS *hosts, const char *filename, int type) +//{ +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_KNOWNHOST_READFILE, +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(filename)), +// varNewInt(type)), +// (HrnLibResolv *)hosts); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_knownhost_writefile +//***********************************************************************************************************************************/ +//int +//libresolv_knownhost_writefile(LIBRESOLV_KNOWNHOSTS *hosts, const char *filename, int type) +//{ +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_KNOWNHOST_WRITEFILE, +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(filename)), +// varNewInt(type)), +// (HrnLibResolv *)hosts); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_hostkey +//***********************************************************************************************************************************/ +//const char * +//libresolv_session_hostkey(LIBRESOLV_SESSION *session, size_t *len, int *type) +//{ +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_HOSTKEY, NULL, (HrnLibResolv *)session); +// +// *len = (size_t)hrnLibResolv->len; +// *type = (int)hrnLibResolv->type; +// +// return hrnLibResolv->resultNull ? NULL : (const char *)hrnLibResolv->resultZ; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_init +//***********************************************************************************************************************************/ +//LIBRESOLV_SESSION * +//libresolv_session_init_ex( +// LIBRESOLV_ALLOC_FUNC((*myalloc)), LIBRESOLV_FREE_FUNC((*myfree)), LIBRESOLV_REALLOC_FUNC((*myrealloc)), void *abstract) +//{ +// // All of these should always be the default NULL +// if (myalloc != NULL && myfree != NULL && myrealloc != NULL && abstract != NULL) +// { +// snprintf( +// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), +// "libresolv script function 'libresolv_session_init_ex', expects all params to be NULL"); +// THROW(AssertError, hrnLibResolvScriptError); +// } +// +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SESSION_INIT_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStr(NULL)), +// varNewStr(NULL)), +// varNewStr(NULL)), +// varNewStr(NULL)), +// NULL); +// +// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SESSION *)hrnLibResolv; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_last_error +//***********************************************************************************************************************************/ +//int +//libresolv_session_last_error(LIBRESOLV_SESSION *session, char **errmsg, int *errmsg_len, int want_buf) +//{ +// // Avoid compiler complaining of unused params +// (void)errmsg_len; +// (void)want_buf; +// +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_LAST_ERROR, NULL, (HrnLibResolv *)session); +// +// if (hrnLibResolv->errMsg != NULL) +// *errmsg = hrnLibResolv->errMsg; +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_handshake +//***********************************************************************************************************************************/ +//int +//libresolv_session_handshake(LIBRESOLV_SESSION *session, libresolv_socket_t sock) +//{ +// return hrnLibResolvScriptRun( +// HRNLIBRESOLV_SESSION_HANDSHAKE, varLstAdd(varLstNew(), varNewInt(sock)), (HrnLibResolv *)session)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_block_directions +//***********************************************************************************************************************************/ +//int +//libresolv_session_block_directions(LIBRESOLV_SESSION *session) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_BLOCK_DIRECTIONS, NULL, (HrnLibResolv *)session)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_hostkey_hash +//***********************************************************************************************************************************/ +//const char * +//libresolv_hostkey_hash(LIBRESOLV_SESSION *session, int hash_type) +//{ +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_HOSTKEY_HASH, varLstAdd(varLstNew(), varNewInt(hash_type)), (HrnLibResolv *)session); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultNull ? NULL : (const char *)hrnLibResolv->resultZ; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_userauth_publickey_fromfile_ex +//***********************************************************************************************************************************/ +//int +//libresolv_userauth_publickey_fromfile_ex( +// LIBRESOLV_SESSION *session, const char *username, unsigned int ousername_len, const char *publickey, const char *privatekey, +// const char *passphrase) +//{ +// HrnLibResolv *hrnLibResolv = NULL; +// +// if (privatekey == NULL) +// { +// snprintf( +// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), +// "libresolv script function 'libresolv_userauth_publickey_fromfile_ex', expects privatekey to be not NULL"); +// THROW(AssertError, hrnLibResolvScriptError); +// } +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_USERAUTH_PUBLICKEY_FROMFILE_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(username)), +// varNewUInt(ousername_len)), +// varNewStrZ(publickey)), +// varNewStrZ(privatekey)), +// varNewStrZ(passphrase)), +// (HrnLibResolv *)session); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_init +//***********************************************************************************************************************************/ +//LIBRESOLV_SFTP * +//libresolv_sftp_init(LIBRESOLV_SESSION *session) +//{ +// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_INIT, NULL, (HrnLibResolv *)session); +// +// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SFTP *)hrnLibResolv; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_close_handle +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_close_handle(LIBRESOLV_SFTP_HANDLE *handle) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_CLOSE_HANDLE, NULL, (HrnLibResolv *)handle)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_shutdown +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_shutdown(LIBRESOLV_SFTP *sftp) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_SHUTDOWN, NULL, (HrnLibResolv *)sftp)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_disconnect_ex +//***********************************************************************************************************************************/ +//int +//libresolv_session_disconnect_ex(LIBRESOLV_SESSION *session, int reason, const char *description, const char *lang) +//{ +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SESSION_DISCONNECT_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewInt(reason)), +// varNewStrZ(description)), +// varNewStrZ(lang)), +// (HrnLibResolv *)session); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for int libresolv_session_free +//***********************************************************************************************************************************/ +//int +//libresolv_session_free(LIBRESOLV_SESSION *session) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_FREE, NULL, (HrnLibResolv *)session)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_stat_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_stat_ex( +// LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBRESOLV_SFTP_ATTRIBUTES *attrs) +//{ +// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where +// // tests are being run. +// // +// // Could we utilize test.c/build.c to calculate/define this and other length params? +// (void)path_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_STAT_EX, +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(path)), +// varNewInt(stat_type)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// if (attrs == NULL) +// THROW(AssertError, "attrs is NULL"); +// +// attrs->flags = 0; +// attrs->flags |= (unsigned long)hrnLibResolv->flags; +// +// attrs->permissions = 0; +// attrs->permissions |= (unsigned long)hrnLibResolv->attrPerms; +// +// attrs->mtime = (unsigned long)hrnLibResolv->mtime; +// attrs->uid = (unsigned long)hrnLibResolv->uid; +// attrs->gid = (unsigned long)hrnLibResolv->gid; +// attrs->filesize = hrnLibResolv->filesize; +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_last_error +//***********************************************************************************************************************************/ +//unsigned long +//libresolv_sftp_last_error(LIBRESOLV_SFTP *sftp) +//{ +// return (unsigned long)hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_LAST_ERROR, NULL, (HrnLibResolv *)sftp)->resultUInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_symlink_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_symlink_ex( +// LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type) +//{ +// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where +// // tests are being run. +// (void)path_len; +// (void)target_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_SYMLINK_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(path)), +// varNewStrZ(target)), +// varNewInt(link_type)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// int rc; +// +// switch (link_type) +// { +// case LIBRESOLV_SFTP_READLINK: +// case LIBRESOLV_SFTP_REALPATH: +// if (hrnLibResolv->symlinkExTarget != NULL) +// { +// if (strSize(hrnLibResolv->symlinkExTarget) < PATH_MAX) +// strncpy(target, strZ(hrnLibResolv->symlinkExTarget), strSize(hrnLibResolv->symlinkExTarget)); +// else +// THROW_FMT(AssertError, "symlinkExTarget too large for target buffer"); +// } +// +// rc = hrnLibResolv->resultInt != 0 ? hrnLibResolv->resultInt : (int)strSize(hrnLibResolv->symlinkExTarget); +// break; +// +// default: +// THROW_FMT(AssertError, "UNKNOWN link_type"); +// break; +// } +// +// return rc; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_open_ex +//***********************************************************************************************************************************/ +//LIBRESOLV_SFTP_HANDLE * +//libresolv_sftp_open_ex( +// LIBRESOLV_SFTP *sftp, const char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type) +//{ +// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where +// // tests are being run. +// (void)filename_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_OPEN_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(filename)), +// varNewUInt64(flags)), +// varNewInt64(mode)), +// varNewInt(open_type)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SFTP_HANDLE *)hrnLibResolv; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_readdir_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_readdir_ex( +// LIBRESOLV_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, char *longentry, size_t longentry_maxlen, +// LIBRESOLV_SFTP_ATTRIBUTES *attrs) +//{ +// if (attrs == NULL) +// THROW_FMT(AssertError, "attrs is NULL"); +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_READDIR_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(buffer)), +// varNewUInt64(buffer_maxlen)), +// varNewStrZ(longentry)), +// varNewUInt64(longentry_maxlen)), +// (HrnLibResolv *)handle); +// } +// MEM_CONTEXT_TEMP_END(); +// +// if (hrnLibResolv->fileName != NULL) +// strncpy(buffer, strZ(hrnLibResolv->fileName), buffer_maxlen); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_session_last_errno +//***********************************************************************************************************************************/ +//int +//libresolv_session_last_errno(LIBRESOLV_SESSION *session) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_LAST_ERRNO, NULL, (HrnLibResolv *)session)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_fsync +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_fsync(LIBRESOLV_SFTP_HANDLE *handle) +//{ +// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_FSYNC, NULL, (HrnLibResolv *)handle)->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_mkdir_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_mkdir_ex(LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, long mode) +//{ +// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on +// // where tests are being run. +// (void)path_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_MKDIR_EX, +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(path)), +// varNewInt64(mode)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_read +//***********************************************************************************************************************************/ +//ssize_t +//libresolv_sftp_read(LIBRESOLV_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen) +//{ +// // We don't pass buffer to hrnLibResolvScriptRun. The first call for each invocation passes buffer with random data, which is +// // an issue for sftpTest.c. +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_READ, +// varLstAdd( +// varLstNew(), varNewUInt64(buffer_maxlen)), +// (HrnLibResolv *)handle); +// } +// MEM_CONTEXT_TEMP_END(); +// +// // copy read into buffer +// if (hrnLibResolv->readBuffer != NULL) +// strncpy(buffer, strZ(hrnLibResolv->readBuffer), strSize(hrnLibResolv->readBuffer)); +// +// // number of bytes populated +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_rename_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_rename_ex( +// LIBRESOLV_SFTP *sftp, const char *source_filename, unsigned int source_filename_len, const char *dest_filename, +// unsigned int dest_filename_len, long flags) +//{ +// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on +// // where tests are being run. +// (void)source_filename_len; +// (void)dest_filename_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_RENAME_EX, +// varLstAdd( +// varLstAdd( +// varLstAdd( +// varLstNew(), varNewStrZ(source_filename)), +// varNewStrZ(dest_filename)), +// varNewInt64(flags)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_rmdir_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_rmdir_ex(LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len) +//{ +// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where +// // tests are being run. +// (void)path_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_RMDIR_EX, +// varLstAdd( +// varLstNew(), varNewStrZ(path)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_seek64 +//***********************************************************************************************************************************/ +//void +//libresolv_sftp_seek64(LIBRESOLV_SFTP_HANDLE *handle, libresolv_uint64_t offset) +//{ +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_SEEK64, +// varLstAdd( +// varLstNew(), varNewUInt64(offset)), +// (HrnLibResolv *)handle); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_unlink_ex +//***********************************************************************************************************************************/ +//int +//libresolv_sftp_unlink_ex(LIBRESOLV_SFTP *sftp, const char *filename, unsigned int filename_len) +//{ +// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where +// // tests are being run. +// (void)filename_len; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_UNLINK_EX, +// varLstAdd( +// varLstNew(), varNewStrZ(filename)), +// (HrnLibResolv *)sftp); +// } +// MEM_CONTEXT_TEMP_END(); +// +// return hrnLibResolv->resultInt; +//} +// +///*********************************************************************************************************************************** +//Shim for libresolv_sftp_write +//***********************************************************************************************************************************/ +//ssize_t +//libresolv_sftp_write(LIBRESOLV_SFTP_HANDLE *handle, const char *buffer, size_t count) +//{ +// // We don't pass buffer to hrnLibResolvScriptRun. The first call for each invocation passes buffer with random data, which is +// // an issue for sftpTest.c. +// (void)buffer; +// +// HrnLibResolv *hrnLibResolv = NULL; +// +// MEM_CONTEXT_TEMP_BEGIN() +// { +// hrnLibResolv = hrnLibResolvScriptRun( +// HRNLIBRESOLV_SFTP_WRITE, +// varLstAdd( +// varLstNew(), varNewUInt64(count)), +// (HrnLibResolv *)handle); +// } +// MEM_CONTEXT_TEMP_END(); +// +// // Return number of bytes written +// return hrnLibResolv->resultInt; +//} diff --git a/test/src/common/harnessLibResolv.h b/test/src/common/harnessLibResolv.h new file mode 100644 index 0000000000..003494d216 --- /dev/null +++ b/test/src/common/harnessLibResolv.h @@ -0,0 +1,70 @@ +/*********************************************************************************************************************************** +libresolv Test Harness + +Scripted testing for libresolv so exact results can be returned for unit testing. See sftp unit tests for usage examples. +***********************************************************************************************************************************/ +#ifndef TEST_COMMON_HARNESS_LIBRESOLV_H +#define TEST_COMMON_HARNESS_LIBRESOLV_H + +#ifdef HAVE_LIBRESOLV + +#ifndef HARNESS_LIBRESOLV_REAL + +#include +#include + +#include "common/macro.h" +#include "common/time.h" +#include "version.h" + +/*********************************************************************************************************************************** +libresolv authorization constants +***********************************************************************************************************************************/ +//#define HOSTKEY "12345678901234567890" + +/*********************************************************************************************************************************** +Function constants +***********************************************************************************************************************************/ +#define HRNLIBRESOLV_RES_NQUERY "res_nquery" + +/*********************************************************************************************************************************** +Macros for defining groups of functions that implement commands +***********************************************************************************************************************************/ + +/*********************************************************************************************************************************** +Structure for scripting libresolv responses +***********************************************************************************************************************************/ +typedef struct HrnLibResolv +{ + unsigned int session; // Session number when multiple sessions are run concurrently + const char *function; // Function call expected + const char *param; // Params expected by the function for verification + int resultInt; // Int result value + uint64_t resultUInt; // UInt result value + const char *resultZ; // Zero-terminated result value + bool resultNull; // Return null from function that normally returns a struct ptr + size_t len; // libresolv_session_hostkey len +// uint64_t flags; // libresolv flags +// uint64_t attrPerms; // libresolv attr perms +// uint64_t atime, mtime; // libresolv timestamps +// uint64_t uid, gid; // libresolv uid/gid +// uint64_t filesize; // libresolv filesize +// uint64_t offset; // libresolv seek offset +// const String *symlinkExTarget; // libresolv_sftp_symlink_ex target +// const String *fileName; // libresolv_readdir* libresolv_stat* filename +// const String *readBuffer; // what to copy into read buffer +// TimeMSec sleep; // Sleep specified milliseconds before returning from function +// int type; // libresolv_session_hostkey type +// char *errMsg; // libresolv_session_last_error error msg +} HrnLibResolv; + +/*********************************************************************************************************************************** +Functions +***********************************************************************************************************************************/ +void hrnLibResolvScriptSet(HrnLibResolv *hrnLibResolvScriptParam); + +#endif // HARNESS_LIBRESOLV_REAL + +#endif // HAVE_LIBRESOLV + +#endif // TEST_COMMON_HARNESS_LIBRESOLV_H From 39278d00b77197d481703e951757e9cb49bde244 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Sun, 8 Oct 2023 22:36:45 -0400 Subject: [PATCH 04/54] Add harnessLibResolv to sftpTest unit --- test/define.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/define.yaml b/test/define.yaml index 81acfc8f6b..9dbf9bef8e 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -609,6 +609,7 @@ unit: - name: sftp total: 19 harness: libSsh2 + harness: libResolv harness: name: fd shim: From 4905947145e794574eed935d9df4701ab6d38787 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 20 Oct 2023 09:53:07 -0400 Subject: [PATCH 05/54] Start to shim libresolv functions in order to implement tests Start adding tests Rename harnessLibResolv* to harnessSftpResolv and update references --- src/storage/sftp/storage.c | 128 +++- test/code-count/file-type.yaml | 16 +- test/define.yaml | 10 +- test/src/common/harnessLibResolv.c | 928 ---------------------------- test/src/common/harnessLibResolv.h | 70 --- test/src/common/harnessLibSsh2.c | 1 + test/src/common/harnessSftpResolv.c | 196 ++++++ test/src/common/harnessSftpResolv.h | 10 + test/src/module/storage/sftpTest.c | 248 +++++++- 9 files changed, 570 insertions(+), 1037 deletions(-) delete mode 100644 test/src/common/harnessLibResolv.c delete mode 100644 test/src/common/harnessLibResolv.h create mode 100644 test/src/common/harnessSftpResolv.c create mode 100644 test/src/common/harnessSftpResolv.h diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index d651de663b..78463078ae 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -33,6 +33,9 @@ Define PATH_MAX if it is not defined #define PATH_MAX (4 * 1024) #endif +/*********************************************************************************************************************************** +Define PACKET_SZ if it is not defined +***********************************************************************************************************************************/ #ifndef PACKET_SZ #define PACKET_SZ 65535 #endif @@ -51,6 +54,10 @@ struct StorageSftp TimeMSec timeout; // Session timeout }; +// jrt !!! should this be in StorageSftp above? +// Initialize the resolver +struct __res_state my_res_state = {0}; + /*********************************************************************************************************************************** Return known host key type based on host key type ***********************************************************************************************************************************/ @@ -1077,6 +1084,84 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c FUNCTION_LOG_RETURN(BOOL, result); } +/**********************************************************************************************************************************/ +static void +storageSftpSetOption(res_state statep, uint64_t option) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, statep); + FUNCTION_LOG_PARAM(UINT64, option); + FUNCTION_LOG_END(); + + ASSERT(statep != NULL); + ASSERT(option >= RES_INIT && option <= RES_TRUSTAD); + + statep->options |= option; + + FUNCTION_LOG_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +static int +storageSftpResNinit(res_state statep) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, statep); + FUNCTION_LOG_END(); + + ASSERT(statep != NULL); + + FUNCTION_LOG_RETURN(INT, res_ninit(statep)); +} + +/**********************************************************************************************************************************/ +static int +storageSftpResNquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, statep); + FUNCTION_LOG_PARAM(STRINGZ, dname); + FUNCTION_LOG_PARAM(INT, class); + FUNCTION_LOG_PARAM(INT, type); + FUNCTION_LOG_PARAM(UCHARDATA, answer); + FUNCTION_LOG_PARAM(INT, anslen); + FUNCTION_LOG_END(); + + ASSERT(statep != NULL); + ASSERT(dname != NULL); + ASSERT(class >= ns_c_invalid && class <= ns_c_max); + ASSERT(type >= ns_t_invalid && type <= ns_t_max); + + FUNCTION_LOG_RETURN(INT, res_nquery(statep, dname, class, type, answer, anslen)); +} + +static int +storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(UCHARDATA, answer); + FUNCTION_LOG_PARAM(INT, len); + FUNCTION_LOG_PARAM(VOID, handle); + FUNCTION_LOG_END(); + + FUNCTION_LOG_RETURN(INT, ns_initparse(answer, len, handle)); +} + +/**********************************************************************************************************************************/ +static int +storageSftpNsMsgGetflag(ns_msg handle, int ns_f_ad) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, handle); + FUNCTION_LOG_PARAM(INT, ns_f_ad); + FUNCTION_LOG_END(); + + ASSERT(ns_f_ad >= 0 && ns_f_ad <= ns_f_max); + + FUNCTION_LOG_RETURN(INT, ns_msg_getflag(handle, ns_f_ad)); +} + +// !!! Do any supported OS's not support this code? /*********************************************************************************************************************************** Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated on the fact that @@ -1091,40 +1176,44 @@ storageSftpTrustAd(const String *const host) ASSERT(host != NULL); - // Initialize the resolver - struct __res_state res_state; - memset(&res_state, 0, sizeof(res_state)); - - if ((res_state.options & RES_INIT) == 0 && res_ninit(&res_state ) == -1) + if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); - // Set the resolver to use TRUSTAD and return RRSIG records - res_state.options |= RES_USE_DNSSEC | RES_USE_EDNS0 | RES_TRUSTAD; + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); + // Query the server for SSHFP records unsigned char answer[PACKET_SZ]; - // Query the server for the host - int len = res_nquery(&res_state, strZ(host), C_IN, T_A, answer, sizeof(answer)); + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + // Check for errors. + // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we think that's + // better. if (len < 0) { - res_nclose(&res_state); + // Closing before throwing the error does not seem to mess up the hstrerror() call + res_nclose(&my_res_state); - THROW_FMT(ServiceError, "res_nquery error '%s' for host '%s'", hstrerror(h_errno), strZ(host)); + THROW_FMT( + ServiceError, + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } - // Check the ad flag - HEADER *hdr = (HEADER *)answer; - if (hdr->ad != 1) - THROW_FMT(ServiceError, "RES_TRUSTAD not set in response"); - // Parse the response + ns_msg handle = {0}; + storageSftpNsInitparse(answer, len, &handle); + + // Check the res_trustad flag + if (storageSftpNsMsgGetflag(handle, ns_f_ad) != 1) + { + res_nclose(&my_res_state); - ns_msg handle; - ns_initparse(answer, len, &handle); + THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); + } // Close the resolver - res_nclose(&res_state); + res_nclose(&my_res_state); FUNCTION_LOG_RETURN_VOID(); } @@ -1384,7 +1473,6 @@ storageSftpNew( if (param.trustAd) storageSftpTrustAd(host); - // Perform public key authorization, expand leading tilde key file paths if needed String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); String *const pubKeyPath = diff --git a/test/code-count/file-type.yaml b/test/code-count/file-type.yaml index 6f4a376c5e..67749e9370 100644 --- a/test/code-count/file-type.yaml +++ b/test/code-count/file-type.yaml @@ -2747,14 +2747,6 @@ test/src/common/harnessInfo.h: class: test/harness type: c/h -test/src/common/harnessLibSsh2.c: - class: test/harness - type: c - -test/src/common/harnessLibSsh2.h: - class: test/harness - type: c/h - test/src/common/harnessLock.c: class: test/harness type: c @@ -2863,6 +2855,14 @@ test/src/common/harnessServer.h: class: test/harness type: c/h +test/src/common/harnessSftpResolv.c: + class: test/harness + type: c + +test/src/common/harnessSftpResolv.h: + class: test/harness + type: c/h + test/src/common/harnessSocket.c: class: test/harness type: c diff --git a/test/define.yaml b/test/define.yaml index 9dbf9bef8e..a30e565f5b 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -609,7 +609,15 @@ unit: - name: sftp total: 19 harness: libSsh2 - harness: libResolv + harness: + name: sftpResolv + shim: + storage/sftp/storage: + function: + - storageSftpResNinit + - storageSftpResNquery + - storageSftpNsInitparse + - storageSftpNsMsgGetflag harness: name: fd shim: diff --git a/test/src/common/harnessLibResolv.c b/test/src/common/harnessLibResolv.c deleted file mode 100644 index f16b3a5fb1..0000000000 --- a/test/src/common/harnessLibResolv.c +++ /dev/null @@ -1,928 +0,0 @@ -/*********************************************************************************************************************************** -libresolv Test Harness -***********************************************************************************************************************************/ -#include "build.auto.h" - -#ifdef HAVE_LIBRESOLV - -#include -#include - -#include "common/type/json.h" -#include "common/type/string.h" -#include "common/type/variantList.h" - -#include "common/harnessLibResolv.h" -#include "common/harnessTest.h" - -/*********************************************************************************************************************************** -libresolv shim error prefix -***********************************************************************************************************************************/ -#define LIBRESOLV_ERROR_PREFIX "LIBRESOLV SHIM ERROR" - -/*********************************************************************************************************************************** -Script that defines how shim functions operate -***********************************************************************************************************************************/ -HrnLibResolv hrnLibResolvScript[1024]; -bool hrnLibResolvScriptDone = true; -unsigned int hrnLibResolvScriptIdx; - -// If there is a script failure change the behavior of cleanup functions to return immediately so the real error will be reported -// rather than a bogus scripting error during cleanup -bool hrnLibResolvScriptFail; -char hrnLibResolvScriptError[4096]; - -/*********************************************************************************************************************************** -Set libresolv script -***********************************************************************************************************************************/ -void -hrnLibResolvScriptSet(HrnLibResolv *hrnLibResolvScriptParam) -{ - if (!hrnLibResolvScriptDone) - THROW(AssertError, "previous libresolv script has not yet completed"); - - if (hrnLibResolvScriptParam[0].function == NULL) - THROW(AssertError, "libresolv script must have entries"); - - // Copy records into local storage - unsigned int copyIdx = 0; - - while (hrnLibResolvScriptParam[copyIdx].function != NULL) - { - hrnLibResolvScript[copyIdx] = hrnLibResolvScriptParam[copyIdx]; - copyIdx++; - } - - hrnLibResolvScript[copyIdx].function = NULL; - hrnLibResolvScriptDone = false; - hrnLibResolvScriptIdx = 0; -} - -/*********************************************************************************************************************************** -Run libresolv script -***********************************************************************************************************************************/ -static HrnLibResolv * -hrnLibResolvScriptRun(const char *const function, const VariantList *const param, const HrnLibResolv *const parent) -{ - // If an error has already been thrown then throw the same error again - if (hrnLibResolvScriptFail) - THROW(AssertError, hrnLibResolvScriptError); - - // Convert params to json for comparison and reporting - String *paramStr = NULL; - - if (param) - { - Variant *const varList = varNewVarLst(param); - - paramStr = jsonFromVar(varList); - varFree(varList); - } - else - paramStr = strNew(); - - // Ensure script has not ended - if (hrnLibResolvScriptDone) - { - snprintf( - hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), "libresolv script ended before %s (%s)", function, - strZ(paramStr)); - - TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); - hrnLibResolvScriptFail = true; - - THROW(AssertError, hrnLibResolvScriptError); - } - - // Get current script item - HrnLibResolv *result = &hrnLibResolvScript[hrnLibResolvScriptIdx]; - - // Check that expected function was called - if (strcmp(result->function, function) != 0) - { - snprintf( - hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), - "libresolv script [%u] expected function %s (%s) but got %s (%s)", hrnLibResolvScriptIdx, result->function, - result->param == NULL ? "" : result->param, function, strZ(paramStr)); - - TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); - hrnLibResolvScriptFail = true; - - THROW(AssertError, hrnLibResolvScriptError); - } - - // Check that parameters match - if ((param != NULL && result->param == NULL) || (param == NULL && result->param != NULL) || - (param != NULL && result->param != NULL && !strEqZ(paramStr, result->param))) - { - snprintf( - hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), - "libresolv script [%u] function '%s', expects param '%s' but got '%s'", - hrnLibResolvScriptIdx, result->function, result->param ? result->param : "NULL", param ? strZ(paramStr) : "NULL"); - - TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); - hrnLibResolvScriptFail = true; - - THROW(AssertError, hrnLibResolvScriptError); - } - - // Make sure the session matches with the parent as a sanity check - if (parent != NULL && result->session != parent->session) - { - snprintf( - hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), - "libresolv script [%u] function '%s', expects session '%u' but got '%u'", - hrnLibResolvScriptIdx, result->function, result->session, parent->session); - - TEST_LOG_FMT(LIBRESOLV_ERROR_PREFIX ": %s", hrnLibResolvScriptError); - hrnLibResolvScriptFail = true; - - THROW(AssertError, hrnLibResolvScriptError); - } - - // Sleep if requested - if (result->sleep > 0) - sleepMSec(result->sleep); - - hrnLibResolvScriptIdx++; - - if (hrnLibResolvScript[hrnLibResolvScriptIdx].function == NULL) - hrnLibResolvScriptDone = true; - - strFree(paramStr); - - return result; -} - -/*********************************************************************************************************************************** -Shim for res_nquery -***********************************************************************************************************************************/ -int -res_nquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) -{ - HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun( - HRNLIBRESOLV_RES_NQUERY, - varLstAdd( - varLstAdd( - varLstAdd( - varLstAdd( - varLstAdd( - varLstAdd( - varLstNew(), varNewStrZ(dname)), - varNewInt(class)), - varNewInt(type)), - varNewStrZ(answer)), - varNewUInt64(anslen)), - (HrnLibResolv *)statep); - - return hrnLibResolv->resultInt; -} - -#endif // HAVE_LIBRESOLV - // -// jrt remove all this -///*********************************************************************************************************************************** -//Shim for libresolv_init -//***********************************************************************************************************************************/ -//int -//libresolv_init(int flags) -//{ -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_INIT, varLstAdd(varLstNew(), varNewInt(flags)), NULL); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_addc -//***********************************************************************************************************************************/ -//int -//libresolv_knownhost_addc( -// LIBRESOLV_KNOWNHOSTS *hosts, const char *host, const char *salt, const char *key, size_t keylen, const char *comment, -// size_t commentlen, int typemask, struct libresolv_knownhost **store) -//{ -// // Avoid compiler complaining of unused param -// (void)store; -// -// if (hosts == NULL) -// { -// snprintf( -// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), -// "libresolv script function 'libresolv_knownhost_adddc', expects hosts to be not NULL"); -// THROW(AssertError, hrnLibResolvScriptError); -// } -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_KNOWNHOST_ADDC, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(host)), -// varNewStrZ(salt)), -// varNewStrZ(key)), -// varNewUInt64(keylen)), -// varNewStrZ(comment)), -// varNewUInt64(commentlen)), -// varNewInt(typemask)), -// (HrnLibResolv *)hosts); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_checkp -//***********************************************************************************************************************************/ -//int -//libresolv_knownhost_checkp( -// LIBRESOLV_KNOWNHOSTS *hosts, const char *host, int port, const char *key, size_t keylen, int typemask, -// struct libresolv_knownhost **knownhost) -//{ -// // Avoid compiler complaining of unused param -// (void)knownhost; -// -// if (hosts == NULL) -// { -// snprintf( -// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), -// "libresolv script function 'libresolv_knownhost_checkp', expects hosts to be not NULL"); -// THROW(AssertError, hrnLibResolvScriptError); -// } -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_KNOWNHOST_CHECKP, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(host)), -// varNewInt(port)), -// varNewStrZ(key)), -// varNewUInt64(keylen)), -// varNewInt(typemask)), -// (HrnLibResolv *)hosts); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_free -//***********************************************************************************************************************************/ -//void -//libresolv_knownhost_free(LIBRESOLV_KNOWNHOSTS *hosts) -//{ -// if (hosts == NULL) -// { -// snprintf( -// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), -// "libresolv script function 'libresolv_session_knownhost_free', expects hosts to be not NULL"); -// THROW(AssertError, hrnLibResolvScriptError); -// } -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_init -//***********************************************************************************************************************************/ -//LIBRESOLV_KNOWNHOSTS * -//libresolv_knownhost_init(LIBRESOLV_SESSION *session) -//{ -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_KNOWNHOST_INIT, NULL, (HrnLibResolv *)session); -// -// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_KNOWNHOSTS *)hrnLibResolv; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_readfile -//***********************************************************************************************************************************/ -//int -//libresolv_knownhost_readfile(LIBRESOLV_KNOWNHOSTS *hosts, const char *filename, int type) -//{ -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_KNOWNHOST_READFILE, -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(filename)), -// varNewInt(type)), -// (HrnLibResolv *)hosts); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_knownhost_writefile -//***********************************************************************************************************************************/ -//int -//libresolv_knownhost_writefile(LIBRESOLV_KNOWNHOSTS *hosts, const char *filename, int type) -//{ -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_KNOWNHOST_WRITEFILE, -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(filename)), -// varNewInt(type)), -// (HrnLibResolv *)hosts); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_hostkey -//***********************************************************************************************************************************/ -//const char * -//libresolv_session_hostkey(LIBRESOLV_SESSION *session, size_t *len, int *type) -//{ -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_HOSTKEY, NULL, (HrnLibResolv *)session); -// -// *len = (size_t)hrnLibResolv->len; -// *type = (int)hrnLibResolv->type; -// -// return hrnLibResolv->resultNull ? NULL : (const char *)hrnLibResolv->resultZ; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_init -//***********************************************************************************************************************************/ -//LIBRESOLV_SESSION * -//libresolv_session_init_ex( -// LIBRESOLV_ALLOC_FUNC((*myalloc)), LIBRESOLV_FREE_FUNC((*myfree)), LIBRESOLV_REALLOC_FUNC((*myrealloc)), void *abstract) -//{ -// // All of these should always be the default NULL -// if (myalloc != NULL && myfree != NULL && myrealloc != NULL && abstract != NULL) -// { -// snprintf( -// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), -// "libresolv script function 'libresolv_session_init_ex', expects all params to be NULL"); -// THROW(AssertError, hrnLibResolvScriptError); -// } -// -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SESSION_INIT_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStr(NULL)), -// varNewStr(NULL)), -// varNewStr(NULL)), -// varNewStr(NULL)), -// NULL); -// -// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SESSION *)hrnLibResolv; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_last_error -//***********************************************************************************************************************************/ -//int -//libresolv_session_last_error(LIBRESOLV_SESSION *session, char **errmsg, int *errmsg_len, int want_buf) -//{ -// // Avoid compiler complaining of unused params -// (void)errmsg_len; -// (void)want_buf; -// -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_LAST_ERROR, NULL, (HrnLibResolv *)session); -// -// if (hrnLibResolv->errMsg != NULL) -// *errmsg = hrnLibResolv->errMsg; -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_handshake -//***********************************************************************************************************************************/ -//int -//libresolv_session_handshake(LIBRESOLV_SESSION *session, libresolv_socket_t sock) -//{ -// return hrnLibResolvScriptRun( -// HRNLIBRESOLV_SESSION_HANDSHAKE, varLstAdd(varLstNew(), varNewInt(sock)), (HrnLibResolv *)session)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_block_directions -//***********************************************************************************************************************************/ -//int -//libresolv_session_block_directions(LIBRESOLV_SESSION *session) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_BLOCK_DIRECTIONS, NULL, (HrnLibResolv *)session)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_hostkey_hash -//***********************************************************************************************************************************/ -//const char * -//libresolv_hostkey_hash(LIBRESOLV_SESSION *session, int hash_type) -//{ -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_HOSTKEY_HASH, varLstAdd(varLstNew(), varNewInt(hash_type)), (HrnLibResolv *)session); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultNull ? NULL : (const char *)hrnLibResolv->resultZ; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_userauth_publickey_fromfile_ex -//***********************************************************************************************************************************/ -//int -//libresolv_userauth_publickey_fromfile_ex( -// LIBRESOLV_SESSION *session, const char *username, unsigned int ousername_len, const char *publickey, const char *privatekey, -// const char *passphrase) -//{ -// HrnLibResolv *hrnLibResolv = NULL; -// -// if (privatekey == NULL) -// { -// snprintf( -// hrnLibResolvScriptError, sizeof(hrnLibResolvScriptError), -// "libresolv script function 'libresolv_userauth_publickey_fromfile_ex', expects privatekey to be not NULL"); -// THROW(AssertError, hrnLibResolvScriptError); -// } -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_USERAUTH_PUBLICKEY_FROMFILE_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(username)), -// varNewUInt(ousername_len)), -// varNewStrZ(publickey)), -// varNewStrZ(privatekey)), -// varNewStrZ(passphrase)), -// (HrnLibResolv *)session); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_init -//***********************************************************************************************************************************/ -//LIBRESOLV_SFTP * -//libresolv_sftp_init(LIBRESOLV_SESSION *session) -//{ -// HrnLibResolv *hrnLibResolv = hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_INIT, NULL, (HrnLibResolv *)session); -// -// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SFTP *)hrnLibResolv; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_close_handle -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_close_handle(LIBRESOLV_SFTP_HANDLE *handle) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_CLOSE_HANDLE, NULL, (HrnLibResolv *)handle)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_shutdown -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_shutdown(LIBRESOLV_SFTP *sftp) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_SHUTDOWN, NULL, (HrnLibResolv *)sftp)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_disconnect_ex -//***********************************************************************************************************************************/ -//int -//libresolv_session_disconnect_ex(LIBRESOLV_SESSION *session, int reason, const char *description, const char *lang) -//{ -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SESSION_DISCONNECT_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewInt(reason)), -// varNewStrZ(description)), -// varNewStrZ(lang)), -// (HrnLibResolv *)session); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for int libresolv_session_free -//***********************************************************************************************************************************/ -//int -//libresolv_session_free(LIBRESOLV_SESSION *session) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_FREE, NULL, (HrnLibResolv *)session)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_stat_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_stat_ex( -// LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBRESOLV_SFTP_ATTRIBUTES *attrs) -//{ -// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where -// // tests are being run. -// // -// // Could we utilize test.c/build.c to calculate/define this and other length params? -// (void)path_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_STAT_EX, -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(path)), -// varNewInt(stat_type)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// if (attrs == NULL) -// THROW(AssertError, "attrs is NULL"); -// -// attrs->flags = 0; -// attrs->flags |= (unsigned long)hrnLibResolv->flags; -// -// attrs->permissions = 0; -// attrs->permissions |= (unsigned long)hrnLibResolv->attrPerms; -// -// attrs->mtime = (unsigned long)hrnLibResolv->mtime; -// attrs->uid = (unsigned long)hrnLibResolv->uid; -// attrs->gid = (unsigned long)hrnLibResolv->gid; -// attrs->filesize = hrnLibResolv->filesize; -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_last_error -//***********************************************************************************************************************************/ -//unsigned long -//libresolv_sftp_last_error(LIBRESOLV_SFTP *sftp) -//{ -// return (unsigned long)hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_LAST_ERROR, NULL, (HrnLibResolv *)sftp)->resultUInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_symlink_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_symlink_ex( -// LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type) -//{ -// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where -// // tests are being run. -// (void)path_len; -// (void)target_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_SYMLINK_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(path)), -// varNewStrZ(target)), -// varNewInt(link_type)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// int rc; -// -// switch (link_type) -// { -// case LIBRESOLV_SFTP_READLINK: -// case LIBRESOLV_SFTP_REALPATH: -// if (hrnLibResolv->symlinkExTarget != NULL) -// { -// if (strSize(hrnLibResolv->symlinkExTarget) < PATH_MAX) -// strncpy(target, strZ(hrnLibResolv->symlinkExTarget), strSize(hrnLibResolv->symlinkExTarget)); -// else -// THROW_FMT(AssertError, "symlinkExTarget too large for target buffer"); -// } -// -// rc = hrnLibResolv->resultInt != 0 ? hrnLibResolv->resultInt : (int)strSize(hrnLibResolv->symlinkExTarget); -// break; -// -// default: -// THROW_FMT(AssertError, "UNKNOWN link_type"); -// break; -// } -// -// return rc; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_open_ex -//***********************************************************************************************************************************/ -//LIBRESOLV_SFTP_HANDLE * -//libresolv_sftp_open_ex( -// LIBRESOLV_SFTP *sftp, const char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type) -//{ -// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where -// // tests are being run. -// (void)filename_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_OPEN_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(filename)), -// varNewUInt64(flags)), -// varNewInt64(mode)), -// varNewInt(open_type)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultNull ? NULL : (LIBRESOLV_SFTP_HANDLE *)hrnLibResolv; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_readdir_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_readdir_ex( -// LIBRESOLV_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, char *longentry, size_t longentry_maxlen, -// LIBRESOLV_SFTP_ATTRIBUTES *attrs) -//{ -// if (attrs == NULL) -// THROW_FMT(AssertError, "attrs is NULL"); -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_READDIR_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(buffer)), -// varNewUInt64(buffer_maxlen)), -// varNewStrZ(longentry)), -// varNewUInt64(longentry_maxlen)), -// (HrnLibResolv *)handle); -// } -// MEM_CONTEXT_TEMP_END(); -// -// if (hrnLibResolv->fileName != NULL) -// strncpy(buffer, strZ(hrnLibResolv->fileName), buffer_maxlen); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_session_last_errno -//***********************************************************************************************************************************/ -//int -//libresolv_session_last_errno(LIBRESOLV_SESSION *session) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SESSION_LAST_ERRNO, NULL, (HrnLibResolv *)session)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_fsync -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_fsync(LIBRESOLV_SFTP_HANDLE *handle) -//{ -// return hrnLibResolvScriptRun(HRNLIBRESOLV_SFTP_FSYNC, NULL, (HrnLibResolv *)handle)->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_mkdir_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_mkdir_ex(LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len, long mode) -//{ -// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on -// // where tests are being run. -// (void)path_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_MKDIR_EX, -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(path)), -// varNewInt64(mode)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_read -//***********************************************************************************************************************************/ -//ssize_t -//libresolv_sftp_read(LIBRESOLV_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen) -//{ -// // We don't pass buffer to hrnLibResolvScriptRun. The first call for each invocation passes buffer with random data, which is -// // an issue for sftpTest.c. -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_READ, -// varLstAdd( -// varLstNew(), varNewUInt64(buffer_maxlen)), -// (HrnLibResolv *)handle); -// } -// MEM_CONTEXT_TEMP_END(); -// -// // copy read into buffer -// if (hrnLibResolv->readBuffer != NULL) -// strncpy(buffer, strZ(hrnLibResolv->readBuffer), strSize(hrnLibResolv->readBuffer)); -// -// // number of bytes populated -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_rename_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_rename_ex( -// LIBRESOLV_SFTP *sftp, const char *source_filename, unsigned int source_filename_len, const char *dest_filename, -// unsigned int dest_filename_len, long flags) -//{ -// // To avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on -// // where tests are being run. -// (void)source_filename_len; -// (void)dest_filename_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_RENAME_EX, -// varLstAdd( -// varLstAdd( -// varLstAdd( -// varLstNew(), varNewStrZ(source_filename)), -// varNewStrZ(dest_filename)), -// varNewInt64(flags)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_rmdir_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_rmdir_ex(LIBRESOLV_SFTP *sftp, const char *path, unsigned int path_len) -//{ -// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where -// // tests are being run. -// (void)path_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_RMDIR_EX, -// varLstAdd( -// varLstNew(), varNewStrZ(path)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_seek64 -//***********************************************************************************************************************************/ -//void -//libresolv_sftp_seek64(LIBRESOLV_SFTP_HANDLE *handle, libresolv_uint64_t offset) -//{ -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_SEEK64, -// varLstAdd( -// varLstNew(), varNewUInt64(offset)), -// (HrnLibResolv *)handle); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_unlink_ex -//***********************************************************************************************************************************/ -//int -//libresolv_sftp_unlink_ex(LIBRESOLV_SFTP *sftp, const char *filename, unsigned int filename_len) -//{ -// // Avoid compiler complaining of unused param. Not passing to hrnLibResolvScriptRun, as parameter will vary depending on where -// // tests are being run. -// (void)filename_len; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_UNLINK_EX, -// varLstAdd( -// varLstNew(), varNewStrZ(filename)), -// (HrnLibResolv *)sftp); -// } -// MEM_CONTEXT_TEMP_END(); -// -// return hrnLibResolv->resultInt; -//} -// -///*********************************************************************************************************************************** -//Shim for libresolv_sftp_write -//***********************************************************************************************************************************/ -//ssize_t -//libresolv_sftp_write(LIBRESOLV_SFTP_HANDLE *handle, const char *buffer, size_t count) -//{ -// // We don't pass buffer to hrnLibResolvScriptRun. The first call for each invocation passes buffer with random data, which is -// // an issue for sftpTest.c. -// (void)buffer; -// -// HrnLibResolv *hrnLibResolv = NULL; -// -// MEM_CONTEXT_TEMP_BEGIN() -// { -// hrnLibResolv = hrnLibResolvScriptRun( -// HRNLIBRESOLV_SFTP_WRITE, -// varLstAdd( -// varLstNew(), varNewUInt64(count)), -// (HrnLibResolv *)handle); -// } -// MEM_CONTEXT_TEMP_END(); -// -// // Return number of bytes written -// return hrnLibResolv->resultInt; -//} diff --git a/test/src/common/harnessLibResolv.h b/test/src/common/harnessLibResolv.h deleted file mode 100644 index 003494d216..0000000000 --- a/test/src/common/harnessLibResolv.h +++ /dev/null @@ -1,70 +0,0 @@ -/*********************************************************************************************************************************** -libresolv Test Harness - -Scripted testing for libresolv so exact results can be returned for unit testing. See sftp unit tests for usage examples. -***********************************************************************************************************************************/ -#ifndef TEST_COMMON_HARNESS_LIBRESOLV_H -#define TEST_COMMON_HARNESS_LIBRESOLV_H - -#ifdef HAVE_LIBRESOLV - -#ifndef HARNESS_LIBRESOLV_REAL - -#include -#include - -#include "common/macro.h" -#include "common/time.h" -#include "version.h" - -/*********************************************************************************************************************************** -libresolv authorization constants -***********************************************************************************************************************************/ -//#define HOSTKEY "12345678901234567890" - -/*********************************************************************************************************************************** -Function constants -***********************************************************************************************************************************/ -#define HRNLIBRESOLV_RES_NQUERY "res_nquery" - -/*********************************************************************************************************************************** -Macros for defining groups of functions that implement commands -***********************************************************************************************************************************/ - -/*********************************************************************************************************************************** -Structure for scripting libresolv responses -***********************************************************************************************************************************/ -typedef struct HrnLibResolv -{ - unsigned int session; // Session number when multiple sessions are run concurrently - const char *function; // Function call expected - const char *param; // Params expected by the function for verification - int resultInt; // Int result value - uint64_t resultUInt; // UInt result value - const char *resultZ; // Zero-terminated result value - bool resultNull; // Return null from function that normally returns a struct ptr - size_t len; // libresolv_session_hostkey len -// uint64_t flags; // libresolv flags -// uint64_t attrPerms; // libresolv attr perms -// uint64_t atime, mtime; // libresolv timestamps -// uint64_t uid, gid; // libresolv uid/gid -// uint64_t filesize; // libresolv filesize -// uint64_t offset; // libresolv seek offset -// const String *symlinkExTarget; // libresolv_sftp_symlink_ex target -// const String *fileName; // libresolv_readdir* libresolv_stat* filename -// const String *readBuffer; // what to copy into read buffer -// TimeMSec sleep; // Sleep specified milliseconds before returning from function -// int type; // libresolv_session_hostkey type -// char *errMsg; // libresolv_session_last_error error msg -} HrnLibResolv; - -/*********************************************************************************************************************************** -Functions -***********************************************************************************************************************************/ -void hrnLibResolvScriptSet(HrnLibResolv *hrnLibResolvScriptParam); - -#endif // HARNESS_LIBRESOLV_REAL - -#endif // HAVE_LIBRESOLV - -#endif // TEST_COMMON_HARNESS_LIBRESOLV_H diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index 6436a0ecb1..ba90325f31 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -7,6 +7,7 @@ libssh2 Test Harness #include #include +#include #include "common/type/json.h" #include "common/type/string.h" diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c new file mode 100644 index 0000000000..9a240910d2 --- /dev/null +++ b/test/src/common/harnessSftpResolv.c @@ -0,0 +1,196 @@ +/*********************************************************************************************************************************** +Harness for SFTP libresolv Testing +***********************************************************************************************************************************/ +#include "build.auto.h" + +#include "common/harnessConfig.h" +#include "common/harnessDebug.h" +#include "common/harnessSftpResolv.h" + +#include +#ifndef __USE_MISC +#define __USE_MISC 1 +#endif +#include + +/*********************************************************************************************************************************** +Include shimmed C modules +***********************************************************************************************************************************/ +{[SHIM_MODULE]} + +/*********************************************************************************************************************************** +Shim install state +***********************************************************************************************************************************/ +static struct +{ + bool localShimSftpResolv; // Is the shim installed? +} hrnSftpResolvStatic; + + +/*********************************************************************************************************************************** +Shim storageSftpResNinit() +***********************************************************************************************************************************/ +int +storageSftpResNinit(res_state statep) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM_P(VOID, statep); + FUNCTION_HARNESS_END(); + + int result; + + if (hrnSftpResolvStatic.localShimSftpResolv) + { + // Use the RES_IGNTC option indicate when to return a failure + if ((my_res_state.options & RES_IGNTC) == RES_IGNTC) + result = -1; + else + result = 0; + } + // Else call the normal function + else + result = storageSftpResNinit_SHIMMED(statep); + + FUNCTION_HARNESS_RETURN(INT, result); +} + +/*********************************************************************************************************************************** +Shim storageSftpResNquery() +***********************************************************************************************************************************/ +int +storageSftpResNquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM_P(VOID, statep); + FUNCTION_HARNESS_PARAM(STRINGZ, dname); + FUNCTION_HARNESS_PARAM(INT, class); + FUNCTION_HARNESS_PARAM(INT, type); + FUNCTION_HARNESS_PARAM(UCHARDATA, answer); + FUNCTION_HARNESS_PARAM(INT, anslen); + FUNCTION_HARNESS_END(); + + int result; + + (void)statep; + (void)dname; + (void)class; + (void)type; + (void)answer; + (void)anslen; + + if (hrnSftpResolvStatic.localShimSftpResolv) + { + + if (strcmp(dname, "trustad-fail") == 0) + { + result = 0; + } + else if (strcmp(dname, "trustad-pass") == 0) + { + result = 1; + } + else + { + result = -1; + statep->res_h_errno = NO_DATA; + } + } + // Else call the normal function + else + result = storageSftpResNquery_SHIMMED(statep, dname, class, type, answer, anslen); + + FUNCTION_HARNESS_RETURN(INT, result); +} + +/*********************************************************************************************************************************** +Shim storageSftpNsInitparse() +***********************************************************************************************************************************/ +int +storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM(UCHARDATA, answer); + FUNCTION_HARNESS_PARAM(INT, len); + FUNCTION_HARNESS_PARAM_P(VOID, handle); + FUNCTION_HARNESS_END(); + + int result; + + if (hrnSftpResolvStatic.localShimSftpResolv) + { + switch (len) + { + case 0: + result = 0; + break; + + case 1: + result = 1; + break; + + default: + result = -1; + break; + } + } + else + result = storageSftpNsInitparse_SHIMMED(answer, len, handle); + + // jrt !!! start here + // Populate handle with dummy data for storageSftpNsMsgGetflag() to work + + + FUNCTION_HARNESS_RETURN(INT, result); +} + +/*********************************************************************************************************************************** +Shim storageSftpNsMsgGetflag() +***********************************************************************************************************************************/ +static int +storageSftpNsMsgGetflag(ns_msg handle, int ns_f_ad) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM(VOID, handle); + FUNCTION_HARNESS_PARAM(INT, ns_f_ad); + FUNCTION_HARNESS_END(); + + (void)handle; + (void)ns_f_ad; + + int result; + + if (hrnSftpResolvStatic.localShimSftpResolv) + { + if (ns_f_ad == 1 ) + result = 1; + else + result = 0; + } + // Else call the normal function + else + result = storageSftpNsMsgGetflag_SHIMMED(handle, ns_f_ad); + + FUNCTION_HARNESS_RETURN(INT, result); +} + +/**********************************************************************************************************************************/ +void +hrnSftpResolvShimInstall(void) +{ + FUNCTION_HARNESS_VOID(); + + hrnSftpResolvStatic.localShimSftpResolv = true; + + FUNCTION_HARNESS_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +void +hrnSftpResolvShimUninstall(void) +{ + FUNCTION_HARNESS_VOID(); + + hrnSftpResolvStatic.localShimSftpResolv = false; + + FUNCTION_HARNESS_RETURN_VOID(); +} diff --git a/test/src/common/harnessSftpResolv.h b/test/src/common/harnessSftpResolv.h new file mode 100644 index 0000000000..01001fc98e --- /dev/null +++ b/test/src/common/harnessSftpResolv.h @@ -0,0 +1,10 @@ +/*********************************************************************************************************************************** +Harness for SFTP libresolv Testing +***********************************************************************************************************************************/ + +/*********************************************************************************************************************************** +Functions +***********************************************************************************************************************************/ +// Install/uninstall shim +void hrnSftpResolvShimInstall(void); +void hrnSftpResolvShimUninstall(void); diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 6f3c45aa8b..0a0be64ea1 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -14,6 +14,7 @@ Test SFTP Storage #include "common/harnessFd.h" #include "common/harnessFork.h" #include "common/harnessLibSsh2.h" +#include "common/harnessSftpResolv.h" #include "common/harnessSocket.h" #include "common/harnessStorage.h" @@ -1144,7 +1145,10 @@ testRun(void) memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file RSA, trustAd"); + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd, res_nquery fail"); + + // Install shim for libresolv + hrnSftpResolvShimInstall(); hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -1173,11 +1177,7 @@ testRun(void) .param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", - .resultInt = 0}, - {.function = HRNLIBSSH2_SFTP_INIT}, - HRNLIBSSH2_MACRO_SHUTDOWN() + {.function = NULL} }); argList = strLstNew(); @@ -1195,11 +1195,9 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - storageTest = NULL; harnessLogLevelSet(logLevelDetail); - TEST_ASSIGN( - storageTest, + TEST_ERROR( storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), @@ -1211,7 +1209,9 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - "new storage (defaults)"); + ServiceError, + "res_nquery error [4] No address associated with name 'localhost'"); + TEST_RESULT_LOG( "P00 DETAIL: libssh2 '/home/" TEST_USER "/.ssh/known_hosts' file is empty\n" "P00 DETAIL: libssh2 read '/home/" TEST_USER "/.ssh/known_hosts2' failed: libssh2 errno [-16] Failed to open file\n" @@ -1226,6 +1226,219 @@ testRun(void) memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd fail"); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"trustad-fail\",22,\"" HOSTKEY "\",20,65537]", + .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_ADDC, + .param = "[\"trustad-fail\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, + {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = NULL} + }); + + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "trustad-fail"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, + .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), + .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), + .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), + .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "Host is untrusted, RES_TRUSTAD not set in response"); + + TEST_RESULT_LOG( + "P00 WARN: host 'trustad-fail' not found in known hosts files, attempting to add host to " + "'/home/" TEST_USER "/.ssh/known_hosts'\n" + "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd pass"); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"trustad-pass\",22,\"" HOSTKEY "\",20,65537]", + .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_ADDC, + .param = "[\"trustad-pass\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, + {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = NULL} + }); + + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "trustad-pass"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + storageSftpSetOption(&my_res_state, RES_TRUSTAD); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, + .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), + .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), + .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), + .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "Host is untrusted, RES_TRUSTAD not set in response"); + + TEST_RESULT_LOG( + "P00 WARN: host 'trustad-pass' not found in known hosts files, attempting to add host to " + "'/home/" TEST_USER "/.ssh/known_hosts'\n" + "P00 WARN: pgBackRest added new host 'trustad-pass' to '/home/" TEST_USER "/.ssh/known_hosts'"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, storageSftpResInit fail"); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"trustad-fail\",22,\"" HOSTKEY "\",20,65537]", + .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_KNOWNHOST_ADDC, + .param = "[\"trustad-fail\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, + {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", + .resultInt = LIBSSH2_ERROR_NONE}, + {.function = NULL} + }); + + // Use the RES_IGNTC option indicate when to return a failure from res_ninit + TEST_RESULT_VOID(storageSftpSetOption(&my_res_state, RES_IGNTC), "set resolv option IGNTC"); + + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "trustad-fail"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, + .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), + .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), + .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), + .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), + .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "unable to initialize resolver"); + + TEST_RESULT_LOG( + "P00 WARN: host 'trustad-fail' not found in known hosts files, attempting to add host to " + "'/home/" TEST_USER "/.ssh/known_hosts'\n" + "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); + + // Uninstall shim for libresolv + hrnSftpResolvShimUninstall(); +>>>>>>> 451c94824 (Start to shim libresolv functions in order to implement tests) + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file DSS"); @@ -1260,6 +1473,21 @@ testRun(void) HRNLIBSSH2_MACRO_SHUTDOWN() }); + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + storageTest = NULL; TEST_ASSIGN( From 03e82e06a68526dc5f3fb33f367b012fc0e069da Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 23 Oct 2023 11:59:47 -0400 Subject: [PATCH 06/54] Rework trustad Update tests --- src/storage/sftp/storage.c | 34 +++++++++-------------- test/define.yaml | 1 - test/src/common/harnessSftpResolv.c | 42 ++++++----------------------- test/src/module/storage/sftpTest.c | 24 +++++++++++------ 4 files changed, 37 insertions(+), 64 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 78463078ae..822b698428 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1135,6 +1135,7 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u FUNCTION_LOG_RETURN(INT, res_nquery(statep, dname, class, type, answer, anslen)); } +/**********************************************************************************************************************************/ static int storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) { @@ -1147,30 +1148,17 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) FUNCTION_LOG_RETURN(INT, ns_initparse(answer, len, handle)); } -/**********************************************************************************************************************************/ -static int -storageSftpNsMsgGetflag(ns_msg handle, int ns_f_ad) -{ - FUNCTION_LOG_BEGIN(logLevelTrace); - FUNCTION_LOG_PARAM(VOID, handle); - FUNCTION_LOG_PARAM(INT, ns_f_ad); - FUNCTION_LOG_END(); - - ASSERT(ns_f_ad >= 0 && ns_f_ad <= ns_f_max); - - FUNCTION_LOG_RETURN(INT, ns_msg_getflag(handle, ns_f_ad)); -} - // !!! Do any supported OS's not support this code? /*********************************************************************************************************************************** Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated on the fact that the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is secure. ***********************************************************************************************************************************/ -void -storageSftpTrustAd(const String *const host) +static void +storageSftpTrustAd(StorageSftp *const this, const String *const host) { FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(STORAGE_SFTP, this); FUNCTION_LOG_PARAM(STRING, host); FUNCTION_LOG_END(); @@ -1200,18 +1188,22 @@ storageSftpTrustAd(const String *const host) "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } - // Parse the response - ns_msg handle = {0}; + // Initialize parsing the response + ns_msg handle; storageSftpNsInitparse(answer, len, &handle); - // Check the res_trustad flag - if (storageSftpNsMsgGetflag(handle, ns_f_ad) != 1) + // Check the RES_TRUSTAD flag + HEADER *dnsMsgHeader = (HEADER *)answer; + if ((dnsMsgHeader->ad) != 1) { res_nclose(&my_res_state); THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); } + // Check that the fingerprint is in the SSHFP list +// storageSftpVerifyFingerprint(this, handle); + // Close the resolver res_nclose(&my_res_state); @@ -1471,7 +1463,7 @@ storageSftpNew( } if (param.trustAd) - storageSftpTrustAd(host); + storageSftpTrustAd(this, host); // Perform public key authorization, expand leading tilde key file paths if needed String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); diff --git a/test/define.yaml b/test/define.yaml index a30e565f5b..7a9a3c23c6 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -617,7 +617,6 @@ unit: - storageSftpResNinit - storageSftpResNquery - storageSftpNsInitparse - - storageSftpNsMsgGetflag harness: name: fd shim: diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 9a240910d2..2c5f3cbff6 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -30,7 +30,7 @@ static struct /*********************************************************************************************************************************** Shim storageSftpResNinit() ***********************************************************************************************************************************/ -int +static int storageSftpResNinit(res_state statep) { FUNCTION_HARNESS_BEGIN(); @@ -57,7 +57,7 @@ storageSftpResNinit(res_state statep) /*********************************************************************************************************************************** Shim storageSftpResNquery() ***********************************************************************************************************************************/ -int +static int storageSftpResNquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) { FUNCTION_HARNESS_BEGIN(); @@ -80,19 +80,23 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u if (hrnSftpResolvStatic.localShimSftpResolv) { + HEADER *header = (HEADER *)answer; if (strcmp(dname, "trustad-fail") == 0) { result = 0; + header->ad = 0; } else if (strcmp(dname, "trustad-pass") == 0) { result = 1; + header->ad = 1; } else { result = -1; statep->res_h_errno = NO_DATA; + header->ad = 0; } } // Else call the normal function @@ -105,7 +109,7 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u /*********************************************************************************************************************************** Shim storageSftpNsInitparse() ***********************************************************************************************************************************/ -int +static int storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) { FUNCTION_HARNESS_BEGIN(); @@ -136,43 +140,13 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) else result = storageSftpNsInitparse_SHIMMED(answer, len, handle); - // jrt !!! start here + // jrt !!! TBD if needed start here // Populate handle with dummy data for storageSftpNsMsgGetflag() to work FUNCTION_HARNESS_RETURN(INT, result); } -/*********************************************************************************************************************************** -Shim storageSftpNsMsgGetflag() -***********************************************************************************************************************************/ -static int -storageSftpNsMsgGetflag(ns_msg handle, int ns_f_ad) -{ - FUNCTION_HARNESS_BEGIN(); - FUNCTION_HARNESS_PARAM(VOID, handle); - FUNCTION_HARNESS_PARAM(INT, ns_f_ad); - FUNCTION_HARNESS_END(); - - (void)handle; - (void)ns_f_ad; - - int result; - - if (hrnSftpResolvStatic.localShimSftpResolv) - { - if (ns_f_ad == 1 ) - result = 1; - else - result = 0; - } - // Else call the normal function - else - result = storageSftpNsMsgGetflag_SHIMMED(handle, ns_f_ad); - - FUNCTION_HARNESS_RETURN(INT, result); -} - /**********************************************************************************************************************************/ void hrnSftpResolvShimInstall(void) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 0a0be64ea1..48395baf9b 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1145,9 +1145,9 @@ testRun(void) memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd, res_nquery fail"); + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd, res_nquery fail, shimmed"); - // Install shim for libresolv + // Install shim for SFTP libresolv functions hrnSftpResolvShimInstall(); hrnLibSsh2ScriptSet((HrnLibSsh2 []) @@ -1324,7 +1324,11 @@ testRun(void) .param = "[\"trustad-pass\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, - {.function = NULL} + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = 0}, + {.function = HRNLIBSSH2_SFTP_INIT}, + HRNLIBSSH2_MACRO_SHUTDOWN() }); argList = strLstNew(); @@ -1342,9 +1346,12 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - storageSftpSetOption(&my_res_state, RES_TRUSTAD); +// jrt remove storageSftpSetOption(&my_res_state, RES_TRUSTAD); - TEST_ERROR( + storageTest = NULL; + + TEST_ASSIGN( + storageTest, storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), @@ -1356,14 +1363,15 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, - "Host is untrusted, RES_TRUSTAD not set in response"); + "new storage (defaults)"); TEST_RESULT_LOG( "P00 WARN: host 'trustad-pass' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'trustad-pass' to '/home/" TEST_USER "/.ssh/known_hosts'"); + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - add host to known_hosts file RSA, storageSftpResInit fail"); @@ -1435,7 +1443,7 @@ testRun(void) "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); - // Uninstall shim for libresolv + // Uninstall shim for SFTP libresolv functions hrnSftpResolvShimUninstall(); >>>>>>> 451c94824 (Start to shim libresolv functions in order to implement tests) From 68dcbe03912057c20f9849c84d2736c673440508 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 30 Oct 2023 11:57:45 -0400 Subject: [PATCH 07/54] Refactor. Update/add tests --- src/storage/sftp/storage.c | 67 +++++++++++- test/define.yaml | 3 +- test/src/common/harnessLibSsh2.c | 2 +- test/src/common/harnessSftpResolv.c | 21 +++- test/src/module/storage/sftpTest.c | 157 +++++++++++++++++++++++++--- 5 files changed, 228 insertions(+), 22 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 822b698428..5dab162513 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1148,6 +1148,71 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) FUNCTION_LOG_RETURN(INT, ns_initparse(answer, len, handle)); } +/**********************************************************************************************************************************/ +static void +storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, session); + FUNCTION_LOG_PARAM(VOID, handle); + FUNCTION_LOG_END(); + + bool result = false; + + for (int rrnum = 0; rrnum < ns_msg_count(handle, ns_s_an); rrnum++) + { + ns_rr rr; + + ns_parserr(&handle, ns_s_an, rrnum, &rr); + + typedef struct rdata_sshfp + { + unsigned algorithm : 8; + unsigned digest_type : 8; + unsigned char *digest; + } rdata_sshfp_t; + + rdata_sshfp_t sshfp; + + sshfp.digest_type = *((unsigned char *) ns_rr_rdata(rr) + 1); + sshfp.digest = (unsigned char *) ns_rr_rdata(rr) + 2; + + int hashType; + size_t hashSize; + + // Only SHA1 and SHA256 are currently defined as valid SSHFP RR types for fingerprint types + if (sshfp.digest_type == 1) + { + hashType = LIBSSH2_HOSTKEY_HASH_SHA1; + hashSize = HASH_TYPE_SHA1_SIZE; + } + else + { + hashType = LIBSSH2_HOSTKEY_HASH_SHA256; + hashSize = HASH_TYPE_SHA256_SIZE; + } + + // Generate hex encoded sshfp.digest + char buffer[256]; + encodeToStr(encodingHex, sshfp.digest, hashSize, buffer); + + const char *binaryFingerprint = libssh2_hostkey_hash(session, hashType); + + if (binaryFingerprint != NULL && memcmp(binaryFingerprint, sshfp.digest, ns_rr_rdlen(rr) - 2) == 0) + { + result = true; + LOG_DETAIL_FMT("sshfp fingerprint match found for sshfp.digest_type '%d' '%s'", sshfp.digest_type, buffer); + } + else + LOG_DETAIL_FMT("no sshfp fingerprint match found for sshfp.digest_type '%d' '%s'", sshfp.digest_type, buffer); + } + + if (result == false) + THROW_FMT(ServiceError, "Host key not found in SSHFP record"); + + FUNCTION_LOG_RETURN_VOID(); +} + // !!! Do any supported OS's not support this code? /*********************************************************************************************************************************** Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the @@ -1202,7 +1267,7 @@ storageSftpTrustAd(StorageSftp *const this, const String *const host) } // Check that the fingerprint is in the SSHFP list -// storageSftpVerifyFingerprint(this, handle); + storageSftpVerifyFingerprint(this->session, handle); // Close the resolver res_nclose(&my_res_state); diff --git a/test/define.yaml b/test/define.yaml index 7a9a3c23c6..f3d7274262 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -607,7 +607,7 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: sftp - total: 19 + total: 20 harness: libSsh2 harness: name: sftpResolv @@ -617,6 +617,7 @@ unit: - storageSftpResNinit - storageSftpResNquery - storageSftpNsInitparse + - storageSftpVerifyFingerprint harness: name: fd shim: diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index ba90325f31..eabfd40884 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -5,9 +5,9 @@ libssh2 Test Harness #ifdef HAVE_LIBSSH2 +#include #include #include -#include #include "common/type/json.h" #include "common/type/string.h" diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 2c5f3cbff6..c181a3c9de 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -26,7 +26,6 @@ static struct bool localShimSftpResolv; // Is the shim installed? } hrnSftpResolvStatic; - /*********************************************************************************************************************************** Shim storageSftpResNinit() ***********************************************************************************************************************************/ @@ -87,7 +86,7 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u result = 0; header->ad = 0; } - else if (strcmp(dname, "trustad-pass") == 0) + else if (strcmp(dname, "trustad-pass") == 0 || strcmp(dname, "localhost") == 0) { result = 1; header->ad = 1; @@ -140,11 +139,23 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) else result = storageSftpNsInitparse_SHIMMED(answer, len, handle); - // jrt !!! TBD if needed start here - // Populate handle with dummy data for storageSftpNsMsgGetflag() to work + FUNCTION_HARNESS_RETURN(INT, result); +} +/*********************************************************************************************************************************** +Shim storageSftpVerifyFingerprint() +***********************************************************************************************************************************/ +static void +storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) +{ + if (session == NULL) + THROW(AssertError, "storageSftpVerifyFingerprint expects 'session' to be not null"); - FUNCTION_HARNESS_RETURN(INT, result); + if (hrnSftpResolvStatic.localShimSftpResolv) + { + } + else + storageSftpVerifyFingerprint_SHIMMED(session, handle); } /**********************************************************************************************************************************/ diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 48395baf9b..6dd2cfd25b 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1168,13 +1168,13 @@ testRun(void) .resultInt = LIBSSH2_ERROR_FILE}, {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, - {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]", + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"no-data\",22,\"" HOSTKEY "\",20,65537]", .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, {.function = HRNLIBSSH2_KNOWNHOST_INIT}, {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_KNOWNHOST_ADDC, - .param = "[\"localhost\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, + .param = "[\"no-data\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, {.function = NULL} @@ -1187,7 +1187,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoPath, TEST_PATH); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "no-data"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); @@ -1196,7 +1196,6 @@ testRun(void) HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - harnessLogLevelSet(logLevelDetail); TEST_ERROR( storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), @@ -1210,19 +1209,12 @@ testRun(void) .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, - "res_nquery error [4] No address associated with name 'localhost'"); + "res_nquery error [4] No address associated with name 'no-data'"); TEST_RESULT_LOG( - "P00 DETAIL: libssh2 '/home/" TEST_USER "/.ssh/known_hosts' file is empty\n" - "P00 DETAIL: libssh2 read '/home/" TEST_USER "/.ssh/known_hosts2' failed: libssh2 errno [-16] Failed to open file\n" - "P00 DETAIL: libssh2 read '/etc/ssh/ssh_known_hosts' failed: libssh2 errno [-16] Failed to open file\n" - "P00 DETAIL: libssh2 read '/etc/ssh/ssh_known_hosts2' failed: libssh2 errno [-16] libssh2 no session error message " - "provided [-16]\n" - "P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to " + "P00 WARN: host 'no-data' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" - "P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'"); - - harnessLogLevelReset(); + "P00 WARN: pgBackRest added new host 'no-data' to '/home/" TEST_USER "/.ssh/known_hosts'"); memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); @@ -8154,6 +8146,143 @@ testRun(void) #endif // HAVE_LIBSSH2 } + // ***************************************************************************************************************************** + if (testBegin("storageSftpVerifyFingerprint()")) + { +#ifdef HAVE_LIBSSH2 + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("storageSftpVerifyFingerprint() fail"); + + harnessLogLevelSet(logLevelDetail); + + TimeMSec timeout = 500; + const StorageSftpNewParam param = {.trustAd = true}; + const String *host = STRDEF("muffat.debian.org"); + unsigned int port = 22; + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultNull = true}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, + {.function = NULL}, + }); + + OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) + { + *this = (StorageSftp) + { + .interface = storageInterfaceSftp, + .timeout = timeout, + }; + + // Init SFTP session + if (libssh2_init(0) != 0) + THROW_FMT(ServiceError, "unable to init libssh2"); + + this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); + this->session = libssh2_session_init(); + + if (this->session == NULL) + THROW_FMT(ServiceError, "unable to init libssh2 session"); + + // Set session to non-blocking + libssh2_session_set_blocking(this->session, 0); + + // Perform handshake + int rc; + + do + { + rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); + } + while (storageSftpWaitFd(this, rc)); + + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); + + if (rc != 0) + THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); + + if (param.trustAd) + { + // storageSftpTrustAd(this, host); + if (storageSftpResNinit(&my_res_state) != 0) + THROW_FMT(ServiceError, "unable to initialize resolver"); + + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); + + // Query the server for SSHFP records + unsigned char answer[PACKET_SZ]; + + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + + // Check for errors. + // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we + // think that's better. + if (len < 0) + { + // Closing before throwing the error does not seem to mess up the hstrerror() call + res_nclose(&my_res_state); + + THROW_FMT( + ServiceError, + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), + strZ(host)); + } + + // Overwrite the sshfp response with a known defined response for testing + Buffer *sshfp = + storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); + TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + memset(answer, 0, sizeof(answer)); + memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); + len = (int)bufUsed(sshfp); + + // Initialize parsing the response + ns_msg handle; + storageSftpNsInitparse(answer, len, &handle); + + // Check the RES_TRUSTAD flag + HEADER *dnsMsgHeader = (HEADER *)answer; + if ((dnsMsgHeader->ad) != 1) + { + res_nclose(&my_res_state); + + THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); + } + + // Check that the fingerprint is in the SSHFP list + TEST_ERROR_FMT( + storageSftpVerifyFingerprint(this->session, handle), ServiceError, "Host key not found in SSHFP record"); + + // Close the resolver + res_nclose(&my_res_state); + } + } + OBJ_NEW_END(); + + objFree(this); + + TEST_RESULT_LOG( + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' '87ac6bede384d2dc6254f396b83ed34856512e64'"); + + harnessLogLevelReset(); +#else + TEST_LOG(PROJECT_NAME " not built with sftp support"); +#endif // HAVE_LIBSSH2 + } + #ifdef HAVE_LIBSSH2 hrnFdReadyShimUninstall(); hrnSckClientOpenShimUninstall(); From 134f159b750feb595bf7e98436944543a0a957e6 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 30 Oct 2023 17:09:12 -0400 Subject: [PATCH 08/54] u22 full coverage --- src/storage/sftp/storage.c | 22 +++-- test/define.yaml | 2 +- test/src/common/harnessLibSsh2.c | 14 ++- test/src/common/harnessLibSsh2.h | 1 + test/src/module/storage/sftpTest.c | 148 ++++++++++++++++++++++++++++- 5 files changed, 175 insertions(+), 12 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 5dab162513..50f8f57043 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1181,15 +1181,19 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) size_t hashSize; // Only SHA1 and SHA256 are currently defined as valid SSHFP RR types for fingerprint types - if (sshfp.digest_type == 1) + switch (sshfp.digest_type) { - hashType = LIBSSH2_HOSTKEY_HASH_SHA1; - hashSize = HASH_TYPE_SHA1_SIZE; - } - else - { - hashType = LIBSSH2_HOSTKEY_HASH_SHA256; - hashSize = HASH_TYPE_SHA256_SIZE; + case 1: + hashType = LIBSSH2_HOSTKEY_HASH_SHA1; + hashSize = HASH_TYPE_SHA1_SIZE; + break; + +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + case 2: + hashType = LIBSSH2_HOSTKEY_HASH_SHA256; + hashSize = HASH_TYPE_SHA256_SIZE; + break; +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 } // Generate hex encoded sshfp.digest @@ -1198,7 +1202,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) const char *binaryFingerprint = libssh2_hostkey_hash(session, hashType); - if (binaryFingerprint != NULL && memcmp(binaryFingerprint, sshfp.digest, ns_rr_rdlen(rr) - 2) == 0) + if (binaryFingerprint != NULL && memcmp(binaryFingerprint, sshfp.digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) { result = true; LOG_DETAIL_FMT("sshfp fingerprint match found for sshfp.digest_type '%d' '%s'", sshfp.digest_type, buffer); diff --git a/test/define.yaml b/test/define.yaml index f3d7274262..3b9355480d 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -607,7 +607,7 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: sftp - total: 20 + total: 21 harness: libSsh2 harness: name: sftpResolv diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index eabfd40884..f193569718 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -430,7 +430,19 @@ libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type) } MEM_CONTEXT_TEMP_END(); - return hrnLibSsh2->resultNull ? NULL : (const char *)hrnLibSsh2->resultZ; + char *result; + + // For this resultZ, return it's binary representation to get a succssful match + if (hrnLibSsh2->resultZ != NULL && strcmp(hrnLibSsh2->resultZ, "87ac6bede384d2dc6254f396b83ed34856512e64") == 0) + { + decodeToBin(encodingHex, hrnLibSsh2->resultZ, hrnLibSsh2->fingerPrint); + + result = (char *)hrnLibSsh2->fingerPrint; + } + else + result = (char *)hrnLibSsh2->resultZ; + + return hrnLibSsh2->resultNull ? NULL : (const char *)result; } /*********************************************************************************************************************************** diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index c17377eae8..a032bcb4f0 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -127,6 +127,7 @@ typedef struct HrnLibSsh2 size_t len; // libssh2_session_hostkey len int type; // libssh2_session_hostkey type char *errMsg; // libssh2_session_last_error error msg + unsigned char fingerPrint[1024]; // binary finger print } HrnLibSsh2; /*********************************************************************************************************************************** diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 6dd2cfd25b..c466b4afd3 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8157,7 +8157,8 @@ testRun(void) TimeMSec timeout = 500; const StorageSftpNewParam param = {.trustAd = true}; - const String *host = STRDEF("muffat.debian.org"); + // const String *host = STRDEF("muffat.debian.org"); + const String *host = STRDEF("www.postgresql.org"); unsigned int port = 22; hrnLibSsh2ScriptSet((HrnLibSsh2 []) @@ -8166,8 +8167,16 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = HOSTKEY}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = HOSTKEY}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultNull = true}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, {.function = NULL}, }); @@ -8283,6 +8292,143 @@ testRun(void) #endif // HAVE_LIBSSH2 } + // ***************************************************************************************************************************** + if (testBegin("storageSftpVerifyFingerprint() localhost")) + { +#ifdef HAVE_LIBSSH2 + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("storageSftpVerifyFingerprint() success"); + + harnessLogLevelSet(logLevelDetail); + + TimeMSec timeout = 500; + const StorageSftpNewParam param = {.trustAd = true}; + // const String *host = STRDEF("muffat.debian.org"); + const String *host = STRDEF("www.postgresql.org"); + unsigned int port = 22; + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultNull = true}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "87ac6bede384d2dc6254f396b83ed34856512e64"}, + {.function = NULL}, + }); + + OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) + { + *this = (StorageSftp) + { + .interface = storageInterfaceSftp, + .timeout = timeout, + }; + + // Init SFTP session + if (libssh2_init(0) != 0) + THROW_FMT(ServiceError, "unable to init libssh2"); + + this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); + this->session = libssh2_session_init(); + + if (this->session == NULL) + THROW_FMT(ServiceError, "unable to init libssh2 session"); + + // Set session to non-blocking + libssh2_session_set_blocking(this->session, 0); + + // Perform handshake + int rc; + + do + { + rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); + } + while (storageSftpWaitFd(this, rc)); + + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); + + if (rc != 0) + THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); + + if (param.trustAd) + { + // storageSftpTrustAd(this, host); + if (storageSftpResNinit(&my_res_state) != 0) + THROW_FMT(ServiceError, "unable to initialize resolver"); + + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); + + // Query the server for SSHFP records + unsigned char answer[PACKET_SZ]; + + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + + // Check for errors. + // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we + // think that's better. + if (len < 0) + { + // Closing before throwing the error does not seem to mess up the hstrerror() call + res_nclose(&my_res_state); + + THROW_FMT( + ServiceError, + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), + strZ(host)); + } + + // Overwrite the sshfp response with a known defined response for testing + Buffer *sshfp = + storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); + TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + memset(answer, 0, sizeof(answer)); + memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); + len = (int)bufUsed(sshfp); + + // Initialize parsing the response + ns_msg handle; + storageSftpNsInitparse(answer, len, &handle); + + // Check the RES_TRUSTAD flag + HEADER *dnsMsgHeader = (HEADER *)answer; + if ((dnsMsgHeader->ad) != 1) + { + res_nclose(&my_res_state); + + THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); + } + + // Check that the fingerprint is in the SSHFP list + TEST_RESULT_VOID(storageSftpVerifyFingerprint(this->session, handle), "Host key found in SSHFP record"); + + // Close the resolver + res_nclose(&my_res_state); + } + } + OBJ_NEW_END(); + + objFree(this); + + TEST_RESULT_LOG( + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" + "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type '1' '87ac6bede384d2dc6254f396b83ed34856512e64'"); + + harnessLogLevelReset(); +#else + TEST_LOG(PROJECT_NAME " not built with sftp support"); +#endif // HAVE_LIBSSH2 + } + #ifdef HAVE_LIBSSH2 hrnFdReadyShimUninstall(); hrnSckClientOpenShimUninstall(); From d2a21c4acd50e0e4f6b4f1d82440a3e681e83441 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 31 Oct 2023 01:22:13 -0400 Subject: [PATCH 09/54] Update help Update helpTest.c Update testTest.c Minor refactoring --- src/build/help/help.xml | 2 +- src/storage/sftp/storage.c | 22 ++++++++-------------- test/src/module/command/helpTest.c | 1 + test/src/module/test/testTest.c | 4 ++++ 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index d91108188c..5d26c3300b 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1060,7 +1060,7 @@ - SFTP Require Trust-Ad. + SFTP require Trust-Ad.

!!! TBD - Perform a minimal host verification via DNSSEC. This verification assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. It queries the DNS server for the host and SSHFP records with RES_TRUSTAD (ad bit) set. If the response ad bit is not set, the host is not trusted. If the ad is is set a check will be made for a matching key in the SSHFP records.

diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 50f8f57043..0bc1a4040a 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1177,24 +1177,18 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) sshfp.digest_type = *((unsigned char *) ns_rr_rdata(rr) + 1); sshfp.digest = (unsigned char *) ns_rr_rdata(rr) + 2; - int hashType; - size_t hashSize; - // Only SHA1 and SHA256 are currently defined as valid SSHFP RR types for fingerprint types - switch (sshfp.digest_type) - { - case 1: - hashType = LIBSSH2_HOSTKEY_HASH_SHA1; - hashSize = HASH_TYPE_SHA1_SIZE; - break; + int hashType = LIBSSH2_HOSTKEY_HASH_SHA1; + size_t hashSize = HASH_TYPE_SHA1_SIZE; + // Newer versions of libssh2 support SHA256 #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - case 2: - hashType = LIBSSH2_HOSTKEY_HASH_SHA256; - hashSize = HASH_TYPE_SHA256_SIZE; - break; -#endif // LIBSSH2_HOSTKEY_HASH_SHA256 + if (sshfp.digest_type == 2) + { + hashType = LIBSSH2_HOSTKEY_HASH_SHA256; + hashSize = HASH_TYPE_SHA256_SIZE; } +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 // Generate hex encoded sshfp.digest char buffer[256]; diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index b37879752b..4eca481bab 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -332,6 +332,7 @@ testRun(void) " --repo-sftp-private-key-file SFTP private key file\n" " --repo-sftp-private-key-passphrase SFTP private key passphrase\n" " --repo-sftp-public-key-file SFTP public key file\n" + " --repo-sftp-require-trust-ad SFTP require Trust-Ad [default=n]\n" " --repo-storage-ca-file repository storage CA file\n" " --repo-storage-ca-path repository storage CA path\n" " --repo-storage-host repository storage host\n" diff --git a/test/src/module/test/testTest.c b/test/src/module/test/testTest.c index ad9f39cdc6..8b41370b96 100644 --- a/test/src/module/test/testTest.c +++ b/test/src/module/test/testTest.c @@ -323,6 +323,7 @@ testRun(void) " lib_lz4,\n" " lib_pq,\n" " lib_ssh2,\n" + " lib_resolv,\n" " lib_xml,\n" " lib_yaml,\n" " lib_z,\n" @@ -443,6 +444,7 @@ testRun(void) " lib_lz4,\n" " lib_pq,\n" " lib_ssh2,\n" + " lib_resolv,\n" " lib_xml,\n" " lib_yaml,\n" " lib_z,\n" @@ -658,6 +660,7 @@ testRun(void) " lib_lz4,\n" " lib_pq,\n" " lib_ssh2,\n" + " lib_resolv,\n" " lib_xml,\n" " lib_yaml,\n" " lib_z,\n" @@ -831,6 +834,7 @@ testRun(void) " lib_lz4,\n" " lib_pq,\n" " lib_ssh2,\n" + " lib_resolv,\n" " lib_xml,\n" " lib_yaml,\n" " lib_z,\n" From 60d6d2230df70b44b2a81e3e7fc58015cd2256a9 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 31 Oct 2023 08:50:55 -0400 Subject: [PATCH 10/54] Update tests for u20 --- src/storage/sftp/storage.c | 9 +++++-- test/src/module/storage/sftpTest.c | 42 ++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 0bc1a4040a..894c1ae963 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1199,10 +1199,15 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (binaryFingerprint != NULL && memcmp(binaryFingerprint, sshfp.digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) { result = true; - LOG_DETAIL_FMT("sshfp fingerprint match found for sshfp.digest_type '%d' '%s'", sshfp.digest_type, buffer); + LOG_DETAIL_FMT( + "sshfp fingerprint match found for sshfp.digest_type [%d] hashType [%d] '%s'", sshfp.digest_type, hashType, buffer); } else - LOG_DETAIL_FMT("no sshfp fingerprint match found for sshfp.digest_type '%d' '%s'", sshfp.digest_type, buffer); + { + LOG_DETAIL_FMT( + "no sshfp fingerprint match found for sshfp.digest_type [%d] hashType [%d] '%s'", sshfp.digest_type, hashType, + buffer); + } } if (result == false) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index c466b4afd3..8d816ffe7c 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8279,12 +8279,21 @@ testRun(void) objFree(this); TEST_RESULT_LOG( - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#else + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + " 'cf40a796b1e8775e60a77d410db745012e134109'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); harnessLogLevelReset(); #else @@ -8313,8 +8322,16 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = HOSTKEY}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = HOSTKEY}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultNull = true}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "87ac6bede384d2dc6254f396b83ed34856512e64"}, {.function = NULL}, }); @@ -8416,12 +8433,21 @@ testRun(void) objFree(this); TEST_RESULT_LOG( - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '1' 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type '2'" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" - "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type '1' '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#else + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + " 'cf40a796b1e8775e60a77d410db745012e134109'\n" + "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); harnessLogLevelReset(); #else From ed7a8d31d8bdf75b79f02f4d45c90b5f5c1130d1 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 1 Nov 2023 09:18:31 -0400 Subject: [PATCH 11/54] Skip trust_ad check on OS's that do not support/define RES_TRUSTAD Update tests Functional for all but rh7, needs cleanup/commenting updated --- src/storage/sftp/storage.c | 14 +++++++++++-- test/src/module/storage/sftpTest.c | 33 +++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 894c1ae963..3e915f882c 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1086,7 +1086,7 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c /**********************************************************************************************************************************/ static void -storageSftpSetOption(res_state statep, uint64_t option) +storageSftpSetOption(res_state statep, uint32_t option) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VOID, statep); @@ -1094,7 +1094,9 @@ storageSftpSetOption(res_state statep, uint64_t option) FUNCTION_LOG_END(); ASSERT(statep != NULL); +#ifdef RES_TRUSTAD ASSERT(option >= RES_INIT && option <= RES_TRUSTAD); +#endif // RES_TRUSTAD statep->options |= option; @@ -1216,7 +1218,6 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) FUNCTION_LOG_RETURN_VOID(); } -// !!! Do any supported OS's not support this code? /*********************************************************************************************************************************** Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated on the fact that @@ -1235,8 +1236,10 @@ storageSftpTrustAd(StorageSftp *const this, const String *const host) if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); +#ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD // Query the server for SSHFP records unsigned char answer[PACKET_SZ]; @@ -1260,6 +1263,7 @@ storageSftpTrustAd(StorageSftp *const this, const String *const host) ns_msg handle; storageSftpNsInitparse(answer, len, &handle); +#ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; if ((dnsMsgHeader->ad) != 1) @@ -1268,6 +1272,7 @@ storageSftpTrustAd(StorageSftp *const this, const String *const host) THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); } +#endif // RES_TRUSTAD // Check that the fingerprint is in the SSHFP list storageSftpVerifyFingerprint(this->session, handle); @@ -1275,6 +1280,11 @@ storageSftpTrustAd(StorageSftp *const this, const String *const host) // Close the resolver res_nclose(&my_res_state); +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + FUNCTION_LOG_RETURN_VOID(); } diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 8d816ffe7c..3d7a987bda 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1221,6 +1221,7 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd fail"); +#ifdef RES_TRUSTAD hrnLibSsh2ScriptSet((HrnLibSsh2 []) { {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, @@ -1285,6 +1286,9 @@ testRun(void) "P00 WARN: host 'trustad-fail' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); +#else + TEST_LOG("RES_TRUSTAD not supported by OS"); +#endif // RES_TRUSTAD // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd pass"); @@ -1338,8 +1342,6 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); -// jrt remove storageSftpSetOption(&my_res_state, RES_TRUSTAD); - storageTest = NULL; TEST_ASSIGN( @@ -8219,12 +8221,13 @@ testRun(void) if (param.trustAd) { - // storageSftpTrustAd(this, host); if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); +#ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD // Query the server for SSHFP records unsigned char answer[PACKET_SZ]; @@ -8257,6 +8260,7 @@ testRun(void) ns_msg handle; storageSftpNsInitparse(answer, len, &handle); +#ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; if ((dnsMsgHeader->ad) != 1) @@ -8265,6 +8269,7 @@ testRun(void) THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); } +#endif // RES_TRUSTAD // Check that the fingerprint is in the SSHFP list TEST_ERROR_FMT( @@ -8312,7 +8317,8 @@ testRun(void) TimeMSec timeout = 500; const StorageSftpNewParam param = {.trustAd = true}; - // const String *host = STRDEF("muffat.debian.org"); + + // Configure a valid host so that we can successfully initialize the resolver const String *host = STRDEF("www.postgresql.org"); unsigned int port = 22; @@ -8374,12 +8380,13 @@ testRun(void) if (param.trustAd) { - // storageSftpTrustAd(this, host); if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); +#ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD // Query the server for SSHFP records unsigned char answer[PACKET_SZ]; @@ -8403,7 +8410,10 @@ testRun(void) // Overwrite the sshfp response with a known defined response for testing Buffer *sshfp = storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); + + // Verify we got the expected size TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + memset(answer, 0, sizeof(answer)); memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); @@ -8412,6 +8422,7 @@ testRun(void) ns_msg handle; storageSftpNsInitparse(answer, len, &handle); +#ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; if ((dnsMsgHeader->ad) != 1) @@ -8420,12 +8431,18 @@ testRun(void) THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); } +#endif // RES_TRUSTAD // Check that the fingerprint is in the SSHFP list TEST_RESULT_VOID(storageSftpVerifyFingerprint(this->session, handle), "Host key found in SSHFP record"); // Close the resolver res_nclose(&my_res_state); + +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD } } OBJ_NEW_END(); @@ -8446,8 +8463,14 @@ testRun(void) "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef RES_TRUSTAD "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#else + "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'\n" + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'"); +#endif // RES_TRUSTAD harnessLogLevelReset(); #else From fa888c40128ff16eca9b3579ebb6cb7b3b045d98 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 3 Nov 2023 12:17:35 -0400 Subject: [PATCH 12/54] Refactor, change references from trust ad to sshfp --- src/build/config/config.yaml | 2 +- src/build/help/help.xml | 6 +- src/config/config.auto.h | 2 +- src/config/parse.auto.c.inc | 172 ++++++++++++++--------------- src/storage/sftp/helper.c | 2 +- src/storage/sftp/storage.c | 8 +- src/storage/sftp/storage.h | 2 +- test/src/module/command/helpTest.c | 2 +- test/src/module/storage/sftpTest.c | 34 +++--- 9 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index 8ea1fa9b4c..8a3ac1932d 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2460,7 +2460,7 @@ option: command: repo-type depend: repo-sftp-host - repo-sftp-require-trust-ad: + repo-sftp-require-sshfp: section: global group: repo type: boolean diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 5d26c3300b..48f6d35931 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1059,11 +1059,11 @@ path
- - SFTP require Trust-Ad. + + SFTP require SSHFP. -

!!! TBD - Perform a minimal host verification via DNSSEC. This verification assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. It queries the DNS server for the host and SSHFP records with RES_TRUSTAD (ad bit) set. If the response ad bit is not set, the host is not trusted. If the ad is is set a check will be made for a matching key in the SSHFP records.

+

Perform a minimal host verification via DNSSEC SSHFP records. This verification assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. If no match is found for the host fingerprint in the SSHFP records an error is thrown. If the OS supports RES_TRUSTAD, queries to the DNS server for SSHFP records will have the RES_TRUSTAD (ad bit) set and if the response ad bit is unset an error will be thrown.

n diff --git a/src/config/config.auto.h b/src/config/config.auto.h index 41a2aa0916..8834c14ee7 100644 --- a/src/config/config.auto.h +++ b/src/config/config.auto.h @@ -528,7 +528,7 @@ typedef enum cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, cfgOptRepoSftpPublicKeyFile, - cfgOptRepoSftpRequireTrustAd, + cfgOptRepoSftpRequireSshfp, cfgOptRepoStorageCaFile, cfgOptRepoStorageCaPath, cfgOptRepoStorageHost, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 51a795ed75..eeac4d2ddc 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8733,91 +8733,91 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-public-key-file ), // opt/repo-sftp-public-key-file // ----------------------------------------------------------------------------------------------------------------------------- - PARSE_RULE_OPTION // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_NAME("repo-sftp-require-trust-ad"), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTIONAL // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-require-trust-ad - PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - // opt/repo-sftp-require-trust-ad - PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-require-trust-ad - ( // opt/repo-sftp-require-trust-ad - PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad - ), // opt/repo-sftp-require-trust-ad + PARSE_RULE_OPTION // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_NAME("repo-sftp-require-sshfp"), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTIONAL // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-require-sshfp + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-require-sshfp + ( // opt/repo-sftp-require-sshfp + PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp + ), // opt/repo-sftp-require-sshfp // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-storage-ca-file ( // opt/repo-storage-ca-file @@ -11074,7 +11074,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order cfgOptRepoSftpPublicKeyFile, // opt-resolve-order - cfgOptRepoSftpRequireTrustAd, // opt-resolve-order + cfgOptRepoSftpRequireSshfp, // opt-resolve-order cfgOptRepoStorageCaFile, // opt-resolve-order cfgOptRepoStorageCaPath, // opt-resolve-order cfgOptRepoStorageHost, // opt-resolve-order diff --git a/src/storage/sftp/helper.c b/src/storage/sftp/helper.c index 5723e07324..45a55ec1ea 100644 --- a/src/storage/sftp/helper.c +++ b/src/storage/sftp/helper.c @@ -40,7 +40,7 @@ storageSftpHelper(const unsigned int repoIdx, const bool write, StoragePathExpre .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), .knownHosts = knownHosts); + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 3e915f882c..9dcf90ad73 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1224,7 +1224,7 @@ hostkey is returned in the SSHFP list. This is not a complete check but it is be the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is secure. ***********************************************************************************************************************************/ static void -storageSftpTrustAd(StorageSftp *const this, const String *const host) +storageSftpSshfp(StorageSftp *const this, const String *const host) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(STORAGE_SFTP, this); @@ -1322,7 +1322,7 @@ storageSftpNew( FUNCTION_LOG_PARAM(STRING_LIST, param.knownHosts); FUNCTION_LOG_PARAM(MODE, param.modeFile); FUNCTION_LOG_PARAM(MODE, param.modePath); - FUNCTION_LOG_PARAM(BOOL, param.trustAd); + FUNCTION_LOG_PARAM(BOOL, param.sshfp); FUNCTION_LOG_PARAM(BOOL, param.write); FUNCTION_LOG_PARAM(FUNCTIONP, param.pathExpressionFunction); FUNCTION_LOG_END(); @@ -1540,8 +1540,8 @@ storageSftpNew( libssh2_knownhost_free(knownHostsList); } - if (param.trustAd) - storageSftpTrustAd(this, host); + if (param.sshfp) + storageSftpSshfp(this, host); // Perform public key authorization, expand leading tilde key file paths if needed String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); diff --git a/src/storage/sftp/storage.h b/src/storage/sftp/storage.h index abcc388f85..2cda843e5e 100644 --- a/src/storage/sftp/storage.h +++ b/src/storage/sftp/storage.h @@ -36,7 +36,7 @@ typedef struct StorageSftpNewParam StringId hostKeyCheckType; const String *hostFingerprint; const StringList *knownHosts; - const bool trustAd; + const bool sshfp; } StorageSftpNewParam; #define storageSftpNewP(path, host, port, user, timeout, keyPriv, hostKeyHashType, ...) \ diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index 4eca481bab..06cc2aa234 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -332,7 +332,7 @@ testRun(void) " --repo-sftp-private-key-file SFTP private key file\n" " --repo-sftp-private-key-passphrase SFTP private key passphrase\n" " --repo-sftp-public-key-file SFTP public key file\n" - " --repo-sftp-require-trust-ad SFTP require Trust-Ad [default=n]\n" + " --repo-sftp-require-sshfp SFTP require SSHFP [default=n]\n" " --repo-storage-ca-file repository storage CA file\n" " --repo-storage-ca-path repository storage CA path\n" " --repo-storage-host repository storage host\n" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 3d7a987bda..55f4dd42d6 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1134,7 +1134,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1145,7 +1145,7 @@ testRun(void) memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd, res_nquery fail, shimmed"); + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, sshfp, res_nquery fail, shimmed"); // Install shim for SFTP libresolv functions hrnSftpResolvShimInstall(); @@ -1192,7 +1192,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); @@ -1206,7 +1206,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, "res_nquery error [4] No address associated with name 'no-data'"); @@ -1219,7 +1219,7 @@ testRun(void) memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd fail"); + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, sshfp fail"); #ifdef RES_TRUSTAD hrnLibSsh2ScriptSet((HrnLibSsh2 []) @@ -1264,7 +1264,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ERROR( @@ -1277,7 +1277,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); @@ -1291,7 +1291,7 @@ testRun(void) #endif // RES_TRUSTAD // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("sftp session init success - add host to known_hosts file RSA, trustAd pass"); + TEST_TITLE("sftp session init success - add host to known_hosts file RSA, sshfp pass"); hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -1339,7 +1339,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; @@ -1355,7 +1355,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); @@ -1414,7 +1414,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ERROR( @@ -1427,7 +1427,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .trustAd = cfgOptionIdxBool(cfgOptRepoSftpRequireTrustAd, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, "unable to initialize resolver"); @@ -1487,7 +1487,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireTrustAd, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; @@ -8158,7 +8158,7 @@ testRun(void) harnessLogLevelSet(logLevelDetail); TimeMSec timeout = 500; - const StorageSftpNewParam param = {.trustAd = true}; + const StorageSftpNewParam param = {.sshfp = true}; // const String *host = STRDEF("muffat.debian.org"); const String *host = STRDEF("www.postgresql.org"); unsigned int port = 22; @@ -8219,7 +8219,7 @@ testRun(void) if (rc != 0) THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); - if (param.trustAd) + if (param.sshfp) { if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); @@ -8316,7 +8316,7 @@ testRun(void) harnessLogLevelSet(logLevelDetail); TimeMSec timeout = 500; - const StorageSftpNewParam param = {.trustAd = true}; + const StorageSftpNewParam param = {.sshfp = true}; // Configure a valid host so that we can successfully initialize the resolver const String *host = STRDEF("www.postgresql.org"); @@ -8378,7 +8378,7 @@ testRun(void) if (rc != 0) THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); - if (param.trustAd) + if (param.sshfp) { if (storageSftpResNinit(&my_res_state) != 0) THROW_FMT(ServiceError, "unable to initialize resolver"); From 8a1ab499a0ce907d8b7653a0b6f70809f2343a34 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 6 Nov 2023 08:46:52 -0500 Subject: [PATCH 13/54] Reorder some code, update tests accordingly Cleanup, add comments --- src/storage/sftp/storage.c | 39 +++++++++++------------ test/src/common/harnessSftpResolv.c | 13 ++++---- test/src/module/storage/sftpTest.c | 49 ++++++++++++++++++----------- 3 files changed, 57 insertions(+), 44 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 9dcf90ad73..b7a37b2fe9 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -19,8 +19,6 @@ SFTP Storage #include -// jrt !!! remove netdb.h, et al if not needed after testing/dev -// !!! jrt is this viable/acceptable #ifndef __USE_MISC #define __USE_MISC 1 #endif @@ -54,7 +52,6 @@ struct StorageSftp TimeMSec timeout; // Session timeout }; -// jrt !!! should this be in StorageSftp above? // Initialize the resolver struct __res_state my_res_state = {0}; @@ -1085,6 +1082,7 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c } /**********************************************************************************************************************************/ +#ifdef RES_TRUSTAD static void storageSftpSetOption(res_state statep, uint32_t option) { @@ -1094,14 +1092,13 @@ storageSftpSetOption(res_state statep, uint32_t option) FUNCTION_LOG_END(); ASSERT(statep != NULL); -#ifdef RES_TRUSTAD ASSERT(option >= RES_INIT && option <= RES_TRUSTAD); -#endif // RES_TRUSTAD statep->options |= option; FUNCTION_LOG_RETURN_VOID(); } +#endif // RES_TRUSTAD /**********************************************************************************************************************************/ static int @@ -1161,15 +1158,16 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) bool result = false; + // Check the sshfp resource records for a fingerprint match for (int rrnum = 0; rrnum < ns_msg_count(handle, ns_s_an); rrnum++) { ns_rr rr; + // Parse the resource record ns_parserr(&handle, ns_s_an, rrnum, &rr); typedef struct rdata_sshfp { - unsigned algorithm : 8; unsigned digest_type : 8; unsigned char *digest; } rdata_sshfp_t; @@ -1219,9 +1217,10 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) } /*********************************************************************************************************************************** -Perform minimal DNS verification on the host. Queries with RES_TRUSTAD and verifies that response is RES_TRUSTAD. Checks that the -hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated on the fact that -the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is secure. +Perform minimal DNS verification on the host. Queries with RES_TRUSTAD if supported and verifies that response is RES_TRUSTAD. +Checks that the hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated +on the fact that the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is +secure. ***********************************************************************************************************************************/ static void storageSftpSshfp(StorageSftp *const this, const String *const host) @@ -1247,8 +1246,8 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); // Check for errors. - // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we think that's - // better. + // Error msg is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we think + // that's better. if (len < 0) { // Closing before throwing the error does not seem to mess up the hstrerror() call @@ -1259,10 +1258,6 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } - // Initialize parsing the response - ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); - #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; @@ -1274,17 +1269,21 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) } #endif // RES_TRUSTAD +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + ns_msg handle; + storageSftpNsInitparse(answer, len, &handle); + // Check that the fingerprint is in the SSHFP list storageSftpVerifyFingerprint(this->session, handle); // Close the resolver res_nclose(&my_res_state); -#ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); -#endif // RES_TRUSTAD - FUNCTION_LOG_RETURN_VOID(); } diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index c181a3c9de..cad4455a66 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -7,12 +7,6 @@ Harness for SFTP libresolv Testing #include "common/harnessDebug.h" #include "common/harnessSftpResolv.h" -#include -#ifndef __USE_MISC -#define __USE_MISC 1 -#endif -#include - /*********************************************************************************************************************************** Include shimmed C modules ***********************************************************************************************************************************/ @@ -70,6 +64,7 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u int result; + // Avoid compiler complaining of unused params (void)statep; (void)dname; (void)class; @@ -79,20 +74,24 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u if (hrnSftpResolvStatic.localShimSftpResolv) { + // Overlay HEADER onto the answer buffer HEADER *header = (HEADER *)answer; if (strcmp(dname, "trustad-fail") == 0) { + // Unset the ad flag to indicate that the answer is not authenticated result = 0; header->ad = 0; } else if (strcmp(dname, "trustad-pass") == 0 || strcmp(dname, "localhost") == 0) { + // Set the ad flag to indicate that the answer is authenticated result = 1; header->ad = 1; } else { + // Return an error result = -1; statep->res_h_errno = NO_DATA; header->ad = 0; @@ -121,6 +120,7 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) if (hrnSftpResolvStatic.localShimSftpResolv) { + // Use the incoming len from the test call to determine the result switch (len) { case 0: @@ -153,6 +153,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (hrnSftpResolvStatic.localShimSftpResolv) { + // Do nothing } else storageSftpVerifyFingerprint_SHIMMED(session, handle); diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 55f4dd42d6..88fabf82bd 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1399,8 +1399,8 @@ testRun(void) {.function = NULL} }); - // Use the RES_IGNTC option indicate when to return a failure from res_ninit - TEST_RESULT_VOID(storageSftpSetOption(&my_res_state, RES_IGNTC), "set resolv option IGNTC"); + // Use the RES_IGNTC option indicate when to return a failure from res_ninit when shimmed + my_res_state.options |= RES_IGNTC; argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptStanza, "test"); @@ -8159,7 +8159,8 @@ testRun(void) TimeMSec timeout = 500; const StorageSftpNewParam param = {.sshfp = true}; - // const String *host = STRDEF("muffat.debian.org"); + + // Configure a valid host so that we can successfully initialize the resolver const String *host = STRDEF("www.postgresql.org"); unsigned int port = 22; @@ -8183,6 +8184,7 @@ testRun(void) {.function = NULL}, }); + // Step through the sftp storage startup process OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) { *this = (StorageSftp) @@ -8256,10 +8258,6 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); - // Initialize parsing the response - ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); - #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; @@ -8271,6 +8269,15 @@ testRun(void) } #endif // RES_TRUSTAD +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + ns_msg handle; + storageSftpNsInitparse(answer, len, &handle); + // Check that the fingerprint is in the SSHFP list TEST_ERROR_FMT( storageSftpVerifyFingerprint(this->session, handle), ServiceError, "Host key not found in SSHFP record"); @@ -8284,6 +8291,9 @@ testRun(void) objFree(this); TEST_RESULT_LOG( +#ifndef RES_TRUSTAD + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" +#endif // RES_TRUSTAD "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 @@ -8307,7 +8317,7 @@ testRun(void) } // ***************************************************************************************************************************** - if (testBegin("storageSftpVerifyFingerprint() localhost")) + if (testBegin("storageSftpVerifyFingerprint()")) { #ifdef HAVE_LIBSSH2 // ------------------------------------------------------------------------------------------------------------------------- @@ -8418,10 +8428,6 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); - // Initialize parsing the response - ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); - #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag HEADER *dnsMsgHeader = (HEADER *)answer; @@ -8433,16 +8439,21 @@ testRun(void) } #endif // RES_TRUSTAD +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + ns_msg handle; + storageSftpNsInitparse(answer, len, &handle); + // Check that the fingerprint is in the SSHFP list TEST_RESULT_VOID(storageSftpVerifyFingerprint(this->session, handle), "Host key found in SSHFP record"); // Close the resolver res_nclose(&my_res_state); -#ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); -#endif // RES_TRUSTAD } } OBJ_NEW_END(); @@ -8450,6 +8461,9 @@ testRun(void) objFree(this); TEST_RESULT_LOG( +#ifndef RES_TRUSTAD + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" +#endif // RES_TRUSTAD "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 @@ -8468,8 +8482,7 @@ testRun(void) " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #else "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" - " '87ac6bede384d2dc6254f396b83ed34856512e64'\n" - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'"); + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #endif // RES_TRUSTAD harnessLogLevelReset(); From 19d2ecddfb6b597276be097b8799e038b74852d1 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 6 Nov 2023 10:51:09 -0500 Subject: [PATCH 14/54] Remove extraneous blank lines --- src/storage/sftp/storage.c | 1 + test/src/module/storage/sftpTest.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index b7a37b2fe9..42c4f7fc71 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1098,6 +1098,7 @@ storageSftpSetOption(res_state statep, uint32_t option) FUNCTION_LOG_RETURN_VOID(); } + #endif // RES_TRUSTAD /**********************************************************************************************************************************/ diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 88fabf82bd..67aed12237 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8453,7 +8453,6 @@ testRun(void) // Close the resolver res_nclose(&my_res_state); - } } OBJ_NEW_END(); From e2f6f35a9c387b1c9b1c58ebddf808616e74f868 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 6 Nov 2023 10:52:46 -0500 Subject: [PATCH 15/54] Add known dnssec trust_ad SSHFP record --- test/data/muffat.debian.org.sshfp | Bin 0 -> 195 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/data/muffat.debian.org.sshfp diff --git a/test/data/muffat.debian.org.sshfp b/test/data/muffat.debian.org.sshfp new file mode 100644 index 0000000000000000000000000000000000000000..789145418fea57c5bf5ddeccb2e8e479ea0477a8 GIT binary patch literal 195 zcmcCyZd|~?$iTt?1Z=sbX=#ZiY$>TpnTdJK`9m*dCj0H< UmP>b%LOxI1VRzXhEKn~601N~`CIA2c literal 0 HcmV?d00001 From 2be433bab89c9f1c8d1bc757adbd906f772a6ef4 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 14 Nov 2023 01:30:10 -0500 Subject: [PATCH 16/54] Refactor to eliminate a valgrind error that was occurring on d10 and f38 --- test/src/common/harnessLibSsh2.c | 14 +------------- test/src/common/harnessLibSsh2.h | 1 - test/src/module/storage/sftpTest.c | 6 +++++- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index f193569718..eabfd40884 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -430,19 +430,7 @@ libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type) } MEM_CONTEXT_TEMP_END(); - char *result; - - // For this resultZ, return it's binary representation to get a succssful match - if (hrnLibSsh2->resultZ != NULL && strcmp(hrnLibSsh2->resultZ, "87ac6bede384d2dc6254f396b83ed34856512e64") == 0) - { - decodeToBin(encodingHex, hrnLibSsh2->resultZ, hrnLibSsh2->fingerPrint); - - result = (char *)hrnLibSsh2->fingerPrint; - } - else - result = (char *)hrnLibSsh2->resultZ; - - return hrnLibSsh2->resultNull ? NULL : (const char *)result; + return hrnLibSsh2->resultNull ? NULL : (const char *)hrnLibSsh2->resultZ; } /*********************************************************************************************************************************** diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index a032bcb4f0..c17377eae8 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -127,7 +127,6 @@ typedef struct HrnLibSsh2 size_t len; // libssh2_session_hostkey len int type; // libssh2_session_hostkey type char *errMsg; // libssh2_session_last_error error msg - unsigned char fingerPrint[1024]; // binary finger print } HrnLibSsh2; /*********************************************************************************************************************************** diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 67aed12237..a0c7a02b31 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8332,6 +8332,10 @@ testRun(void) const String *host = STRDEF("www.postgresql.org"); unsigned int port = 22; + // Create binary representation of the host key that will generate a successful match + unsigned char fingperprint[1024]; + decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingperprint); + hrnLibSsh2ScriptSet((HrnLibSsh2 []) { {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, @@ -8348,7 +8352,7 @@ testRun(void) #else {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "87ac6bede384d2dc6254f396b83ed34856512e64"}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingperprint}, {.function = NULL}, }); From c00e2d25895571d39da581975d26b245c0ea9cd1 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 14 Nov 2023 09:10:37 -0500 Subject: [PATCH 17/54] Attempt to remedy CI meson issue --- meson.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d1e9280633..467c5276f8 100644 --- a/meson.build +++ b/meson.build @@ -172,7 +172,12 @@ lib_ssh2 = dependency('libssh2', required: false) if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') - lib_resolv = cc.find_library('resolv') +endif + +# Find libresolv library +lib_resolv = cc.find_library('resolv') +if lib_ssh2.found() and not lib_resolv.found() + error('libssh2 requires libresolv') endif # Find optional zstd library From 04428df1b278e6f3dc1316a88f3feb71e0bc376b Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 20 Nov 2023 11:11:30 -0500 Subject: [PATCH 18/54] Determined FTM definitions for rh7 to compile with libresolv --- meson.build | 2 ++ src/build/configure.ac | 2 ++ src/configure | 6 +++++- src/storage/sftp/storage.c | 12 ++++-------- test/src/module/storage/sftpTest.c | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 467c5276f8..7f939ce244 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,8 @@ cc = meson.get_compiler('c') # OS-specific settings #################################################################################################################################### if host_machine.system() == 'linux' + add_global_arguments('-D_DEFAULT_SOURCE', language : 'c') + add_global_arguments('-D_BSD_SOURCE', language : 'c') add_global_arguments('-D_POSIX_C_SOURCE=200809L', language : 'c') elif host_machine.system() == 'darwin' add_global_arguments('-D_DARWIN_C_SOURCE', language : 'c') diff --git a/src/build/configure.ac b/src/build/configure.ac index 514fef0776..17dc9f06af 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -21,6 +21,8 @@ case $host_os in ;; linux*) + AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_DEFAULT_SOURCE") + AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_BSD_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_POSIX_C_SOURCE=200809L") ;; esac diff --git a/src/configure b/src/configure index b14aa9c680..532d4e73be 100755 --- a/src/configure +++ b/src/configure @@ -3415,6 +3415,10 @@ case $host_os in ;; linux*) + CPPFLAGS="${CPPFLAGS} -D_DEFAULT_SOURCE" + + CPPFLAGS="${CPPFLAGS} -D_BSD_SOURCE" + CPPFLAGS="${CPPFLAGS} -D_POSIX_C_SOURCE=200809L" ;; @@ -5810,4 +5814,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 75d6effef8179480c54966cbbfb9213f70e45c1e +# Generated from src/build/configure.ac sha1 726febc0d6c2b8bd149996fbc38be528a622c65b diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 42c4f7fc71..f15c0e2fd3 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -5,6 +5,9 @@ SFTP Storage #ifdef HAVE_LIBSSH2 +#include +#include + #include "common/crypto/hash.h" #include "common/debug.h" #include "common/io/fd.h" @@ -17,13 +20,6 @@ SFTP Storage #include "storage/sftp/storage.intern.h" #include "storage/sftp/write.h" -#include - -#ifndef __USE_MISC -#define __USE_MISC 1 -#endif -#include - /*********************************************************************************************************************************** Define PATH_MAX if it is not defined ***********************************************************************************************************************************/ @@ -1247,7 +1243,7 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); // Check for errors. - // Error msg is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we think + // Error msg is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we think // that's better. if (len < 0) { diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index a0c7a02b31..8671620c6d 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8237,7 +8237,7 @@ testRun(void) int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); // Check for errors. - // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we + // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we // think that's better. if (len < 0) { @@ -8408,7 +8408,7 @@ testRun(void) int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); // Check for errors. - // This is dependent on keeping the __USE_MISC for netdb.h. We can drop it and rewrite to a generic error if we + // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we // think that's better. if (len < 0) { From 0ea785eeeea124321ed0899b884595c0d5cb76dd Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 20 Nov 2023 13:11:02 -0500 Subject: [PATCH 19/54] Attempt to fix ci doc build --- test/src/common/harnessSftpResolv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index cad4455a66..08a3b6c916 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -3,6 +3,8 @@ Harness for SFTP libresolv Testing ***********************************************************************************************************************************/ #include "build.auto.h" +#include + #include "common/harnessConfig.h" #include "common/harnessDebug.h" #include "common/harnessSftpResolv.h" @@ -35,7 +37,7 @@ storageSftpResNinit(res_state statep) if (hrnSftpResolvStatic.localShimSftpResolv) { // Use the RES_IGNTC option indicate when to return a failure - if ((my_res_state.options & RES_IGNTC) == RES_IGNTC) + if ((statep->options & RES_IGNTC) == RES_IGNTC) result = -1; else result = 0; From 6375f37b18c2fef590b8f41b42bd4c8940d9fee6 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 27 Nov 2023 11:58:04 -0500 Subject: [PATCH 20/54] Update help --- src/build/help/help.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 48f6d35931..bfcbf67ddc 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1063,7 +1063,7 @@ SFTP require SSHFP. -

Perform a minimal host verification via DNSSEC SSHFP records. This verification assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. If no match is found for the host fingerprint in the SSHFP records an error is thrown. If the OS supports RES_TRUSTAD, queries to the DNS server for SSHFP records will have the RES_TRUSTAD (ad bit) set and if the response ad bit is unset an error will be thrown.

+

Perform a fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. If no match is found for the host fingerprint in the SSHFP records an error is thrown. If the OS supports RES_TRUSTAD, the SSHFP query will have the RES_TRUSTAD (ad) flag set and if the response ad flag is unset an error will be thrown.

n From 2e0e2dc48af62f9abd6632d0a64489141824fb1a Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Sun, 3 Dec 2023 23:00:01 -0500 Subject: [PATCH 21/54] Fix CI build failure on doc/s390 --- src/meson.build | 2 +- src/storage/sftp/storage.c | 40 ++++++++++++++--------------- test/src/common/harnessSftpResolv.c | 4 +++ test/src/common/harnessSftpResolv.h | 2 ++ 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/meson.build b/src/meson.build index 3f8194eaa6..21d2e8261b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -259,7 +259,7 @@ src_pgbackrest = [ 'storage/s3/write.c', 'storage/sftp/helper.c', 'storage/sftp/read.c', - 'storage/sftp/storage.c', + 'storage/sftp/storage.c', 'storage/sftp/write.c', 'main.c', ] diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index f15c0e2fd3..12443972e7 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1077,26 +1077,6 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c FUNCTION_LOG_RETURN(BOOL, result); } -/**********************************************************************************************************************************/ -#ifdef RES_TRUSTAD -static void -storageSftpSetOption(res_state statep, uint32_t option) -{ - FUNCTION_LOG_BEGIN(logLevelTrace); - FUNCTION_LOG_PARAM(VOID, statep); - FUNCTION_LOG_PARAM(UINT64, option); - FUNCTION_LOG_END(); - - ASSERT(statep != NULL); - ASSERT(option >= RES_INIT && option <= RES_TRUSTAD); - - statep->options |= option; - - FUNCTION_LOG_RETURN_VOID(); -} - -#endif // RES_TRUSTAD - /**********************************************************************************************************************************/ static int storageSftpResNinit(res_state statep) @@ -1144,6 +1124,26 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) FUNCTION_LOG_RETURN(INT, ns_initparse(answer, len, handle)); } +/**********************************************************************************************************************************/ +#ifdef RES_TRUSTAD +static void +storageSftpSetOption(res_state statep, uint32_t option) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(VOID, statep); + FUNCTION_LOG_PARAM(UINT64, option); + FUNCTION_LOG_END(); + + ASSERT(statep != NULL); + ASSERT(option >= RES_INIT && option <= RES_TRUSTAD); + + statep->options |= option; + + FUNCTION_LOG_RETURN_VOID(); +} + +#endif // RES_TRUSTAD + /**********************************************************************************************************************************/ static void storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 08a3b6c916..4d49f65934 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -3,6 +3,8 @@ Harness for SFTP libresolv Testing ***********************************************************************************************************************************/ #include "build.auto.h" +#ifdef HAVE_LIBSSH2 + #include #include "common/harnessConfig.h" @@ -182,3 +184,5 @@ hrnSftpResolvShimUninstall(void) FUNCTION_HARNESS_RETURN_VOID(); } + +#endif // HAVE_LIBSSH2 diff --git a/test/src/common/harnessSftpResolv.h b/test/src/common/harnessSftpResolv.h index 01001fc98e..01b3a21674 100644 --- a/test/src/common/harnessSftpResolv.h +++ b/test/src/common/harnessSftpResolv.h @@ -5,6 +5,8 @@ Harness for SFTP libresolv Testing /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ +#ifdef HAVE_LIBSSH2 // Install/uninstall shim void hrnSftpResolvShimInstall(void); void hrnSftpResolvShimUninstall(void); +#endif // HAVE_LIBSSH2 From be5be435b9a01c0345c681ca299e50777643ecca Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 10:42:30 -0500 Subject: [PATCH 22/54] Note that DEFAULT_SOURCE AND BSD_SOURCE can be removed when support for RHEL7 is dropped Format added line in meson.build to match surrounding lines Remove unneeded struct, update log messages Update tests Remove unneeded header resolv.h inclusion Update comments Return inadvertently removed listings in test/code-count/file-type.yaml --- meson.build | 2 ++ src/build/configure.ac | 2 ++ src/configure | 3 ++- src/meson.build | 2 +- src/storage/sftp/storage.c | 38 ++++++++++++----------------- test/code-count/file-type.yaml | 8 ++++++ test/src/common/harnessLibSsh2.c | 1 - test/src/common/harnessSftpResolv.c | 4 +-- test/src/module/storage/sftpTest.c | 26 ++++++++++---------- 9 files changed, 45 insertions(+), 41 deletions(-) diff --git a/meson.build b/meson.build index 7f939ce244..5daae7afd0 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,8 @@ cc = meson.get_compiler('c') # OS-specific settings #################################################################################################################################### if host_machine.system() == 'linux' + # BSD_SOURCE can be removed when support for RHEL7 is dropped, + # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message add_global_arguments('-D_DEFAULT_SOURCE', language : 'c') add_global_arguments('-D_BSD_SOURCE', language : 'c') add_global_arguments('-D_POSIX_C_SOURCE=200809L', language : 'c') diff --git a/src/build/configure.ac b/src/build/configure.ac index 17dc9f06af..6c5d561ba7 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -21,6 +21,8 @@ case $host_os in ;; linux*) + # BSD_SOURCE can be removed when support for RHEL7 is dropped + # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_DEFAULT_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_BSD_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_POSIX_C_SOURCE=200809L") diff --git a/src/configure b/src/configure index 532d4e73be..91ba4d1cf4 100755 --- a/src/configure +++ b/src/configure @@ -3415,6 +3415,7 @@ case $host_os in ;; linux*) + # DEFAULT_SOURCE AND BSD_SOURCE can be removed when support for RHEL7 is dropped CPPFLAGS="${CPPFLAGS} -D_DEFAULT_SOURCE" CPPFLAGS="${CPPFLAGS} -D_BSD_SOURCE" @@ -5814,4 +5815,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 726febc0d6c2b8bd149996fbc38be528a622c65b +# Generated from src/build/configure.ac sha1 aab922c9c49b9c602e583d6046182a006f37058e diff --git a/src/meson.build b/src/meson.build index 21d2e8261b..3f8194eaa6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -259,7 +259,7 @@ src_pgbackrest = [ 'storage/s3/write.c', 'storage/sftp/helper.c', 'storage/sftp/read.c', - 'storage/sftp/storage.c', + 'storage/sftp/storage.c', 'storage/sftp/write.c', 'main.c', ] diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 12443972e7..8fe2781d28 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1092,7 +1092,7 @@ storageSftpResNinit(res_state statep) /**********************************************************************************************************************************/ static int -storageSftpResNquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) +storageSftpResNquery(res_state statep, const char *dname, const int class, const int type, unsigned char *answer, const int anslen) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VOID, statep); @@ -1127,7 +1127,7 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) /**********************************************************************************************************************************/ #ifdef RES_TRUSTAD static void -storageSftpSetOption(res_state statep, uint32_t option) +storageSftpSetOption(res_state statep, const uint32_t option) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VOID, statep); @@ -1163,47 +1163,39 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) // Parse the resource record ns_parserr(&handle, ns_s_an, rrnum, &rr); - typedef struct rdata_sshfp - { - unsigned digest_type : 8; - unsigned char *digest; - } rdata_sshfp_t; - - rdata_sshfp_t sshfp; - - sshfp.digest_type = *((unsigned char *) ns_rr_rdata(rr) + 1); - sshfp.digest = (unsigned char *) ns_rr_rdata(rr) + 2; + const uint8_t digest_type = *((unsigned char *) ns_rr_rdata(rr) + 1); + const unsigned char *digest = (unsigned char *) ns_rr_rdata(rr) + 2; - // Only SHA1 and SHA256 are currently defined as valid SSHFP RR types for fingerprint types + // Only SHA1 and SHA256 are currently defined as valid SSHFP RR types for fingerprint types, default to sha1 int hashType = LIBSSH2_HOSTKEY_HASH_SHA1; size_t hashSize = HASH_TYPE_SHA1_SIZE; - // Newer versions of libssh2 support SHA256 + // Newer versions of libssh2 support SHA256, check for it #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - if (sshfp.digest_type == 2) + if (digest_type == 2) { hashType = LIBSSH2_HOSTKEY_HASH_SHA256; hashSize = HASH_TYPE_SHA256_SIZE; } #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - // Generate hex encoded sshfp.digest + // Generate hex encoded sshfp digest char buffer[256]; - encodeToStr(encodingHex, sshfp.digest, hashSize, buffer); + encodeToStr(encodingHex, digest, hashSize, buffer); + // Compare the fingerprints const char *binaryFingerprint = libssh2_hostkey_hash(session, hashType); - if (binaryFingerprint != NULL && memcmp(binaryFingerprint, sshfp.digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) + if (binaryFingerprint != NULL && memcmp(binaryFingerprint, digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) { result = true; LOG_DETAIL_FMT( - "sshfp fingerprint match found for sshfp.digest_type [%d] hashType [%d] '%s'", sshfp.digest_type, hashType, buffer); + "sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } else { LOG_DETAIL_FMT( - "no sshfp fingerprint match found for sshfp.digest_type [%d] hashType [%d] '%s'", sshfp.digest_type, hashType, - buffer); + "no sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } } @@ -1267,8 +1259,7 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -1536,6 +1527,7 @@ storageSftpNew( libssh2_knownhost_free(knownHostsList); } + // Check for matching SSHFP fingerprint if requested if (param.sshfp) storageSftpSshfp(this, host); diff --git a/test/code-count/file-type.yaml b/test/code-count/file-type.yaml index 67749e9370..5ce828b694 100644 --- a/test/code-count/file-type.yaml +++ b/test/code-count/file-type.yaml @@ -2747,6 +2747,14 @@ test/src/common/harnessInfo.h: class: test/harness type: c/h +test/src/common/harnessLibSsh2.c: + class: test/harness + type: c + +test/src/common/harnessLibSsh2.h: + class: test/harness + type: c/h + test/src/common/harnessLock.c: class: test/harness type: c diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index eabfd40884..6436a0ecb1 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -5,7 +5,6 @@ libssh2 Test Harness #ifdef HAVE_LIBSSH2 -#include #include #include diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 4d49f65934..136ba2bea2 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -38,7 +38,7 @@ storageSftpResNinit(res_state statep) if (hrnSftpResolvStatic.localShimSftpResolv) { - // Use the RES_IGNTC option indicate when to return a failure + // Use the RES_IGNTC option to indicate when to return a failure if ((statep->options & RES_IGNTC) == RES_IGNTC) result = -1; else @@ -157,7 +157,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (hrnSftpResolvStatic.localShimSftpResolv) { - // Do nothing + // Do nothing, storageSftpVerifyFingerprint has its own tests in sftpTest.c } else storageSftpVerifyFingerprint_SHIMMED(session, handle); diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 8671620c6d..16d45ad6f6 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8294,20 +8294,20 @@ testRun(void) #ifndef RES_TRUSTAD "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" #endif // RES_TRUSTAD - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); harnessLogLevelReset(); @@ -8467,24 +8467,24 @@ testRun(void) #ifndef RES_TRUSTAD "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" #endif // RES_TRUSTAD - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp.digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 #ifdef RES_TRUSTAD - "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #else - "P00 DETAIL: sshfp fingerprint match found for sshfp.digest_type [1] hashType [2]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #endif // RES_TRUSTAD From 4d3fe8693fedef789eb7bf604be57191cd0d1045 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 11:00:03 -0500 Subject: [PATCH 23/54] Attempt to fix configure issue --- src/build/configure.ac | 4 ++-- src/configure | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index 6c5d561ba7..3fd07f1c7b 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -21,8 +21,8 @@ case $host_os in ;; linux*) - # BSD_SOURCE can be removed when support for RHEL7 is dropped - # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message +# BSD_SOURCE can be removed when support for RHEL7 is dropped +# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_DEFAULT_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_BSD_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_POSIX_C_SOURCE=200809L") diff --git a/src/configure b/src/configure index 91ba4d1cf4..46f7af7e50 100755 --- a/src/configure +++ b/src/configure @@ -3415,7 +3415,8 @@ case $host_os in ;; linux*) - # DEFAULT_SOURCE AND BSD_SOURCE can be removed when support for RHEL7 is dropped + # BSD_SOURCE can be removed when support for RHEL7 is dropped + # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message CPPFLAGS="${CPPFLAGS} -D_DEFAULT_SOURCE" CPPFLAGS="${CPPFLAGS} -D_BSD_SOURCE" @@ -5815,4 +5816,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 aab922c9c49b9c602e583d6046182a006f37058e +# Generated from src/build/configure.ac sha1 f93bba2632ca0e0760cf8a014c5d2b886e786c56 From 3f0f17ebd32071f8f846f83f301b10c8fa776414 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 11:03:18 -0500 Subject: [PATCH 24/54] Attempt to fix configure issue --- src/build/configure.ac | 5 +++-- src/configure | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index 3fd07f1c7b..15f425ff36 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -15,14 +15,15 @@ AC_PROG_CC AC_CANONICAL_HOST AC_SUBST(CFLAGS, "${CFLAGS} -std=c99") +# BSD_SOURCE can be removed when support for RHEL7 is dropped +# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message +# ---------------------------------------------------------------------------------------------------------------------------------- case $host_os in darwin*) AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_DARWIN_C_SOURCE") ;; linux*) -# BSD_SOURCE can be removed when support for RHEL7 is dropped -# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_DEFAULT_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_BSD_SOURCE") AC_SUBST(CPPFLAGS, "${CPPFLAGS} -D_POSIX_C_SOURCE=200809L") diff --git a/src/configure b/src/configure index 46f7af7e50..95b01c0a4d 100755 --- a/src/configure +++ b/src/configure @@ -3408,6 +3408,9 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac CFLAGS="${CFLAGS} -std=c99" +# BSD_SOURCE can be removed when support for RHEL7 is dropped +# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message +# ---------------------------------------------------------------------------------------------------------------------------------- case $host_os in darwin*) CPPFLAGS="${CPPFLAGS} -D_DARWIN_C_SOURCE" @@ -3415,8 +3418,6 @@ case $host_os in ;; linux*) - # BSD_SOURCE can be removed when support for RHEL7 is dropped - # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message CPPFLAGS="${CPPFLAGS} -D_DEFAULT_SOURCE" CPPFLAGS="${CPPFLAGS} -D_BSD_SOURCE" @@ -5816,4 +5817,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 f93bba2632ca0e0760cf8a014c5d2b886e786c56 +# Generated from src/build/configure.ac sha1 cfd720d55bc80b062a2ab12dd227d679997f737e From 1266dc6e01babb0fb21e036a17bb9b3506944581 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 14:51:48 -0500 Subject: [PATCH 25/54] Attempt to fix CI freebsd issue --- meson.build | 10 ++++++---- src/build/configure.ac | 15 +++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index 5daae7afd0..ada3be32ec 100644 --- a/meson.build +++ b/meson.build @@ -178,10 +178,12 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif -# Find libresolv library -lib_resolv = cc.find_library('resolv') -if lib_ssh2.found() and not lib_resolv.found() - error('libssh2 requires libresolv') +if host_machine.system() == 'linux' + # Find libresolv library + lib_resolv = cc.find_library('resolv') + if lib_ssh2.found() and not lib_resolv.found() + error('libssh2 requires libresolv') + endif endif # Find optional zstd library diff --git a/src/build/configure.ac b/src/build/configure.ac index 15f425ff36..b1c45efee8 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -131,12 +131,15 @@ AC_CHECK_LIB( # Check optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" -then - AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) - AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) -fi - +case $host_os in + linux*) + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) + AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) + fi + ;; +esac # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- From 6cff20b03acdbc37ec8087986fc9b5c36f06602c Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 14:57:55 -0500 Subject: [PATCH 26/54] Attempt to fix configure issue --- src/configure | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/configure b/src/configure index 95b01c0a4d..7376cb0046 100755 --- a/src/configure +++ b/src/configure @@ -4194,9 +4194,11 @@ fi # Check optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +case $host_os in + linux*) + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 printf %s "checking for ns_initparse in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_ns_initparse+y} then : @@ -4241,7 +4243,7 @@ else $as_nop as_fn_error $? "library 'resolv' is required" "$LINENO" 5 fi - ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" + ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes then : @@ -4249,8 +4251,9 @@ else $as_nop as_fn_error $? "header file is required" "$LINENO" 5 fi -fi - + fi + ;; +esac # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5817,4 +5820,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 cfd720d55bc80b062a2ab12dd227d679997f737e +# Generated from src/build/configure.ac sha1 33b24e8a3283f829d696de10740bc18504ecc9a3 From 3f4a1737925a6010ab2184fbe22b4a2ac7e0393d Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 15:15:51 -0500 Subject: [PATCH 27/54] Attempt to fix CI freebsd issue --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index ada3be32ec..520aedd1f4 100644 --- a/meson.build +++ b/meson.build @@ -178,6 +178,7 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif +lib_resolv = false if host_machine.system() == 'linux' # Find libresolv library lib_resolv = cc.find_library('resolv') From 121fa28acd6cee7f946e26dabe90f00057d1c21b Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 15:23:17 -0500 Subject: [PATCH 28/54] Attempt to fix CI freebsd issue --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 520aedd1f4..798de6df09 100644 --- a/meson.build +++ b/meson.build @@ -178,7 +178,7 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif -lib_resolv = false +lib_resolv = dependency('libssh2', required: false) if host_machine.system() == 'linux' # Find libresolv library lib_resolv = cc.find_library('resolv') From 8178f14353eb59efc216084c26f122ff6584a632 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 4 Dec 2023 15:34:19 -0500 Subject: [PATCH 29/54] Attempt to fix CI freebsd issue --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 798de6df09..c5fcc7a6fa 100644 --- a/meson.build +++ b/meson.build @@ -178,7 +178,7 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif -lib_resolv = dependency('libssh2', required: false) +lib_resolv = dependency('libresolv', required: false) if host_machine.system() == 'linux' # Find libresolv library lib_resolv = cc.find_library('resolv') From 4e16045d160523245cbc5b2ab183d920cffe3cfc Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 08:49:12 -0500 Subject: [PATCH 30/54] Attempt to fix CI freebsd issue --- meson.build | 5 +++++ src/build/configure.ac | 3 ++- src/configure | 4 +++- src/storage/sftp/storage.c | 3 +++ test/src/common/harnessSftpResolv.c | 2 ++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index c5fcc7a6fa..1d114ac22c 100644 --- a/meson.build +++ b/meson.build @@ -182,9 +182,14 @@ lib_resolv = dependency('libresolv', required: false) if host_machine.system() == 'linux' # Find libresolv library lib_resolv = cc.find_library('resolv') + if lib_ssh2.found() and not lib_resolv.found() error('libssh2 requires libresolv') endif + + if lib_ssh2.found() + configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') + endif endif # Find optional zstd library diff --git a/src/build/configure.ac b/src/build/configure.ac index b1c45efee8..3cf3427e9d 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -136,7 +136,8 @@ case $host_os in if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" then AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) - AC_CHECK_HEADER(resolv.h, [], [AC_MSG_ERROR([header file is required])]) + AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], + [AC_MSG_ERROR([header file is required])]) fi ;; esac diff --git a/src/configure b/src/configure index 7376cb0046..76b19d02e1 100755 --- a/src/configure +++ b/src/configure @@ -4246,6 +4246,8 @@ fi ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes then : + printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h + LIBS="${LIBS} -lresolv" else $as_nop as_fn_error $? "header file is required" "$LINENO" 5 @@ -5820,4 +5822,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 33b24e8a3283f829d696de10740bc18504ecc9a3 +# Generated from src/build/configure.ac sha1 301025f8d21b2aa972fbb5b17bab2d21d59d7531 diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 8fe2781d28..843a028fb1 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -6,7 +6,10 @@ SFTP Storage #ifdef HAVE_LIBSSH2 #include + +#ifdef HAVE_LIBRESOLV #include +#endif // HAVE_LIBRESOLV #include "common/crypto/hash.h" #include "common/debug.h" diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 136ba2bea2..4bdd535184 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -5,7 +5,9 @@ Harness for SFTP libresolv Testing #ifdef HAVE_LIBSSH2 +#ifdef HAVE_LIBRESOLV #include +#endif // HAVE_LIBRESOLV #include "common/harnessConfig.h" #include "common/harnessDebug.h" From 8a124d876393cbfcaff588bbda29d88d9b8e43b9 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 15:40:18 -0500 Subject: [PATCH 31/54] Attempt to fix CI freebsd issue --- src/storage/sftp/storage.c | 4 +--- test/src/common/harnessSftpResolv.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 843a028fb1..cd42313d48 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -5,11 +5,9 @@ SFTP Storage #ifdef HAVE_LIBSSH2 +#include #include - -#ifdef HAVE_LIBRESOLV #include -#endif // HAVE_LIBRESOLV #include "common/crypto/hash.h" #include "common/debug.h" diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 4bdd535184..136ba2bea2 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -5,9 +5,7 @@ Harness for SFTP libresolv Testing #ifdef HAVE_LIBSSH2 -#ifdef HAVE_LIBRESOLV #include -#endif // HAVE_LIBRESOLV #include "common/harnessConfig.h" #include "common/harnessDebug.h" From 2d616e06b86c5842b5914e3fffb22f17bffd81df Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 15:46:56 -0500 Subject: [PATCH 32/54] Attempt to fix CI freebsd issue --- src/storage/sftp/storage.c | 2 +- test/src/common/harnessSftpResolv.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index cd42313d48..292bd1db18 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -5,8 +5,8 @@ SFTP Storage #ifdef HAVE_LIBSSH2 -#include #include +#include #include #include "common/crypto/hash.h" diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 136ba2bea2..fd1e1c6785 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -5,6 +5,7 @@ Harness for SFTP libresolv Testing #ifdef HAVE_LIBSSH2 +#include #include #include "common/harnessConfig.h" From 40be5e4491d10351cd76151f1e5a7510c5ee73dc Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 15:56:37 -0500 Subject: [PATCH 33/54] Attempt to fix CI freebsd issue --- src/storage/sftp/storage.c | 7 +++++++ test/src/common/harnessSftpResolv.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 292bd1db18..67db75a4a3 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -35,6 +35,13 @@ Define PACKET_SZ if it is not defined #define PACKET_SZ 65535 #endif +/*********************************************************************************************************************************** +Define T_SSHFP if it is not defined +***********************************************************************************************************************************/ +#ifndef T_SSHFP +#define T_SSHFP ns_t_sshfp +#endif + /*********************************************************************************************************************************** Object type ***********************************************************************************************************************************/ diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index fd1e1c6785..2a79229278 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -17,6 +17,13 @@ Include shimmed C modules ***********************************************************************************************************************************/ {[SHIM_MODULE]} +/*********************************************************************************************************************************** +Define T_SSHFP if it is not defined +***********************************************************************************************************************************/ +#ifndef T_SSHFP +#define T_SSHFP ns_t_sshfp +#endif + /*********************************************************************************************************************************** Shim install state ***********************************************************************************************************************************/ From 2dc7a36dce1fc5846bb4f66d163dcb9f53faab1f Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 16:44:59 -0500 Subject: [PATCH 34/54] Do not define T_SSHFP for freebsd, just use ns_t_sshfp instead --- meson.build | 2 +- src/storage/sftp/storage.c | 9 +-------- test/src/common/harnessSftpResolv.c | 7 ------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/meson.build b/meson.build index 1d114ac22c..686d65d326 100644 --- a/meson.build +++ b/meson.build @@ -31,7 +31,7 @@ cc = meson.get_compiler('c') #################################################################################################################################### if host_machine.system() == 'linux' # BSD_SOURCE can be removed when support for RHEL7 is dropped, - # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror() to a generic error message + # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message add_global_arguments('-D_DEFAULT_SOURCE', language : 'c') add_global_arguments('-D_BSD_SOURCE', language : 'c') add_global_arguments('-D_POSIX_C_SOURCE=200809L', language : 'c') diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 67db75a4a3..477c5928a9 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -35,13 +35,6 @@ Define PACKET_SZ if it is not defined #define PACKET_SZ 65535 #endif -/*********************************************************************************************************************************** -Define T_SSHFP if it is not defined -***********************************************************************************************************************************/ -#ifndef T_SSHFP -#define T_SSHFP ns_t_sshfp -#endif - /*********************************************************************************************************************************** Object type ***********************************************************************************************************************************/ @@ -1240,7 +1233,7 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) // Query the server for SSHFP records unsigned char answer[PACKET_SZ]; - int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, ns_t_sshfp, answer, sizeof(answer)); // Check for errors. // Error msg is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we think diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 2a79229278..fd1e1c6785 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -17,13 +17,6 @@ Include shimmed C modules ***********************************************************************************************************************************/ {[SHIM_MODULE]} -/*********************************************************************************************************************************** -Define T_SSHFP if it is not defined -***********************************************************************************************************************************/ -#ifndef T_SSHFP -#define T_SSHFP ns_t_sshfp -#endif - /*********************************************************************************************************************************** Shim install state ***********************************************************************************************************************************/ From 505038dc640a36009ce58f561f49b81fdf472d52 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 21:43:51 -0500 Subject: [PATCH 35/54] Refactor to see if these are now unneded --- meson.build | 9 ++++----- src/build/configure.ac | 16 ++++++---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/meson.build b/meson.build index 686d65d326..51eb439da0 100644 --- a/meson.build +++ b/meson.build @@ -178,16 +178,15 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif -lib_resolv = dependency('libresolv', required: false) -if host_machine.system() == 'linux' - # Find libresolv library - lib_resolv = cc.find_library('resolv') +# Find libresolv library +lib_resolv = cc.find_library('resolv') +if host_machine.system() == 'linux' if lib_ssh2.found() and not lib_resolv.found() error('libssh2 requires libresolv') endif - if lib_ssh2.found() + if lib_resolv.found() configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') endif endif diff --git a/src/build/configure.ac b/src/build/configure.ac index 3cf3427e9d..ef409f56bf 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -131,16 +131,12 @@ AC_CHECK_LIB( # Check optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -case $host_os in - linux*) - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) - AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], - [AC_MSG_ERROR([header file is required])]) - fi - ;; -esac +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) + AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], + [AC_MSG_ERROR([header file is required])]) +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- From 306301a13ae58381b59a046dd35169c606611663 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 21:45:45 -0500 Subject: [PATCH 36/54] Missed configure --- src/configure | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/configure b/src/configure index 76b19d02e1..62c863f29b 100755 --- a/src/configure +++ b/src/configure @@ -4194,11 +4194,9 @@ fi # Check optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -case $host_os in - linux*) - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 printf %s "checking for ns_initparse in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_ns_initparse+y} then : @@ -4243,7 +4241,7 @@ else $as_nop as_fn_error $? "library 'resolv' is required" "$LINENO" 5 fi - ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" + ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes then : printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h @@ -4253,9 +4251,7 @@ else $as_nop as_fn_error $? "header file is required" "$LINENO" 5 fi - fi - ;; -esac +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5822,4 +5818,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 301025f8d21b2aa972fbb5b17bab2d21d59d7531 +# Generated from src/build/configure.ac sha1 5f027042c071c103e757b0d3c6406cf21c5824e3 From 35ef8694f0adff654744141082822713c84d0cef Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 23:10:35 -0500 Subject: [PATCH 37/54] Rework meson.build and configure.ac --- meson.build | 6 +++--- src/build/configure.ac | 13 ++++++++----- src/configure | 11 +++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/meson.build b/meson.build index 51eb439da0..a8d1282d92 100644 --- a/meson.build +++ b/meson.build @@ -178,10 +178,10 @@ if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') endif -# Find libresolv library -lib_resolv = cc.find_library('resolv') +# Find optional libresolv library, required if libssh2 is present +lib_resolv = cc.find_library('resolv', required: false) -if host_machine.system() == 'linux' +if host_machine.system() != 'freebsd' if lib_ssh2.found() and not lib_resolv.found() error('libssh2 requires libresolv') endif diff --git a/src/build/configure.ac b/src/build/configure.ac index ef409f56bf..ad753284bc 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -129,13 +129,16 @@ AC_CHECK_LIB( [AC_CHECK_HEADER(libssh2_sftp.h, [], [AC_MSG_ERROR([header file is required])])]) -# Check optional resolv library if we have libssh2 +# Check for optional resolv library, required if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +if [[ ${host_os%%[0-9]*} != "freebsd" ]] then - AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) - AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], - [AC_MSG_ERROR([header file is required])]) + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) + AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], + [AC_MSG_ERROR([header file is required])]) + fi fi # Check optional zst library. Ignore any versions below 1.0. diff --git a/src/configure b/src/configure index 62c863f29b..9b712e650b 100755 --- a/src/configure +++ b/src/configure @@ -4194,9 +4194,11 @@ fi # Check optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +if [ ${host_os%%[0-9]*} != "freebsd" ] then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 printf %s "checking for ns_initparse in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_ns_initparse+y} then : @@ -4241,7 +4243,7 @@ else $as_nop as_fn_error $? "library 'resolv' is required" "$LINENO" 5 fi - ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" + ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes then : printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h @@ -4251,6 +4253,7 @@ else $as_nop as_fn_error $? "header file is required" "$LINENO" 5 fi + fi fi # Check optional zst library. Ignore any versions below 1.0. @@ -5818,4 +5821,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 5f027042c071c103e757b0d3c6406cf21c5824e3 +# Generated from src/build/configure.ac sha1 59998969e730d711550fb2d2fa83a2de07c7bf8d From 336cdbe376d2aca788fb70d9e9df1b654355b349 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 5 Dec 2023 23:18:05 -0500 Subject: [PATCH 38/54] Generate configure --- src/configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/configure b/src/configure index 9b712e650b..296d131711 100755 --- a/src/configure +++ b/src/configure @@ -4192,7 +4192,7 @@ fi fi -# Check optional resolv library if we have libssh2 +# Check for optional resolv library, required if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- if [ ${host_os%%[0-9]*} != "freebsd" ] then @@ -5821,4 +5821,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 59998969e730d711550fb2d2fa83a2de07c7bf8d +# Generated from src/build/configure.ac sha1 5abff83db3e7f884359086cce1e4ecd8e3ce41f0 From 5fe92228b5dee4122ede787640e07d2bb32cb344 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 01:47:16 -0500 Subject: [PATCH 39/54] Check CI, needs cleanup, docs updated --- src/storage/sftp/storage.c | 361 +++++++++++++++------------- test/define.yaml | 2 +- test/src/common/harnessSftpResolv.c | 21 +- 3 files changed, 211 insertions(+), 173 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 477c5928a9..bb3d79215d 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1100,7 +1100,7 @@ storageSftpResNquery(res_state statep, const char *dname, const int class, const FUNCTION_LOG_PARAM(STRINGZ, dname); FUNCTION_LOG_PARAM(INT, class); FUNCTION_LOG_PARAM(INT, type); - FUNCTION_LOG_PARAM(UCHARDATA, answer); + FUNCTION_LOG_PARAM_P(UCHARDATA, answer); FUNCTION_LOG_PARAM(INT, anslen); FUNCTION_LOG_END(); @@ -1117,9 +1117,9 @@ static int storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) { FUNCTION_LOG_BEGIN(logLevelTrace); - FUNCTION_LOG_PARAM(UCHARDATA, answer); + FUNCTION_LOG_PARAM_P(UCHARDATA, answer); FUNCTION_LOG_PARAM(INT, len); - FUNCTION_LOG_PARAM(VOID, handle); + FUNCTION_LOG_PARAM_P(VOID, handle); FUNCTION_LOG_END(); FUNCTION_LOG_RETURN(INT, ns_initparse(answer, len, handle)); @@ -1146,15 +1146,17 @@ storageSftpSetOption(res_state statep, const uint32_t option) #endif // RES_TRUSTAD /**********************************************************************************************************************************/ -static void +static bool storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) { FUNCTION_LOG_BEGIN(logLevelTrace); - FUNCTION_LOG_PARAM(VOID, session); + FUNCTION_LOG_PARAM_P(VOID, session); FUNCTION_LOG_PARAM(VOID, handle); FUNCTION_LOG_END(); bool result = false; + bool keyNoMatch = false; + bool foundSshfpRecord = false; // Check the sshfp resource records for a fingerprint match for (int rrnum = 0; rrnum < ns_msg_count(handle, ns_s_an); rrnum++) @@ -1164,6 +1166,11 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) // Parse the resource record ns_parserr(&handle, ns_s_an, rrnum, &rr); + if (ns_rr_type(rr) != ns_t_sshfp) + continue; + + foundSshfpRecord = true; + const uint8_t digest_type = *((unsigned char *) ns_rr_rdata(rr) + 1); const unsigned char *digest = (unsigned char *) ns_rr_rdata(rr) + 2; @@ -1189,21 +1196,33 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (binaryFingerprint != NULL && memcmp(binaryFingerprint, digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) { - result = true; LOG_DETAIL_FMT( "sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } else { - LOG_DETAIL_FMT( + keyNoMatch = true; + + LOG_WARN_FMT( "no sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } } - if (result == false) - THROW_FMT(ServiceError, "Host key not found in SSHFP record"); + if (!foundSshfpRecord) + LOG_WARN("no SSHFP records for host found in DNS"); - FUNCTION_LOG_RETURN_VOID(); + // no records return false + // any mismatch return false + // else all match return true + + if (foundSshfpRecord == false) + result = false; + else if (keyNoMatch == true) + result = false; + else + result = true; + + FUNCTION_LOG_RETURN(BOOL, result); } /*********************************************************************************************************************************** @@ -1212,7 +1231,7 @@ Checks that the hostkey is returned in the SSHFP list. This is not a complete ch on the fact that the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is secure. ***********************************************************************************************************************************/ -static void +static bool storageSftpSshfp(StorageSftp *const this, const String *const host) { FUNCTION_LOG_BEGIN(logLevelDebug); @@ -1222,8 +1241,10 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) ASSERT(host != NULL); + bool result = false; + if (storageSftpResNinit(&my_res_state) != 0) - THROW_FMT(ServiceError, "unable to initialize resolver"); + LOG_WARN("unable to initialize resolver"); #ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD @@ -1235,45 +1256,48 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, ns_t_sshfp, answer, sizeof(answer)); - // Check for errors. - // Error msg is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we think - // that's better. + // Check for errors. Error msg is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic + // error if we think that's better. if (len < 0) - { - // Closing before throwing the error does not seem to mess up the hstrerror() call - res_nclose(&my_res_state); + LOG_WARN_FMT("res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); - THROW_FMT( - ServiceError, - "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); - } + // Default res_trustad to unset + unsigned char res_trustad = 0; #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - HEADER *dnsMsgHeader = (HEADER *)answer; - if ((dnsMsgHeader->ad) != 1) - { - res_nclose(&my_res_state); + res_trustad = ((HEADER *)answer)->ad; - THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); - } + if (res_trustad != 1) + LOG_WARN("Host cannot be verified via SSHFP, RES_TRUSTAD not set in response"); #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); #endif // RES_TRUSTAD + // If res_trustad is not set, we should still check for sshfp records, we can't verify them, but we may be able to provide + // useful information to the user + // Initialize parsing the response + int rc; ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); - // Check that the fingerprint is in the SSHFP list - storageSftpVerifyFingerprint(this->session, handle); + // Attempt to verify the host via DNS provided fingerprint + bool sshfpVerified = storageSftpVerifyFingerprint(this->session, handle); // Close the resolver res_nclose(&my_res_state); - FUNCTION_LOG_RETURN_VOID(); + // If res_trustad is not set, return false, else return the result of the fingerprint verification + if (res_trustad == 0) + result = false; + else + result = sshfpVerified; + + FUNCTION_LOG_RETURN(BOOL, result); } /**********************************************************************************************************************************/ @@ -1392,175 +1416,180 @@ storageSftpNew( break; } - // Compare fingerprint if provided else check known hosts files for a match - if (param.hostKeyCheckType == SFTP_STRICT_HOSTKEY_CHECKING_FINGERPRINT) - { - const char *const binaryFingerprint = libssh2_hostkey_hash(this->session, hashType); - - if (binaryFingerprint == NULL) - { - THROW_FMT( - ServiceError, "libssh2 hostkey hash failed: libssh2 errno [%d]", libssh2_session_last_errno(this->session)); - } - - // 256 bytes is large enough to hold the hex representation of currently supported hash types. The hex encoded version - // requires twice as much space (hashSize * 2) as the raw version. - char fingerprint[256]; - - encodeToStr(encodingHex, (unsigned char *)binaryFingerprint, hashSize, fingerprint); + // Attempt to verify via SSHFP fingerprint if requested. If verifiedViaSshfp is successful we implicitly trust the host + bool verifiedViaSshfp = false; + if (param.sshfp) + verifiedViaSshfp = storageSftpSshfp(this, host); - if (strcmp(fingerprint, strZ(param.hostFingerprint)) != 0) - { - THROW_FMT( - ServiceError, "host [%s] and configured fingerprint (repo-sftp-host-fingerprint) [%s] do not match", - fingerprint, strZ(param.hostFingerprint)); - } - } - else if (param.hostKeyCheckType != SFTP_STRICT_HOSTKEY_CHECKING_NONE) + // If we did not verify via SSHFP then we need to verify via normal means + if (!verifiedViaSshfp) { - // Init the known host collection - LIBSSH2_KNOWNHOSTS *const knownHostsList = libssh2_knownhost_init(this->session); - - if (knownHostsList == NULL) + // Compare fingerprint if provided else check known hosts files for a match + if (param.hostKeyCheckType == SFTP_STRICT_HOSTKEY_CHECKING_FINGERPRINT) { - const int rc = libssh2_session_last_errno(this->session); + const char *const binaryFingerprint = libssh2_hostkey_hash(this->session, hashType); - THROW_FMT( - ServiceError, - "failure during libssh2_knownhost_init: libssh2 errno [%d] %s", rc, - strZ(storageSftpLibSsh2SessionLastError(this->session))); - } + if (binaryFingerprint == NULL) + { + THROW_FMT( + ServiceError, "libssh2 hostkey hash failed: libssh2 errno [%d]", libssh2_session_last_errno(this->session)); + } - // Get the list of known host files to search - const StringList *const knownHostsPathList = storageSftpKnownHostsFilesList(param.knownHosts); + // 256 bytes is large enough to hold the hex representation of currently supported hash types. The hex encoded + // version requires twice as much space (hashSize * 2) as the raw version. + char fingerprint[256]; - // Loop through the list of known host files - for (unsigned int listIdx = 0; listIdx < strLstSize(knownHostsPathList); listIdx++) - { - const char *const currentKnownHostFile = strZNull(strLstGet(knownHostsPathList, listIdx)); + encodeToStr(encodingHex, (unsigned char *)binaryFingerprint, hashSize, fingerprint); - // Read the known hosts file entries into the collection, log message for readfile status. - // libssh2_knownhost_readfile() returns the number of successfully loaded hosts or a negative value on error, an - // empty known hosts file will return 0. - if ((rc = libssh2_knownhost_readfile(knownHostsList, currentKnownHostFile, LIBSSH2_KNOWNHOST_FILE_OPENSSH)) <= 0) + if (strcmp(fingerprint, strZ(param.hostFingerprint)) != 0) { - if (rc == 0) - LOG_DETAIL_FMT("libssh2 '%s' file is empty", currentKnownHostFile); - else - { - LOG_DETAIL_FMT( - "libssh2 read '%s' failed: libssh2 errno [%d] %s", currentKnownHostFile, rc, - strZ(storageSftpLibSsh2SessionLastError(this->session))); - } + THROW_FMT( + ServiceError, "host [%s] and configured fingerprint (repo-sftp-host-fingerprint) [%s] do not match", + fingerprint, strZ(param.hostFingerprint)); } - else - LOG_DETAIL_FMT("libssh2 read '%s' succeeded", currentKnownHostFile); } + else if (param.hostKeyCheckType != SFTP_STRICT_HOSTKEY_CHECKING_NONE) + { + // Init the known host collection + LIBSSH2_KNOWNHOSTS *const knownHostsList = libssh2_knownhost_init(this->session); - // Get the remote host key - size_t hostKeyLen; - int hostKeyType; - const char *const hostKey = libssh2_session_hostkey(this->session, &hostKeyLen, &hostKeyType); + if (knownHostsList == NULL) + THROW_FMT(ServiceError, "failure during libssh2_knownhost_init"); - // Check for a match in known hosts files else throw an error if no host key was retrieved - if (hostKey != NULL) - { - rc = libssh2_knownhost_checkp( - knownHostsList, strZ(host), (int)port, hostKey, hostKeyLen, - LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW, NULL); + // Get the list of known host files to search + const StringList *const knownHostsPathList = storageSftpKnownHostsFilesList(param.knownHosts); - // Handle check success/failure - if (rc == LIBSSH2_KNOWNHOST_CHECK_MATCH) - LOG_DETAIL_FMT("known hosts match found for '%s'", strZ(host)); - else + // Loop through the list of known host files + for (unsigned int listIdx = 0; listIdx < strLstSize(knownHostsPathList); listIdx++) { - // Handle failure to match in a similar manner as ssh_config StrictHostKeyChecking. If this flag is set to - // "strict", never automatically add host keys to the ~/.ssh/known_hosts file, and refuse to connect to hosts - // whose host key has changed. This option forces the user to manually add all new hosts. If this flag is set to - // "accept-new" then automatically add new host keys to the user known hosts files, but do not permit - // connections to hosts with changed host keys. - switch (param.hostKeyCheckType) + const char *const idxKnownHostFile = strZNull(strLstGet(knownHostsPathList, listIdx)); + + // Read the known hosts file entries into the collection, log message for readfile status. + // libssh2_knownhost_readfile() returns the number of successfully loaded hosts or a negative value on error, an + // empty known hosts file will return 0. + if ((rc = libssh2_knownhost_readfile(knownHostsList, idxKnownHostFile, LIBSSH2_KNOWNHOST_FILE_OPENSSH)) <= 0) { - case SFTP_STRICT_HOSTKEY_CHECKING_STRICT: + if (rc == 0) + LOG_DETAIL_FMT("libssh2 '%s' file is empty", idxKnownHostFile); + else { - // Throw an error when set to strict and we have any result other than match - libssh2_knownhost_free(knownHostsList); + char *libSsh2ErrMsg; + int libSsh2ErrMsgLen; - THROW_FMT( - ServiceError, "known hosts failure: '%s' %s [%d]: check type [%s]", strZ(host), - storageSftpKnownHostCheckpFailureMsg(rc), rc, strZ(strIdToStr(param.hostKeyCheckType))); + // Get the libssh2 error message + rc = libssh2_session_last_error(this->session, &libSsh2ErrMsg, &libSsh2ErrMsgLen, 0); - break; + LOG_DETAIL_FMT("libssh2 read '%s' failed: libssh2 errno [%d] %s", idxKnownHostFile, rc, libSsh2ErrMsg); } + } + else + LOG_DETAIL_FMT("libssh2 read '%s' succeeded", idxKnownHostFile); + } - default: - { - ASSERT(param.hostKeyCheckType == SFTP_STRICT_HOSTKEY_CHECKING_ACCEPT_NEW); + // Get the remote host key + size_t hostKeyLen; + int hostKeyType; + const char *const hostKey = libssh2_session_hostkey(this->session, &hostKeyLen, &hostKeyType); - // Throw an error when set to accept-new and match fails or mismatches else add the new host key to the - // user's known_hosts file - if (rc == LIBSSH2_KNOWNHOST_CHECK_MISMATCH || rc == LIBSSH2_KNOWNHOST_CHECK_FAILURE) + // Check for a match in known hosts files else throw an error if no host key was retrieved + if (hostKey != NULL) + { + rc = libssh2_knownhost_checkp( + knownHostsList, strZ(host), (int)port, hostKey, hostKeyLen, + LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW, NULL); + + // Handle check success/failure + if (rc == LIBSSH2_KNOWNHOST_CHECK_MATCH) + LOG_DETAIL_FMT("known hosts match found for '%s'", strZ(host)); + else + { + // Handle failure to match in a similar manner as ssh_config StrictHostKeyChecking. If this flag is set to + // "strict", never automatically add host keys to the ~/.ssh/known_hosts file, and refuse to connect to + // hosts whose host key has changed. This option forces the user to manually add all new hosts. If this flag + // is set to "accept-new" then automatically add new host keys to the user known hosts files, but do not + // permit connections to hosts with changed host keys. + switch (param.hostKeyCheckType) + { + case SFTP_STRICT_HOSTKEY_CHECKING_STRICT: { - // Free the known hosts list + // Throw an error when set to strict and we have any result other than match libssh2_knownhost_free(knownHostsList); THROW_FMT( - ServiceError, "known hosts failure: '%s': %s [%d]: check type [%s]", strZ(host), - storageSftpKnownHostCheckpFailureMsg(rc), rc, - strZ(strIdToStr(param.hostKeyCheckType))); + ServiceError, "known hosts failure: '%s' %s [%d]: check type [%s]", strZ(host), + storageSftpKnownHostCheckpFailureMsg(rc), rc, strZ(strIdToStr(param.hostKeyCheckType))); + + break; } - else - storageSftpUpdateKnownHostsFile(this, hostKeyType, host, hostKey, hostKeyLen); - break; + default: + { + ASSERT(param.hostKeyCheckType == SFTP_STRICT_HOSTKEY_CHECKING_ACCEPT_NEW); + + // Throw an error when set to accept-new and match fails or mismatches else add the new host key to + // the user's known_hosts file + if (rc == LIBSSH2_KNOWNHOST_CHECK_MISMATCH || rc == LIBSSH2_KNOWNHOST_CHECK_FAILURE) + { + // Free the known hosts list + libssh2_knownhost_free(knownHostsList); + + THROW_FMT( + ServiceError, "known hosts failure: '%s': %s [%d]: check type [%s]", strZ(host), + storageSftpKnownHostCheckpFailureMsg(rc), rc, + strZ(strIdToStr(param.hostKeyCheckType))); + } + else + storageSftpUpdateKnownHostsFile(this, hostKeyType, host, hostKey, hostKeyLen); + + break; + } } } } - } - else - { - THROW_FMT( - ServiceError, - "libssh2_session_hostkey failed to get hostkey: libssh2 error [%d]", libssh2_session_last_errno(this->session)); - } - - // Free the known hosts list - libssh2_knownhost_free(knownHostsList); - } + else + { + THROW_FMT( + ServiceError, + "libssh2_session_hostkey failed to get hostkey: libssh2 error [%d]", + libssh2_session_last_errno(this->session)); + } - // Check for matching SSHFP fingerprint if requested - if (param.sshfp) - storageSftpSshfp(this, host); + // Free the known hosts list + libssh2_knownhost_free(knownHostsList); + } - // Perform public key authorization, expand leading tilde key file paths if needed - String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); - String *const pubKeyPath = - param.keyPub != NULL && regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? - storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); + // Perform public key authorization, expand leading tilde key file paths if needed + String *const privKeyPath = + regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv); + String *const pubKeyPath = + param.keyPub != NULL && + regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); - do - { - rc = libssh2_userauth_publickey_fromfile( - this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase)); - } - while (storageSftpWaitFd(this, rc)); + do + { + rc = + libssh2_userauth_publickey_fromfile( + this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase)); + } + while (storageSftpWaitFd(this, rc)); - strFree(privKeyPath); - strFree(pubKeyPath); + strFree(privKeyPath); + strFree(pubKeyPath); - if (rc != 0) - { - if (rc == LIBSSH2_ERROR_EAGAIN) - THROW_FMT(ServiceError, "timeout during public key authentication"); + if (rc != 0) + { + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during public key authentication"); - storageSftpEvalLibSsh2Error( - rc, libssh2_sftp_last_error(this->sftpSession), &ServiceError, - STRDEF("public key authentication failed"), - STRDEF( - "HINT: libssh2 compiled against non-openssl libraries requires --repo-sftp-private-key-file and" - " --repo-sftp-public-key-file to be provided\n" - "HINT: libssh2 versions before 1.9.0 expect a PEM format keypair, try ssh-keygen -m PEM -t rsa -P \"\" to" - " generate the keypair")); + storageSftpEvalLibSsh2Error( + rc, libssh2_sftp_last_error(this->sftpSession), &ServiceError, + STRDEF("public key authentication failed"), + STRDEF( + "HINT: libssh2 compiled against non-openssl libraries requires --repo-sftp-private-key-file and" + " --repo-sftp-public-key-file to be provided\n" + "HINT: libssh2 versions before 1.9.0 expect a PEM format keypair, try ssh-keygen -m PEM -t rsa -P \"\"" + " to generate the keypair")); + } } // Init the sftp session diff --git a/test/define.yaml b/test/define.yaml index 3b9355480d..c2f7ddfd0d 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -607,7 +607,7 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: sftp - total: 21 + total: 24 harness: libSsh2 harness: name: sftpResolv diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index fd1e1c6785..8f59050ab1 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -63,7 +63,7 @@ storageSftpResNquery(res_state statep, const char *dname, int class, int type, u FUNCTION_HARNESS_PARAM(STRINGZ, dname); FUNCTION_HARNESS_PARAM(INT, class); FUNCTION_HARNESS_PARAM(INT, type); - FUNCTION_HARNESS_PARAM(UCHARDATA, answer); + FUNCTION_HARNESS_PARAM_P(UCHARDATA, answer); FUNCTION_HARNESS_PARAM(INT, anslen); FUNCTION_HARNESS_END(); @@ -116,7 +116,7 @@ static int storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) { FUNCTION_HARNESS_BEGIN(); - FUNCTION_HARNESS_PARAM(UCHARDATA, answer); + FUNCTION_HARNESS_PARAM_P(UCHARDATA, answer); FUNCTION_HARNESS_PARAM(INT, len); FUNCTION_HARNESS_PARAM_P(VOID, handle); FUNCTION_HARNESS_END(); @@ -133,7 +133,7 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) break; case 1: - result = 1; + result = 0; break; default: @@ -150,18 +150,27 @@ storageSftpNsInitparse(const unsigned char *answer, int len, ns_msg *handle) /*********************************************************************************************************************************** Shim storageSftpVerifyFingerprint() ***********************************************************************************************************************************/ -static void +static bool storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) { + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM_P(VOID, session); + FUNCTION_HARNESS_PARAM(VOID, handle); + FUNCTION_HARNESS_END(); + + bool result; + if (session == NULL) THROW(AssertError, "storageSftpVerifyFingerprint expects 'session' to be not null"); if (hrnSftpResolvStatic.localShimSftpResolv) { - // Do nothing, storageSftpVerifyFingerprint has its own tests in sftpTest.c + result = true; } else - storageSftpVerifyFingerprint_SHIMMED(session, handle); + result = storageSftpVerifyFingerprint_SHIMMED(session, handle); + + FUNCTION_HARNESS_RETURN(BOOL, result); } /**********************************************************************************************************************************/ From 32f2a632b1dcdc163d0d0a8ca98f076d14fab64e Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 09:12:09 -0500 Subject: [PATCH 40/54] Missed sftpTest in last commit --- test/src/module/storage/sftpTest.c | 689 ++++++++++++++++++++++++----- 1 file changed, 585 insertions(+), 104 deletions(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 16d45ad6f6..ae12d2749c 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1177,7 +1177,11 @@ testRun(void) .param = "[\"no-data\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, - {.function = NULL} + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = 0}, + {.function = HRNLIBSSH2_SFTP_INIT}, + HRNLIBSSH2_MACRO_SHUTDOWN() }); argList = strLstNew(); @@ -1195,8 +1199,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - - TEST_ERROR( + TEST_ASSIGN( + storageTest, storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), @@ -1208,10 +1212,16 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, - "res_nquery error [4] No address associated with name 'no-data'"); - + "new storage (defaults)"); TEST_RESULT_LOG( + "P00 WARN: res_nquery error [4] No address associated with name 'no-data'\n" +#ifdef RES_TRUSTAD + "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" +#endif // RES_TRUSTAD +#ifndef RES_TRUSTAD + "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'no-data'\n" +#endif // RES_TRUSTAD + "P00 WARN: ns_initparse error [-1] Resolver internal error for host 'no-data'\n" "P00 WARN: host 'no-data' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'no-data' to '/home/" TEST_USER "/.ssh/known_hosts'"); @@ -1249,7 +1259,11 @@ testRun(void) .param = "[\"trustad-fail\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, - {.function = NULL} + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = 0}, + {.function = HRNLIBSSH2_SFTP_INIT}, + HRNLIBSSH2_MACRO_SHUTDOWN() }); argList = strLstNew(); @@ -1267,7 +1281,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - TEST_ERROR( + TEST_ASSIGN( + storageTest, storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), @@ -1279,13 +1294,14 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, - "Host is untrusted, RES_TRUSTAD not set in response"); - + "new storage (defaults)"); TEST_RESULT_LOG( + "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" "P00 WARN: host 'trustad-fail' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); + + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); #else TEST_LOG("RES_TRUSTAD not supported by OS"); #endif // RES_TRUSTAD @@ -1293,36 +1309,12 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - add host to known_hosts file RSA, sshfp pass"); +#ifdef RES_TRUSTAD hrnLibSsh2ScriptSet((HrnLibSsh2 []) { {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_KNOWNHOST_INIT}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Failed to open file", .resultInt = LIBSSH2_ERROR_FILE}, - {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, - {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"trustad-pass\",22,\"" HOSTKEY "\",20,65537]", - .resultInt = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND}, - {.function = HRNLIBSSH2_KNOWNHOST_INIT}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_KNOWNHOST_ADDC, - .param = "[\"trustad-pass\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, - {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", - .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", - .resultInt = 0}, {.function = HRNLIBSSH2_SFTP_INIT}, HRNLIBSSH2_MACRO_SHUTDOWN() }); @@ -1359,16 +1351,15 @@ testRun(void) .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); - TEST_RESULT_LOG( - "P00 WARN: host 'trustad-pass' not found in known hosts files, attempting to add host to " - "'/home/" TEST_USER "/.ssh/known_hosts'\n" - "P00 WARN: pgBackRest added new host 'trustad-pass' to '/home/" TEST_USER "/.ssh/known_hosts'"); - memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); +#else + TEST_LOG("RES_TRUSTAD not supported by OS"); +#endif // RES_TRUSTAD // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - add host to known_hosts file RSA, storageSftpResInit fail"); +#ifdef RES_TRUSTAD hrnLibSsh2ScriptSet((HrnLibSsh2 []) { {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, @@ -1396,7 +1387,11 @@ testRun(void) .param = "[\"trustad-fail\",null,\"12345678901234567890\",20,\"Generated from pgBackRest\",25,589825]"}, {.function = HRNLIBSSH2_KNOWNHOST_WRITEFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = LIBSSH2_ERROR_NONE}, - {.function = NULL} + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = 0}, + {.function = HRNLIBSSH2_SFTP_INIT}, + HRNLIBSSH2_MACRO_SHUTDOWN() }); // Use the RES_IGNTC option indicate when to return a failure from res_ninit when shimmed @@ -1417,7 +1412,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); - TEST_ERROR( + TEST_ASSIGN( + storageTest, storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), @@ -1429,14 +1425,19 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, - "unable to initialize resolver"); - + "new storage (defaults)"); TEST_RESULT_LOG( + "P00 WARN: unable to initialize resolver\n" + "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" "P00 WARN: host 'trustad-fail' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'trustad-fail' to '/home/" TEST_USER "/.ssh/known_hosts'"); + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); +#else + TEST_LOG("RES_TRUSTAD not supported by OS"); +#endif // RES_TRUSTAD + // Uninstall shim for SFTP libresolv functions hrnSftpResolvShimUninstall(); >>>>>>> 451c94824 (Start to shim libresolv functions in order to implement tests) @@ -8148,6 +8149,147 @@ testRun(void) #endif // HAVE_LIBSSH2 } + // ***************************************************************************************************************************** + if (testBegin("storageSftpVerifyFingerprint()")) + { +#ifdef HAVE_LIBSSH2 + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("storageSftpVerifyFingerprint() no sshfp fingerprint records"); + + harnessLogLevelSet(logLevelDetail); + + TimeMSec timeout = 500; + const StorageSftpNewParam param = {.sshfp = true}; + + // Configure a valid host so that we can successfully initialize the resolver + const String *host = STRDEF("www.postgresql.org"); + unsigned int port = 22; + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, + {.function = NULL}, + }); + + // Step through the sftp storage startup process + OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) + { + *this = (StorageSftp) + { + .interface = storageInterfaceSftp, + .timeout = timeout, + }; + + // Init SFTP session + if (libssh2_init(0) != 0) + THROW_FMT(ServiceError, "unable to init libssh2"); + + this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); + this->session = libssh2_session_init(); + + if (this->session == NULL) + THROW_FMT(ServiceError, "unable to init libssh2 session"); + + // Set session to non-blocking + libssh2_session_set_blocking(this->session, 0); + + // Perform handshake + int rc; + + do + { + rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); + } + while (storageSftpWaitFd(this, rc)); + + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); + + if (rc != 0) + THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); + + if (param.sshfp) + { + if (storageSftpResNinit(&my_res_state) != 0) + LOG_WARN("unable to initialize resolver"); + +#ifdef RES_TRUSTAD + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD + + // Query the server for SSHFP records + unsigned char answer[PACKET_SZ]; + + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + + // Check for errors. + // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we + // think that's better. + if (len < 0) + { + LOG_WARN_FMT( + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); + } + + // Overwrite the sshfp response with a known defined response for testing - this response has ad set, but no sshfp + // records + Buffer *sshfp = + storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/www.postgresql.org.sshfp"))); + + // Verify we got the expected size + TEST_RESULT_INT((int)bufUsed(sshfp), 112, "expected size 112"); + + memset(answer, 0, sizeof(answer)); + memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); + len = (int)bufUsed(sshfp); + +// // Default res_trustad to unset +// unsigned char res_trustad = 0; +#ifdef RES_TRUSTAD + // Check the RES_TRUSTAD flag + unsigned char res_trustad = ((HEADER *)answer)->ad; + if (res_trustad != 1) + LOG_WARN("Host cannot be verified via SSHFP, RES_TRUSTAD not set in response"); +#endif // RES_TRUSTAD + +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT( + "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + int rc; + ns_msg handle; + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); + + // Attempt to verify the host via DNS provided fingerprint - host key not found in SSHFP record + TEST_RESULT_BOOL( + storageSftpVerifyFingerprint(this->session, handle), false, "return false, host key not found in SSHFP record"); + + // Close the resolver + res_nclose(&my_res_state); + } + } + OBJ_NEW_END(); + + objFree(this); + + TEST_RESULT_LOG( +#ifndef RES_TRUSTAD + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" +#endif // RES_TRUSTAD + "P00 WARN: no SSHFP records for host found in DNS"); + + harnessLogLevelReset(); +#else + TEST_LOG(PROJECT_NAME " not built with sftp support"); +#endif // HAVE_LIBSSH2 + } + // ***************************************************************************************************************************** if (testBegin("storageSftpVerifyFingerprint()")) { @@ -8224,7 +8366,7 @@ testRun(void) if (param.sshfp) { if (storageSftpResNinit(&my_res_state) != 0) - THROW_FMT(ServiceError, "unable to initialize resolver"); + LOG_WARN("unable to initialize resolver"); #ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD @@ -8241,46 +8383,41 @@ testRun(void) // think that's better. if (len < 0) { - // Closing before throwing the error does not seem to mess up the hstrerror() call - res_nclose(&my_res_state); - - THROW_FMT( - ServiceError, - "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), - strZ(host)); + LOG_WARN_FMT( + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } - // Overwrite the sshfp response with a known defined response for testing + // Overwrite the sshfp response with a known defined response for testing - this response has ad set and 4 sshfp + // records Buffer *sshfp = storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); - TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + + // Verify we got the expected size + TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size 195"); + memset(answer, 0, sizeof(answer)); memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - HEADER *dnsMsgHeader = (HEADER *)answer; - if ((dnsMsgHeader->ad) != 1) - { - res_nclose(&my_res_state); - - THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); - } + unsigned char res_trustad = ((HEADER *)answer)->ad; + if (res_trustad != 1) + LOG_WARN("Host cannot be verified, RES_TRUSTAD not set in response"); #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response + int rc; ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); - // Check that the fingerprint is in the SSHFP list - TEST_ERROR_FMT( - storageSftpVerifyFingerprint(this->session, handle), ServiceError, "Host key not found in SSHFP record"); + // Attempt to verify the host via DNS provided fingerprint -- no keys match + TEST_RESULT_BOOL(storageSftpVerifyFingerprint(this->session, handle), false, "no keys match"); // Close the resolver res_nclose(&my_res_state); @@ -8292,22 +8429,22 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" #endif // RES_TRUSTAD - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); harnessLogLevelReset(); @@ -8321,7 +8458,7 @@ testRun(void) { #ifdef HAVE_LIBSSH2 // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("storageSftpVerifyFingerprint() success"); + TEST_TITLE("storageSftpVerifyFingerprint() keyMatch && keyNoMatch"); harnessLogLevelSet(logLevelDetail); @@ -8333,8 +8470,8 @@ testRun(void) unsigned int port = 22; // Create binary representation of the host key that will generate a successful match - unsigned char fingperprint[1024]; - decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingperprint); + unsigned char fingerprint[1024]; + decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingerprint); hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -8352,7 +8489,7 @@ testRun(void) #else {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingperprint}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint}, {.function = NULL}, }); @@ -8395,7 +8532,7 @@ testRun(void) if (param.sshfp) { if (storageSftpResNinit(&my_res_state) != 0) - THROW_FMT(ServiceError, "unable to initialize resolver"); + LOG_WARN("unable to initialize resolver"); #ifdef RES_TRUSTAD // Set the resolver to use TRUSTAD @@ -8412,13 +8549,8 @@ testRun(void) // think that's better. if (len < 0) { - // Closing before throwing the error does not seem to mess up the hstrerror() call - res_nclose(&my_res_state); - - THROW_FMT( - ServiceError, - "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), - strZ(host)); + LOG_WARN_FMT( + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } // Overwrite the sshfp response with a known defined response for testing @@ -8434,26 +8566,199 @@ testRun(void) #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - HEADER *dnsMsgHeader = (HEADER *)answer; - if ((dnsMsgHeader->ad) != 1) - { - res_nclose(&my_res_state); + unsigned char res_trustad = ((HEADER *)answer)->ad; + if (res_trustad != 1) + LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); +#endif // RES_TRUSTAD + +#ifndef RES_TRUSTAD + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + int rc; + ns_msg handle; + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); + + // Attempt to verify the host via DNS provided fingerprint -- keyMatch && keyNoMatch + TEST_RESULT_BOOL(storageSftpVerifyFingerprint(this->session, handle), false, "keyMatch && keyNoMatch"); + + // Close the resolver + res_nclose(&my_res_state); + } + } + OBJ_NEW_END(); + + objFree(this); + + TEST_RESULT_LOG( +#ifndef RES_TRUSTAD + "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" +#endif // RES_TRUSTAD + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" +#else + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + " 'cf40a796b1e8775e60a77d410db745012e134109'\n" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef RES_TRUSTAD + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#else + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#endif // RES_TRUSTAD + + harnessLogLevelReset(); +#else + TEST_LOG(PROJECT_NAME " not built with sftp support"); +#endif // HAVE_LIBSSH2 + } + + // ***************************************************************************************************************************** + if (testBegin("storageSftpVerifyFingerprint()")) + { +#ifdef HAVE_LIBSSH2 + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("storageSftpVerifyFingerprint() keyMatch"); + + harnessLogLevelSet(logLevelDetail); + + TimeMSec timeout = 500; + const StorageSftpNewParam param = {.sshfp = true}; - THROW_FMT(ServiceError, "Host is untrusted, RES_TRUSTAD not set in response"); + // Configure a valid host so that we can successfully initialize the resolver + const String *host = STRDEF("www.postgresql.org"); + unsigned int port = 22; + + // Create binary representation of the host keys that will generate a successful match + unsigned char fingerprint1[1024]; + decodeToBin(encodingHex, "BDC1F467AB69238FC4173C20658097835379DBE5", fingerprint1); + unsigned char fingerprint2[1024]; + decodeToBin(encodingHex, "CF40A796B1E8775E60A77D410DB745012E13410935489C411DBFCADF9D62DE19", fingerprint2); + unsigned char fingerprint3[1024]; + decodeToBin(encodingHex, "DED38FADB5713BC6C772E788B5CC41223CA4072C061E5EF152B63EBB1B024096", fingerprint3); + unsigned char fingerprint4[1024]; + decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingerprint4); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint1}, +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = (char *)fingerprint2}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint2}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = (char *)fingerprint3}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint3}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint4}, + {.function = NULL}, + }); + + OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) + { + *this = (StorageSftp) + { + .interface = storageInterfaceSftp, + .timeout = timeout, + }; + + // Init SFTP session + if (libssh2_init(0) != 0) + THROW_FMT(ServiceError, "unable to init libssh2"); + + this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); + this->session = libssh2_session_init(); + + if (this->session == NULL) + THROW_FMT(ServiceError, "unable to init libssh2 session"); + + // Set session to non-blocking + libssh2_session_set_blocking(this->session, 0); + + // Perform handshake + int rc; + + do + { + rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); + } + while (storageSftpWaitFd(this, rc)); + + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); + + if (rc != 0) + THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); + + if (param.sshfp) + { + if (storageSftpResNinit(&my_res_state) != 0) + LOG_WARN("unable to initialize resolver"); + +#ifdef RES_TRUSTAD + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD + + // Query the server for SSHFP records + unsigned char answer[PACKET_SZ]; + + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + + // Check for errors. + // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we + // think that's better. + if (len < 0) + { + LOG_WARN_FMT( + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); } + + // Overwrite the sshfp response with a known defined response for testing + Buffer *sshfp = + storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); + + // Verify we got the expected size + TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + + memset(answer, 0, sizeof(answer)); + memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); + len = (int)bufUsed(sshfp); + +#ifdef RES_TRUSTAD + // Check the RES_TRUSTAD flag + unsigned char res_trustad = ((HEADER *)answer)->ad; + if (res_trustad != 1) + LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response + int rc; ns_msg handle; - storageSftpNsInitparse(answer, len, &handle); + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); - // Check that the fingerprint is in the SSHFP list - TEST_RESULT_VOID(storageSftpVerifyFingerprint(this->session, handle), "Host key found in SSHFP record"); + // Attempt to verify the host via DNS provided fingerprint -- all keys match + TEST_RESULT_BOOL(storageSftpVerifyFingerprint(this->session, handle), true, "all keys match in SSHFP record"); // Close the resolver res_nclose(&my_res_state); @@ -8465,19 +8770,19 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" #endif // RES_TRUSTAD - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 #ifdef RES_TRUSTAD @@ -8494,6 +8799,182 @@ testRun(void) #endif // HAVE_LIBSSH2 } + // ***************************************************************************************************************************** + if (testBegin("storageSftpVerifyFingerprint()")) + { +#ifdef HAVE_LIBSSH2 + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("storageSftpVerifyFingerprint() keyNoMatch - all failures"); + + harnessLogLevelSet(logLevelDetail); + + TimeMSec timeout = 500; + const StorageSftpNewParam param = {.sshfp = true}; + + // Configure a valid host so that we can successfully initialize the resolver + const String *host = STRDEF("www.postgresql.org"); + unsigned int port = 22; + + // Create binary representation of the host keys that will generate all failures - reverse the order of the fingerprints + unsigned char fingerprint4[1024]; + decodeToBin(encodingHex, "BDC1F467AB69238FC4173C20658097835379DBE5", fingerprint4); + unsigned char fingerprint3[1024]; + decodeToBin(encodingHex, "CF40A796B1E8775E60A77D410DB745012E13410935489C411DBFCADF9D62DE19", fingerprint3); + unsigned char fingerprint2[1024]; + decodeToBin(encodingHex, "DED38FADB5713BC6C772E788B5CC41223CA4072C061E5EF152B63EBB1B024096", fingerprint2); + unsigned char fingerprint1[1024]; + decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingerprint1); + + hrnLibSsh2ScriptSet((HrnLibSsh2 []) + { + {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, + {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint1}, +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = (char *)fingerprint2}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint2}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = (char *)fingerprint3}, +#else + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint3}, +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint4}, + {.function = NULL}, + }); + + OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) + { + *this = (StorageSftp) + { + .interface = storageInterfaceSftp, + .timeout = timeout, + }; + + // Init SFTP session + if (libssh2_init(0) != 0) + THROW_FMT(ServiceError, "unable to init libssh2"); + + this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); + this->session = libssh2_session_init(); + + if (this->session == NULL) + THROW_FMT(ServiceError, "unable to init libssh2 session"); + + // Set session to non-blocking + libssh2_session_set_blocking(this->session, 0); + + // Perform handshake + int rc; + + do + { + rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); + } + while (storageSftpWaitFd(this, rc)); + + if (rc == LIBSSH2_ERROR_EAGAIN) + THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); + + if (rc != 0) + THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); + + if (param.sshfp) + { + if (storageSftpResNinit(&my_res_state) != 0) + LOG_WARN("unable to initialize resolver"); + +#ifdef RES_TRUSTAD + // Set the resolver to use TRUSTAD + storageSftpSetOption(&my_res_state, RES_TRUSTAD); +#endif // RES_TRUSTAD + + // Query the server for SSHFP records + unsigned char answer[PACKET_SZ]; + + int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); + + // Check for errors. + // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we + // think that's better. + if (len < 0) + { + LOG_WARN_FMT( + "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); + } + + // Overwrite the sshfp response with a known defined response for testing + Buffer *sshfp = + storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); + + // Verify we got the expected size + TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); + + memset(answer, 0, sizeof(answer)); + memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); + len = (int)bufUsed(sshfp); + +#ifdef RES_TRUSTAD + // Check the RES_TRUSTAD flag + unsigned char res_trustad = ((HEADER *)answer)->ad; + if (res_trustad != 1) + LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); +#endif // RES_TRUSTAD + +#ifndef RES_TRUSTAD + LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); +#endif // RES_TRUSTAD + + // Initialize parsing the response + int rc; + ns_msg handle; + if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) + LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); + + // Attempt to verify the host via DNS provided fingerprint -- no keys match + TEST_RESULT_BOOL(storageSftpVerifyFingerprint(this->session, handle), false, "no SSHFP record matches for hostkey"); + + // Close the resolver + res_nclose(&my_res_state); + } + } + OBJ_NEW_END(); + + objFree(this); + + TEST_RESULT_LOG( +#ifndef RES_TRUSTAD + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" +#endif // RES_TRUSTAD + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" +#else + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + " 'cf40a796b1e8775e60a77d410db745012e134109'\n" + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" +#endif // LIBSSH2_HOSTKEY_HASH_SHA256 +#ifdef RES_TRUSTAD + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#else + "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + " '87ac6bede384d2dc6254f396b83ed34856512e64'"); +#endif // RES_TRUSTAD + + harnessLogLevelReset(); +#else + TEST_LOG(PROJECT_NAME " not built with sftp support"); +#endif // HAVE_LIBSSH2 + } + #ifdef HAVE_LIBSSH2 hrnFdReadyShimUninstall(); hrnSckClientOpenShimUninstall(); From a7e12ce622937598f7d03d4655735c1e2524e03d Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 09:25:54 -0500 Subject: [PATCH 41/54] Add DNS response with ad set but no sshfp records --- test/data/www.postgresql.org.sshfp | Bin 0 -> 112 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/data/www.postgresql.org.sshfp diff --git a/test/data/www.postgresql.org.sshfp b/test/data/www.postgresql.org.sshfp new file mode 100644 index 0000000000000000000000000000000000000000..65802d74d9475c3591c0a4068d007c477b404845 GIT binary patch literal 112 zcmaFv-nf8)5eyla%gf8T3i69f(u-1y3v-zBi_#ewbQl;9@G!6fRWLBBG4O%Zu;*qL z73CKd9}qZT!oUWSVQyhiW6mo!JRrbXo|=@KSX`1?bU+}r=;uVR90Q{c1E*C3hz$Tr Cu^e;& literal 0 HcmV?d00001 From f0470705c22c705ad9901c347a40bda190ee4e46 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 09:36:06 -0500 Subject: [PATCH 42/54] Fix format --- test/src/module/storage/sftpTest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index ae12d2749c..8684367249 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8280,9 +8280,9 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" #endif // RES_TRUSTAD - "P00 WARN: no SSHFP records for host found in DNS"); + "P00 WARN: no SSHFP records for host found in DNS"); harnessLogLevelReset(); #else From c6854829792f22cb064bdf36cac6dee86898b2a0 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 11:41:51 -0500 Subject: [PATCH 43/54] Rename option to repo-sftp-verify-sshfp Make libresolv optional Update help, tests, etc --- meson.build | 12 +- src/build/config/config.yaml | 2 +- src/build/configure.ac | 14 +-- src/build/help/help.xml | 6 +- src/config/config.auto.h | 2 +- src/config/parse.auto.c.inc | 172 ++++++++++++++--------------- src/configure | 76 +++++++------ src/storage/sftp/helper.c | 2 +- test/src/module/command/helpTest.c | 2 +- test/src/module/storage/sftpTest.c | 20 ++-- 10 files changed, 149 insertions(+), 159 deletions(-) diff --git a/meson.build b/meson.build index a8d1282d92..415939e329 100644 --- a/meson.build +++ b/meson.build @@ -31,7 +31,7 @@ cc = meson.get_compiler('c') #################################################################################################################################### if host_machine.system() == 'linux' # BSD_SOURCE can be removed when support for RHEL7 is dropped, - # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message + # DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite a few hstrerror calls to a generic error message add_global_arguments('-D_DEFAULT_SOURCE', language : 'c') add_global_arguments('-D_BSD_SOURCE', language : 'c') add_global_arguments('-D_POSIX_C_SOURCE=200809L', language : 'c') @@ -181,14 +181,8 @@ endif # Find optional libresolv library, required if libssh2 is present lib_resolv = cc.find_library('resolv', required: false) -if host_machine.system() != 'freebsd' - if lib_ssh2.found() and not lib_resolv.found() - error('libssh2 requires libresolv') - endif - - if lib_resolv.found() - configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') - endif +if lib_resolv.found() + configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') endif # Find optional zstd library diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index 8a3ac1932d..fb1b1a89dd 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2460,7 +2460,7 @@ option: command: repo-type depend: repo-sftp-host - repo-sftp-require-sshfp: + repo-sftp-verify-sshfp: section: global group: repo type: boolean diff --git a/src/build/configure.ac b/src/build/configure.ac index ad753284bc..fc618010a3 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -16,7 +16,7 @@ AC_CANONICAL_HOST AC_SUBST(CFLAGS, "${CFLAGS} -std=c99") # BSD_SOURCE can be removed when support for RHEL7 is dropped -# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message +# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite a few hstrerror calls to a generic error message # ---------------------------------------------------------------------------------------------------------------------------------- case $host_os in darwin*) @@ -129,17 +129,9 @@ AC_CHECK_LIB( [AC_CHECK_HEADER(libssh2_sftp.h, [], [AC_MSG_ERROR([header file is required])])]) -# Check for optional resolv library, required if we have libssh2 +# Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if [[ ${host_os%%[0-9]*} != "freebsd" ]] -then - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - AC_CHECK_LIB([resolv], [ns_initparse], [], [AC_MSG_ERROR([library 'resolv' is required])]) - AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], - [AC_MSG_ERROR([header file is required])]) - fi -fi +AC_SEARCH_LIBS([resolv], [ns_initparse], [], []) # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/build/help/help.xml b/src/build/help/help.xml index bfcbf67ddc..51ec9b6e75 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1059,11 +1059,11 @@ path
- - SFTP require SSHFP. + + SFTP verify SSHFP. -

Perform a fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. If no match is found for the host fingerprint in the SSHFP records an error is thrown. If the OS supports RES_TRUSTAD, the SSHFP query will have the RES_TRUSTAD (ad) flag set and if the response ad flag is unset an error will be thrown.

+

Perform fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. The OS must support RES_TRUSTAD (ad flag) in order to verify via SSHFP. If all DNS provided fingerprints match, the host will be trusted. If the DNS response ad flag is not set, or no DNS fingerprints are provided, or if any of the fingerprint records do not match the host fingerprint, warnings are logged and will failover to attempt to verify via normal methods.

n diff --git a/src/config/config.auto.h b/src/config/config.auto.h index 8834c14ee7..24ababdc94 100644 --- a/src/config/config.auto.h +++ b/src/config/config.auto.h @@ -528,7 +528,7 @@ typedef enum cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, cfgOptRepoSftpPublicKeyFile, - cfgOptRepoSftpRequireSshfp, + cfgOptRepoSftpVerifySshfp, cfgOptRepoStorageCaFile, cfgOptRepoStorageCaPath, cfgOptRepoStorageHost, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index eeac4d2ddc..184a842149 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8733,91 +8733,91 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-public-key-file ), // opt/repo-sftp-public-key-file // ----------------------------------------------------------------------------------------------------------------------------- - PARSE_RULE_OPTION // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_NAME("repo-sftp-require-sshfp"), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTIONAL // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-require-sshfp - PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - // opt/repo-sftp-require-sshfp - PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-require-sshfp - ( // opt/repo-sftp-require-sshfp - PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp - ), // opt/repo-sftp-require-sshfp + PARSE_RULE_OPTION // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_NAME("repo-sftp-verify-sshfp"), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTIONAL // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-verify-sshfp + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-verify-sshfp + ( // opt/repo-sftp-verify-sshfp + PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp + ), // opt/repo-sftp-verify-sshfp // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-storage-ca-file ( // opt/repo-storage-ca-file @@ -11074,7 +11074,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order cfgOptRepoSftpPublicKeyFile, // opt-resolve-order - cfgOptRepoSftpRequireSshfp, // opt-resolve-order + cfgOptRepoSftpVerifySshfp, // opt-resolve-order cfgOptRepoStorageCaFile, // opt-resolve-order cfgOptRepoStorageCaPath, // opt-resolve-order cfgOptRepoStorageHost, // opt-resolve-order diff --git a/src/configure b/src/configure index 296d131711..54a781a4b9 100755 --- a/src/configure +++ b/src/configure @@ -3409,7 +3409,7 @@ CFLAGS="${CFLAGS} -std=c99" # BSD_SOURCE can be removed when support for RHEL7 is dropped -# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite an hstrerror call to a generic error message +# DEFAULT_SOURCE can be removed when support for RHEL7 is dropped if we rewrite a few hstrerror calls to a generic error message # ---------------------------------------------------------------------------------------------------------------------------------- case $host_os in darwin*) @@ -4192,69 +4192,73 @@ fi fi -# Check for optional resolv library, required if we have libssh2 +# Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if [ ${host_os%%[0-9]*} != "freebsd" ] -then - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 -printf %s "checking for ns_initparse in -lresolv... " >&6; } -if test ${ac_cv_lib_resolv_ns_initparse+y} +#if [[ ${host_os%%[0-9]*} != "freebsd" ]] +#then +# if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +# then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing resolv" >&5 +printf %s "checking for library containing resolv... " >&6; } +if test ${ac_cv_search_resolv+y} then : printf %s "(cached) " >&6 else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lresolv $LIBS" + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -char ns_initparse (); +char resolv (); int main (void) { -return ns_initparse (); +return resolv (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO" +for ac_lib in '' ns_initparse +do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO" then : - ac_cv_lib_resolv_ns_initparse=yes -else $as_nop - ac_cv_lib_resolv_ns_initparse=no + ac_cv_search_resolv=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + conftest$ac_exeext + if test ${ac_cv_search_resolv+y} +then : + break fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_ns_initparse" >&5 -printf "%s\n" "$ac_cv_lib_resolv_ns_initparse" >&6; } -if test "x$ac_cv_lib_resolv_ns_initparse" = xyes +done +if test ${ac_cv_search_resolv+y} then : - printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h - - LIBS="-lresolv $LIBS" else $as_nop - as_fn_error $? "library 'resolv' is required" "$LINENO" 5 + ac_cv_search_resolv=no fi - - ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" -if test "x$ac_cv_header_resolv_h" = xyes +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_resolv" >&5 +printf "%s\n" "$ac_cv_search_resolv" >&6; } +ac_res=$ac_cv_search_resolv +if test "$ac_res" != no then : - printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h - LIBS="${LIBS} -lresolv" + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -else $as_nop - as_fn_error $? "header file is required" "$LINENO" 5 fi - fi -fi +# fi +#fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5821,4 +5825,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 5abff83db3e7f884359086cce1e4ecd8e3ce41f0 +# Generated from src/build/configure.ac sha1 b0cd3995489a1f085dc72b4b82a755747a7cae2c diff --git a/src/storage/sftp/helper.c b/src/storage/sftp/helper.c index 45a55ec1ea..a80f0b35de 100644 --- a/src/storage/sftp/helper.c +++ b/src/storage/sftp/helper.c @@ -40,7 +40,7 @@ storageSftpHelper(const unsigned int repoIdx, const bool write, StoragePathExpre .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), .knownHosts = knownHosts); + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index 06cc2aa234..696ed7f8cd 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -332,7 +332,7 @@ testRun(void) " --repo-sftp-private-key-file SFTP private key file\n" " --repo-sftp-private-key-passphrase SFTP private key passphrase\n" " --repo-sftp-public-key-file SFTP public key file\n" - " --repo-sftp-require-sshfp SFTP require SSHFP [default=n]\n" + " --repo-sftp-verify-sshfp SFTP verify via SSHFP [default=n]\n" " --repo-storage-ca-file repository storage CA file\n" " --repo-storage-ca-path repository storage CA path\n" " --repo-storage-host repository storage host\n" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 8684367249..1221f5d98f 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1134,7 +1134,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1196,7 +1196,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1210,7 +1210,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1278,7 +1278,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1292,7 +1292,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1331,7 +1331,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; @@ -1347,7 +1347,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); @@ -1409,7 +1409,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1423,7 +1423,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpRequireSshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1488,7 +1488,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpRequireSshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; From 0a2c644d7d48ce406daa59ff6324b4930fa2fc50 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 11:44:38 -0500 Subject: [PATCH 44/54] Regen configure --- src/configure | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/configure b/src/configure index 54a781a4b9..ab021ae9e2 100755 --- a/src/configure +++ b/src/configure @@ -4194,11 +4194,7 @@ fi # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -#if [[ ${host_os%%[0-9]*} != "freebsd" ]] -#then -# if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" -# then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing resolv" >&5 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing resolv" >&5 printf %s "checking for library containing resolv... " >&6; } if test ${ac_cv_search_resolv+y} then : @@ -4257,8 +4253,6 @@ then : fi -# fi -#fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5825,4 +5819,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 b0cd3995489a1f085dc72b4b82a755747a7cae2c +# Generated from src/build/configure.ac sha1 5388a0b7f822bc4419415b75f1a766ea7fbe6e0e From 522e2891bcb5f0d2721cef3ab21dfd6795b964e5 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 11:57:49 -0500 Subject: [PATCH 45/54] Revert configure.ac change --- src/build/configure.ac | 10 ++++++- src/configure | 66 +++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index fc618010a3..294cf79400 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -131,7 +131,15 @@ AC_CHECK_LIB( # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -AC_SEARCH_LIBS([resolv], [ns_initparse], [], []) +if [[ ${host_os%%[0-9]*} != "freebsd" ]] +then + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + AC_CHECK_LIB([resolv], [ns_initparse], [], []) + AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], + [AC_MSG_ERROR([header file is required])]) + fi +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/configure b/src/configure index ab021ae9e2..0591452e69 100755 --- a/src/configure +++ b/src/configure @@ -4194,65 +4194,65 @@ fi # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing resolv" >&5 -printf %s "checking for library containing resolv... " >&6; } -if test ${ac_cv_search_resolv+y} +if [ ${host_os%%[0-9]*} != "freebsd" ] +then + if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +printf %s "checking for ns_initparse in -lresolv... " >&6; } +if test ${ac_cv_lib_resolv_ns_initparse+y} then : printf %s "(cached) " >&6 else $as_nop - ac_func_search_save_LIBS=$LIBS + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -char resolv (); +char ns_initparse (); int main (void) { -return resolv (); +return ns_initparse (); ; return 0; } _ACEOF -for ac_lib in '' ns_initparse -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" +if ac_fn_c_try_link "$LINENO" then : - ac_cv_search_resolv=$ac_res + ac_cv_lib_resolv_ns_initparse=yes +else $as_nop + ac_cv_lib_resolv_ns_initparse=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_resolv+y} -then : - break + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -done -if test ${ac_cv_search_resolv+y} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_ns_initparse" >&5 +printf "%s\n" "$ac_cv_lib_resolv_ns_initparse" >&6; } +if test "x$ac_cv_lib_resolv_ns_initparse" = xyes then : + printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h + + LIBS="-lresolv $LIBS" -else $as_nop - ac_cv_search_resolv=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_resolv" >&5 -printf "%s\n" "$ac_cv_search_resolv" >&6; } -ac_res=$ac_cv_search_resolv -if test "$ac_res" != no + + ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" +if test "x$ac_cv_header_resolv_h" = xyes then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h + LIBS="${LIBS} -lresolv" +else $as_nop + as_fn_error $? "header file is required" "$LINENO" 5 fi + fi +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5819,4 +5819,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 5388a0b7f822bc4419415b75f1a766ea7fbe6e0e +# Generated from src/build/configure.ac sha1 c5d742711c204f7c8faaaae0134095b38b49412b From e1d902799a4166676569a2ebe93696501df21e62 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 12:24:34 -0500 Subject: [PATCH 46/54] Rename option, update help, update tests --- src/build/config/config.yaml | 2 +- src/build/help/help.xml | 4 +- src/config/config.auto.h | 2 +- src/config/parse.auto.c.inc | 172 ++++++++++++++--------------- src/storage/sftp/helper.c | 2 +- test/src/module/command/helpTest.c | 2 +- test/src/module/storage/sftpTest.c | 20 ++-- 7 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index fb1b1a89dd..29a990b513 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2460,7 +2460,7 @@ option: command: repo-type depend: repo-sftp-host - repo-sftp-verify-sshfp: + repo-sftp-verify-via-sshfp: section: global group: repo type: boolean diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 51ec9b6e75..b0d6189c16 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1059,8 +1059,8 @@ path
- - SFTP verify SSHFP. + + SFTP verify via SSHFP.

Perform fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. The OS must support RES_TRUSTAD (ad flag) in order to verify via SSHFP. If all DNS provided fingerprints match, the host will be trusted. If the DNS response ad flag is not set, or no DNS fingerprints are provided, or if any of the fingerprint records do not match the host fingerprint, warnings are logged and will failover to attempt to verify via normal methods.

diff --git a/src/config/config.auto.h b/src/config/config.auto.h index 24ababdc94..dbaac10a6a 100644 --- a/src/config/config.auto.h +++ b/src/config/config.auto.h @@ -528,7 +528,7 @@ typedef enum cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, cfgOptRepoSftpPublicKeyFile, - cfgOptRepoSftpVerifySshfp, + cfgOptRepoSftpVerifyViaSshfp, cfgOptRepoStorageCaFile, cfgOptRepoStorageCaPath, cfgOptRepoStorageHost, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 184a842149..daf458d73c 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8733,91 +8733,91 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-public-key-file ), // opt/repo-sftp-public-key-file // ----------------------------------------------------------------------------------------------------------------------------- - PARSE_RULE_OPTION // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_NAME("repo-sftp-verify-sshfp"), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTIONAL // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-verify-sshfp - PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - // opt/repo-sftp-verify-sshfp - PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-verify-sshfp - ( // opt/repo-sftp-verify-sshfp - PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp - ), // opt/repo-sftp-verify-sshfp + PARSE_RULE_OPTION // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_NAME("repo-sftp-verify-via-sshfp"), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTIONAL // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-verify-via-sshfp + ( // opt/repo-sftp-verify-via-sshfp + PARSE_RULE_VAL_BOOL_FALSE, // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp + ), // opt/repo-sftp-verify-via-sshfp // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-storage-ca-file ( // opt/repo-storage-ca-file @@ -11074,7 +11074,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order cfgOptRepoSftpPublicKeyFile, // opt-resolve-order - cfgOptRepoSftpVerifySshfp, // opt-resolve-order + cfgOptRepoSftpVerifyViaSshfp, // opt-resolve-order cfgOptRepoStorageCaFile, // opt-resolve-order cfgOptRepoStorageCaPath, // opt-resolve-order cfgOptRepoStorageHost, // opt-resolve-order diff --git a/src/storage/sftp/helper.c b/src/storage/sftp/helper.c index a80f0b35de..ef7524efc5 100644 --- a/src/storage/sftp/helper.c +++ b/src/storage/sftp/helper.c @@ -40,7 +40,7 @@ storageSftpHelper(const unsigned int repoIdx, const bool write, StoragePathExpre .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), .knownHosts = knownHosts); + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index 696ed7f8cd..ae34355476 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -332,7 +332,7 @@ testRun(void) " --repo-sftp-private-key-file SFTP private key file\n" " --repo-sftp-private-key-passphrase SFTP private key passphrase\n" " --repo-sftp-public-key-file SFTP public key file\n" - " --repo-sftp-verify-sshfp SFTP verify via SSHFP [default=n]\n" + " --repo-sftp-verify-via-sshfp SFTP verify via SSHFP [default=n]\n" " --repo-storage-ca-file repository storage CA file\n" " --repo-storage-ca-path repository storage CA path\n" " --repo-storage-host repository storage host\n" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 1221f5d98f..7c560d9765 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1134,7 +1134,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1196,7 +1196,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifyViaSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1210,7 +1210,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1278,7 +1278,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifyViaSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1292,7 +1292,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1331,7 +1331,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifyViaSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; @@ -1347,7 +1347,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); @@ -1409,7 +1409,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifyViaSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); TEST_ASSIGN( @@ -1423,7 +1423,7 @@ testRun(void) .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), - .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifySshfp, repoIdx), + .sshfp = cfgOptionIdxBool(cfgOptRepoSftpVerifyViaSshfp, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( @@ -1488,7 +1488,7 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "accept-new"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifySshfp, "y"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpVerifyViaSshfp, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); storageTest = NULL; From d6f814867242e45d6962da1db89f34cac43dac9f Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 15:27:01 -0500 Subject: [PATCH 47/54] Try to make libresolv optional --- src/build/configure.ac | 11 ++--------- src/configure | 16 +++------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index 294cf79400..0e88ffe0d8 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -131,15 +131,8 @@ AC_CHECK_LIB( # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if [[ ${host_os%%[0-9]*} != "freebsd" ]] -then - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - AC_CHECK_LIB([resolv], [ns_initparse], [], []) - AC_CHECK_HEADER(resolv.h, [AC_DEFINE(HAVE_LIBRESOLV) AC_SUBST(LIBS, "${LIBS} -lresolv")], - [AC_MSG_ERROR([header file is required])]) - fi -fi +AC_CHECK_LIB([resolv], [ns_initparse], [], []) +AC_CHECK_HEADER(resolv.h, [], []) # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/configure b/src/configure index 0591452e69..2482724aba 100755 --- a/src/configure +++ b/src/configure @@ -4194,11 +4194,7 @@ fi # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -if [ ${host_os%%[0-9]*} != "freebsd" ] -then - if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 printf %s "checking for ns_initparse in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_ns_initparse+y} then : @@ -4241,18 +4237,12 @@ then : fi - ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" +ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes then : - printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h - LIBS="${LIBS} -lresolv" -else $as_nop - as_fn_error $? "header file is required" "$LINENO" 5 fi - fi -fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5819,4 +5809,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 c5d742711c204f7c8faaaae0134095b38b49412b +# Generated from src/build/configure.ac sha1 65b6564a9a587b5d860cb82af6b2796829905e30 From e138622cc02fda5adf9bca376b069f9589ad82f9 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 11 Dec 2023 22:15:54 -0500 Subject: [PATCH 48/54] Try using predefined header check for resolv.h --- src/build/configure.ac | 3 +- src/configure | 91 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/build/configure.ac b/src/build/configure.ac index 0e88ffe0d8..3b51ae24e8 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -132,7 +132,8 @@ AC_CHECK_LIB( # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- AC_CHECK_LIB([resolv], [ns_initparse], [], []) -AC_CHECK_HEADER(resolv.h, [], []) +#AC_CHECK_HEADER(resolv.h, [], []) +AC_HEADER_RESOLV # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/configure b/src/configure index 2482724aba..8d504179d9 100755 --- a/src/configure +++ b/src/configure @@ -4237,13 +4237,100 @@ then : fi -ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" +#AC_CHECK_HEADER(resolv.h, [], []) +ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include +#endif +" +if test "x$ac_cv_header_sys_types_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include +#endif +" +if test "x$ac_cv_header_netinet_in_h" = xyes +then : + printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "arpa/nameser.h" "ac_cv_header_arpa_nameser_h" "#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include +#endif +" +if test "x$ac_cv_header_arpa_nameser_h" = xyes +then : + printf "%s\n" "#define HAVE_ARPA_NAMESER_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include +#endif +" +if test "x$ac_cv_header_netdb_h" = xyes +then : + printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include /* inet_ functions / structs */ +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include /* DNS HEADER struct */ +#endif +#ifdef HAVE_NETDB_H +# include +#endif +" if test "x$ac_cv_header_resolv_h" = xyes then : + printf "%s\n" "#define HAVE_RESOLV_H 1" >>confdefs.h fi + # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZSTD_isError in -lzstd" >&5 @@ -5809,4 +5896,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 65b6564a9a587b5d860cb82af6b2796829905e30 +# Generated from src/build/configure.ac sha1 13947fd17a3dc13d1ae7750708ad0fc89fc9b997 From 583c5218a5185789673a85b6c140864bf6a99091 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 12 Dec 2023 00:03:19 -0500 Subject: [PATCH 49/54] Update meson.build, configure.ac re optional libresolv Add const modifiers, fix type Update, cleanup, format comments --- meson.build | 12 ++++---- src/build/configure.ac | 10 ++++--- src/configure | 12 ++++---- src/storage/sftp/storage.c | 45 +++++++++++++++-------------- test/src/common/harnessSftpResolv.c | 7 +++-- test/src/module/storage/sftpTest.c | 22 +++++++------- 6 files changed, 60 insertions(+), 48 deletions(-) diff --git a/meson.build b/meson.build index 415939e329..c347ed95a0 100644 --- a/meson.build +++ b/meson.build @@ -176,13 +176,15 @@ lib_ssh2 = dependency('libssh2', required: false) if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') -endif -# Find optional libresolv library, required if libssh2 is present -lib_resolv = cc.find_library('resolv', required: false) + # Find optional libresolv library, if libssh2 is present + if lib_ssh2.found() + lib_resolv = cc.find_library('resolv', required: false) -if lib_resolv.found() - configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') + if lib_resolv.found() + configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') + endif + endif endif # Find optional zstd library diff --git a/src/build/configure.ac b/src/build/configure.ac index 3b51ae24e8..2d2638f0c8 100644 --- a/src/build/configure.ac +++ b/src/build/configure.ac @@ -118,7 +118,7 @@ AC_CHECK_LIB( [AC_CHECK_HEADER(lz4frame.h, [AC_DEFINE(HAVE_LIBLZ4) AC_SUBST(LIBS, "${LIBS} -llz4")], [AC_MSG_ERROR([header file is required])])]) -# Check optional libSSH2 library +# Check optional libssh2 library # ---------------------------------------------------------------------------------------------------------------------------------- AC_CHECK_LIB( [ssh2], [libssh2_init], @@ -131,9 +131,11 @@ AC_CHECK_LIB( # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -AC_CHECK_LIB([resolv], [ns_initparse], [], []) -#AC_CHECK_HEADER(resolv.h, [], []) -AC_HEADER_RESOLV +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + AC_CHECK_LIB([resolv], [ns_initparse], [], []) + AC_HEADER_RESOLV +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/configure b/src/configure index 8d504179d9..154b8625bc 100755 --- a/src/configure +++ b/src/configure @@ -4093,7 +4093,7 @@ fi fi -# Check optional libSSH2 library +# Check optional libssh2 library # ---------------------------------------------------------------------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libssh2_init in -lssh2" >&5 printf %s "checking for libssh2_init in -lssh2... " >&6; } @@ -4194,7 +4194,9 @@ fi # Check for optional resolv library if we have libssh2 # ---------------------------------------------------------------------------------------------------------------------------------- -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 +if test "x$ac_cv_lib_ssh2_libssh2_init" = "xyes" +then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ns_initparse in -lresolv" >&5 printf %s "checking for ns_initparse in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_ns_initparse+y} then : @@ -4237,8 +4239,7 @@ then : fi -#AC_CHECK_HEADER(resolv.h, [], []) -ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "#ifdef HAVE_SYS_TYPES_H + ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "#ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_NETINET_IN_H @@ -4330,6 +4331,7 @@ then : fi +fi # Check optional zst library. Ignore any versions below 1.0. # ---------------------------------------------------------------------------------------------------------------------------------- @@ -5896,4 +5898,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -# Generated from src/build/configure.ac sha1 13947fd17a3dc13d1ae7750708ad0fc89fc9b997 +# Generated from src/build/configure.ac sha1 d02753966f72fc0ea5ee493613a5b2aac0852b5c diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index bb3d79215d..a36d45b8c0 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1093,7 +1093,9 @@ storageSftpResNinit(res_state statep) /**********************************************************************************************************************************/ static int -storageSftpResNquery(res_state statep, const char *dname, const int class, const int type, unsigned char *answer, const int anslen) +storageSftpResNquery( + res_state statep, const char *const dname, const int class, const int type, unsigned char *answer, + const int anslen) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VOID, statep); @@ -1132,7 +1134,7 @@ storageSftpSetOption(res_state statep, const uint32_t option) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VOID, statep); - FUNCTION_LOG_PARAM(UINT64, option); + FUNCTION_LOG_PARAM(UINT32, option); FUNCTION_LOG_END(); ASSERT(statep != NULL); @@ -1166,6 +1168,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) // Parse the resource record ns_parserr(&handle, ns_s_an, rrnum, &rr); + // Skip non-sshfp records if (ns_rr_type(rr) != ns_t_sshfp) continue; @@ -1211,8 +1214,8 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (!foundSshfpRecord) LOG_WARN("no SSHFP records for host found in DNS"); - // no records return false - // any mismatch return false + // If no records return false + // else if any mismatch return false // else all match return true if (foundSshfpRecord == false) @@ -1227,9 +1230,8 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) /*********************************************************************************************************************************** Perform minimal DNS verification on the host. Queries with RES_TRUSTAD if supported and verifies that response is RES_TRUSTAD. -Checks that the hostkey is returned in the SSHFP list. This is not a complete check but it is better than nothing. It is predicated -on the fact that the DNS server is properly configured for DNSSEC and the communication path between the host and the DNS server is -secure. +Checks that the hostkey is returned in the SSHFP list. It is predicated on the fact that the DNS server is properly configured for +DNSSEC and the communication path between the host and the DNS server is secure. ***********************************************************************************************************************************/ static bool storageSftpSshfp(StorageSftp *const this, const String *const host) @@ -1273,11 +1275,11 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD - // If res_trustad is not set, we should still check for sshfp records, we can't verify them, but we may be able to provide - // useful information to the user + // If res_trustad is not set, we still check for sshfp records, we can't verify them, but we may be able to provide useful + // information to the user. // Initialize parsing the response int rc; @@ -1286,7 +1288,7 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); // Attempt to verify the host via DNS provided fingerprint - bool sshfpVerified = storageSftpVerifyFingerprint(this->session, handle); + const bool sshfpVerified = storageSftpVerifyFingerprint(this->session, handle); // Close the resolver res_nclose(&my_res_state); @@ -1416,7 +1418,7 @@ storageSftpNew( break; } - // Attempt to verify via SSHFP fingerprint if requested. If verifiedViaSshfp is successful we implicitly trust the host + // Attempt to verify via SSHFP fingerprint if requested. If verifiedViaSshfp is successful we implicitly trust the host. bool verifiedViaSshfp = false; if (param.sshfp) verifiedViaSshfp = storageSftpSshfp(this, host); @@ -1462,15 +1464,16 @@ storageSftpNew( // Loop through the list of known host files for (unsigned int listIdx = 0; listIdx < strLstSize(knownHostsPathList); listIdx++) { - const char *const idxKnownHostFile = strZNull(strLstGet(knownHostsPathList, listIdx)); + const char *const currentKnownHostFile = strZNull(strLstGet(knownHostsPathList, listIdx)); // Read the known hosts file entries into the collection, log message for readfile status. // libssh2_knownhost_readfile() returns the number of successfully loaded hosts or a negative value on error, an // empty known hosts file will return 0. - if ((rc = libssh2_knownhost_readfile(knownHostsList, idxKnownHostFile, LIBSSH2_KNOWNHOST_FILE_OPENSSH)) <= 0) + if ((rc = libssh2_knownhost_readfile( + knownHostsList, currentKnownHostFile, LIBSSH2_KNOWNHOST_FILE_OPENSSH)) <= 0) { if (rc == 0) - LOG_DETAIL_FMT("libssh2 '%s' file is empty", idxKnownHostFile); + LOG_DETAIL_FMT("libssh2 '%s' file is empty", currentKnownHostFile); else { char *libSsh2ErrMsg; @@ -1479,11 +1482,12 @@ storageSftpNew( // Get the libssh2 error message rc = libssh2_session_last_error(this->session, &libSsh2ErrMsg, &libSsh2ErrMsgLen, 0); - LOG_DETAIL_FMT("libssh2 read '%s' failed: libssh2 errno [%d] %s", idxKnownHostFile, rc, libSsh2ErrMsg); + LOG_DETAIL_FMT( + "libssh2 read '%s' failed: libssh2 errno [%d] %s", currentKnownHostFile, rc, libSsh2ErrMsg); } } else - LOG_DETAIL_FMT("libssh2 read '%s' succeeded", idxKnownHostFile); + LOG_DETAIL_FMT("libssh2 read '%s' succeeded", currentKnownHostFile); } // Get the remote host key @@ -1527,7 +1531,7 @@ storageSftpNew( ASSERT(param.hostKeyCheckType == SFTP_STRICT_HOSTKEY_CHECKING_ACCEPT_NEW); // Throw an error when set to accept-new and match fails or mismatches else add the new host key to - // the user's known_hosts file + // the user's known_hosts file. if (rc == LIBSSH2_KNOWNHOST_CHECK_MISMATCH || rc == LIBSSH2_KNOWNHOST_CHECK_FAILURE) { // Free the known hosts list @@ -1567,9 +1571,8 @@ storageSftpNew( do { - rc = - libssh2_userauth_publickey_fromfile( - this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase)); + rc = libssh2_userauth_publickey_fromfile( + this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase)); } while (storageSftpWaitFd(this, rc)); diff --git a/test/src/common/harnessSftpResolv.c b/test/src/common/harnessSftpResolv.c index 8f59050ab1..29b65d82d7 100644 --- a/test/src/common/harnessSftpResolv.c +++ b/test/src/common/harnessSftpResolv.c @@ -32,7 +32,7 @@ static int storageSftpResNinit(res_state statep) { FUNCTION_HARNESS_BEGIN(); - FUNCTION_HARNESS_PARAM_P(VOID, statep); + FUNCTION_HARNESS_PARAM(VOID, statep); FUNCTION_HARNESS_END(); int result; @@ -56,7 +56,9 @@ storageSftpResNinit(res_state statep) Shim storageSftpResNquery() ***********************************************************************************************************************************/ static int -storageSftpResNquery(res_state statep, const char *dname, int class, int type, unsigned char *answer, int anslen) +storageSftpResNquery( + res_state statep, const char *const dname, const int class, const int type, unsigned char *answer, + const int anslen) { FUNCTION_HARNESS_BEGIN(); FUNCTION_HARNESS_PARAM_P(VOID, statep); @@ -165,6 +167,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (hrnSftpResolvStatic.localShimSftpResolv) { + // Return true. storageSftpVerifyFingerprint has its own tests in sftpTest.c. result = true; } else diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 7c560d9765..7b5f7b5dc5 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1219,7 +1219,7 @@ testRun(void) "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'no-data'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'no-data' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: ns_initparse error [-1] Resolver internal error for host 'no-data'\n" "P00 WARN: host 'no-data' not found in known hosts files, attempting to add host to " @@ -8257,7 +8257,7 @@ testRun(void) #ifndef RES_TRUSTAD LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + "RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8280,7 +8280,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 DETAIL: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: no SSHFP records for host found in DNS"); @@ -8407,7 +8407,7 @@ testRun(void) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8429,7 +8429,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" @@ -8572,7 +8572,7 @@ testRun(void) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8594,7 +8594,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" @@ -8748,7 +8748,7 @@ testRun(void) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8770,7 +8770,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 WARN: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" @@ -8924,7 +8924,7 @@ testRun(void) #endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, skipping trust_ad check for host '%s'", strZ(host)); + LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via sshfp", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8946,7 +8946,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, skipping trust_ad check for host 'www.postgresql.org'\n" + "P00 DETAIL: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via sshfp\n" #endif // RES_TRUSTAD "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" From e206b40b4dc8ce193c061af4c465f1a52cc56910 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 12 Dec 2023 00:24:15 -0500 Subject: [PATCH 50/54] Revert last change to meson build --- meson.build | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index c347ed95a0..00a83b5f90 100644 --- a/meson.build +++ b/meson.build @@ -176,15 +176,13 @@ lib_ssh2 = dependency('libssh2', required: false) if lib_ssh2.found() configuration.set('HAVE_LIBSSH2', true, description: 'Is libssh2 present?') +endif - # Find optional libresolv library, if libssh2 is present - if lib_ssh2.found() - lib_resolv = cc.find_library('resolv', required: false) +# Find optional libresolv library +lib_resolv = cc.find_library('resolv', required: false) - if lib_resolv.found() - configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') - endif - endif +if lib_resolv.found() + configuration.set('HAVE_LIBRESOLV', true, description: 'Is libresolv present?') endif # Find optional zstd library From 1a806e4b603f29d3d78d5d3aa5c7423c29ead893 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 13 Dec 2023 01:34:17 -0500 Subject: [PATCH 51/54] Rework fingerprint matching If any DNS key matches, return success Update tests --- src/build/help/help.xml | 2 +- src/storage/sftp/storage.c | 20 +-- test/define.yaml | 2 +- test/src/module/storage/sftpTest.c | 213 ++++------------------------- 4 files changed, 33 insertions(+), 204 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index b0d6189c16..df92de5097 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1063,7 +1063,7 @@ SFTP verify via SSHFP. -

Perform fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. The OS must support RES_TRUSTAD (ad flag) in order to verify via SSHFP. If all DNS provided fingerprints match, the host will be trusted. If the DNS response ad flag is not set, or no DNS fingerprints are provided, or if any of the fingerprint records do not match the host fingerprint, warnings are logged and will failover to attempt to verify via normal methods.

+

Perform fingerprint verification via SSHFP records. This assumes that DNS resolution is configured to resolve to a DNS server that has been properly configured for DNSSEC and that the path between the host and the DNS server is secure. The OS must support RES_TRUSTAD (ad flag) in order to verify via SSHFP. If any DNS provided fingerprints match, the host will be trusted. If the DNS response ad flag is not set, or no DNS fingerprints are provided, or no DNS fingerprints match the host fingerprint, warnings are logged and will failover to attempt to verify via normal methods.

n diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index a36d45b8c0..6f11fab4ac 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1157,7 +1157,6 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) FUNCTION_LOG_END(); bool result = false; - bool keyNoMatch = false; bool foundSshfpRecord = false; // Check the sshfp resource records for a fingerprint match @@ -1199,32 +1198,19 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) if (binaryFingerprint != NULL && memcmp(binaryFingerprint, digest, (size_t)ns_rr_rdlen(rr) - 2) == 0) { + result = true; + LOG_DETAIL_FMT( "sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } else - { - keyNoMatch = true; - LOG_WARN_FMT( "no sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); - } } if (!foundSshfpRecord) LOG_WARN("no SSHFP records for host found in DNS"); - // If no records return false - // else if any mismatch return false - // else all match return true - - if (foundSshfpRecord == false) - result = false; - else if (keyNoMatch == true) - result = false; - else - result = true; - FUNCTION_LOG_RETURN(BOOL, result); } @@ -1269,10 +1255,10 @@ storageSftpSshfp(StorageSftp *const this, const String *const host) #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag res_trustad = ((HEADER *)answer)->ad; +#endif // RES_TRUSTAD if (res_trustad != 1) LOG_WARN("Host cannot be verified via SSHFP, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); diff --git a/test/define.yaml b/test/define.yaml index c2f7ddfd0d..a09b3ae9df 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -607,7 +607,7 @@ unit: # ---------------------------------------------------------------------------------------------------------------------------- - name: sftp - total: 24 + total: 23 harness: libSsh2 harness: name: sftpResolv diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 7b5f7b5dc5..b71648e24a 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8246,18 +8246,18 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); -// // Default res_trustad to unset -// unsigned char res_trustad = 0; + // Default res_trustad to unset + unsigned char res_trustad = 0; #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - unsigned char res_trustad = ((HEADER *)answer)->ad; + res_trustad = ((HEADER *)answer)->ad; +#endif // RES_TRUSTAD + if (res_trustad != 1) LOG_WARN("Host cannot be verified via SSHFP, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT( - "RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8280,7 +8280,8 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" + "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: no SSHFP records for host found in DNS"); @@ -8399,12 +8400,15 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); + // Default res_trustad to unset + unsigned char res_trustad = 0; #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - unsigned char res_trustad = ((HEADER *)answer)->ad; + res_trustad = ((HEADER *)answer)->ad; +#endif // RES_TRUSTAD + if (res_trustad != 1) LOG_WARN("Host cannot be verified, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); @@ -8429,6 +8433,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD + "P00 WARN: Host cannot be verified, RES_TRUSTAD not set in response\n" "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" @@ -8453,176 +8458,6 @@ testRun(void) #endif // HAVE_LIBSSH2 } - // ***************************************************************************************************************************** - if (testBegin("storageSftpVerifyFingerprint()")) - { -#ifdef HAVE_LIBSSH2 - // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("storageSftpVerifyFingerprint() keyMatch && keyNoMatch"); - - harnessLogLevelSet(logLevelDetail); - - TimeMSec timeout = 500; - const StorageSftpNewParam param = {.sshfp = true}; - - // Configure a valid host so that we can successfully initialize the resolver - const String *host = STRDEF("www.postgresql.org"); - unsigned int port = 22; - - // Create binary representation of the host key that will generate a successful match - unsigned char fingerprint[1024]; - decodeToBin(encodingHex, "87ac6bede384d2dc6254f396b83ed34856512e64", fingerprint); - - hrnLibSsh2ScriptSet((HrnLibSsh2 []) - { - {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = 0}, - {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, - {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = 0}, - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultZ = HOSTKEY}, -#else - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = HOSTKEY}, -#endif // LIBSSH2_HOSTKEY_HASH_SHA256 -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[3]", .resultNull = true}, -#else - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultNull = true}, -#endif // LIBSSH2_HOSTKEY_HASH_SHA256 - {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = (char *)fingerprint}, - {.function = NULL}, - }); - - OBJ_NEW_BEGIN(StorageSftp, .childQty = MEM_CONTEXT_QTY_MAX, .callbackQty = 1) - { - *this = (StorageSftp) - { - .interface = storageInterfaceSftp, - .timeout = timeout, - }; - - // Init SFTP session - if (libssh2_init(0) != 0) - THROW_FMT(ServiceError, "unable to init libssh2"); - - this->ioSession = ioClientOpen(sckClientNew(host, port, timeout, timeout)); - this->session = libssh2_session_init(); - - if (this->session == NULL) - THROW_FMT(ServiceError, "unable to init libssh2 session"); - - // Set session to non-blocking - libssh2_session_set_blocking(this->session, 0); - - // Perform handshake - int rc; - - do - { - rc = libssh2_session_handshake(this->session, ioSessionFd(this->ioSession)); - } - while (storageSftpWaitFd(this, rc)); - - if (rc == LIBSSH2_ERROR_EAGAIN) - THROW_FMT(ServiceError, "timeout during libssh2 handshake [%d]", rc); - - if (rc != 0) - THROW_FMT(ServiceError, "libssh2 handshake failed [%d]", rc); - - if (param.sshfp) - { - if (storageSftpResNinit(&my_res_state) != 0) - LOG_WARN("unable to initialize resolver"); - -#ifdef RES_TRUSTAD - // Set the resolver to use TRUSTAD - storageSftpSetOption(&my_res_state, RES_TRUSTAD); -#endif // RES_TRUSTAD - - // Query the server for SSHFP records - unsigned char answer[PACKET_SZ]; - - int len = storageSftpResNquery(&my_res_state, strZ(host), C_IN, T_SSHFP, answer, sizeof(answer)); - - // Check for errors. - // This is dependent on keeping the _DEFAULT_SOURCE for netdb.h. We can drop it and rewrite to a generic error if we - // think that's better. - if (len < 0) - { - LOG_WARN_FMT( - "res_nquery error [%d] %s '%s'", my_res_state.res_h_errno, hstrerror(my_res_state.res_h_errno), strZ(host)); - } - - // Overwrite the sshfp response with a known defined response for testing - Buffer *sshfp = - storageGetP(storageNewReadP(storagePosixNewP(HRN_PATH_REPO_STR), STRDEF("test/data/muffat.debian.org.sshfp"))); - - // Verify we got the expected size - TEST_RESULT_INT((int)bufUsed(sshfp), 195, "expected size"); - - memset(answer, 0, sizeof(answer)); - memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); - len = (int)bufUsed(sshfp); - -#ifdef RES_TRUSTAD - // Check the RES_TRUSTAD flag - unsigned char res_trustad = ((HEADER *)answer)->ad; - if (res_trustad != 1) - LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD - -#ifndef RES_TRUSTAD - LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); -#endif // RES_TRUSTAD - - // Initialize parsing the response - int rc; - ns_msg handle; - if ((rc = storageSftpNsInitparse(answer, len, &handle)) != 0) - LOG_WARN_FMT("ns_initparse error [%d] %s for host '%s'", rc, hstrerror(rc), strZ(host)); - - // Attempt to verify the host via DNS provided fingerprint -- keyMatch && keyNoMatch - TEST_RESULT_BOOL(storageSftpVerifyFingerprint(this->session, handle), false, "keyMatch && keyNoMatch"); - - // Close the resolver - res_nclose(&my_res_state); - } - } - OBJ_NEW_END(); - - objFree(this); - - TEST_RESULT_LOG( -#ifndef RES_TRUSTAD - "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" -#endif // RES_TRUSTAD - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" - " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" -#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" - " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" - " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" -#else - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" - " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" - " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" -#endif // LIBSSH2_HOSTKEY_HASH_SHA256 -#ifdef RES_TRUSTAD - "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" - " '87ac6bede384d2dc6254f396b83ed34856512e64'"); -#else - "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" - " '87ac6bede384d2dc6254f396b83ed34856512e64'"); -#endif // RES_TRUSTAD - - harnessLogLevelReset(); -#else - TEST_LOG(PROJECT_NAME " not built with sftp support"); -#endif // HAVE_LIBSSH2 - } - // ***************************************************************************************************************************** if (testBegin("storageSftpVerifyFingerprint()")) { @@ -8740,12 +8575,15 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); + // Default res_trustad to unset + unsigned char res_trustad = 0; #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - unsigned char res_trustad = ((HEADER *)answer)->ad; + res_trustad = ((HEADER *)answer)->ad; +#endif // RES_TRUSTAD + if (res_trustad != 1) LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via SSHFP", strZ(host)); @@ -8770,6 +8608,7 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD + "P00 WARN: Host is untrusted, RES_TRUSTAD not set in response\n" "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD "P00 DETAIL: sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" @@ -8916,15 +8755,18 @@ testRun(void) memmove(answer, bufPtr(sshfp), (size_t)bufUsed(sshfp)); len = (int)bufUsed(sshfp); + // Default res_trustad to unset + unsigned char res_trustad = 0; #ifdef RES_TRUSTAD // Check the RES_TRUSTAD flag - unsigned char res_trustad = ((HEADER *)answer)->ad; + res_trustad = ((HEADER *)answer)->ad; +#endif // RES_TRUSTAD + if (res_trustad != 1) LOG_WARN("Host is untrusted, RES_TRUSTAD not set in response"); -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD - LOG_DETAIL_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via sshfp", strZ(host)); + LOG_WARN_FMT("RES_TRUSTAD not supported on this OS, host '%s' cannot be verified via sshfp", strZ(host)); #endif // RES_TRUSTAD // Initialize parsing the response @@ -8946,7 +8788,8 @@ testRun(void) TEST_RESULT_LOG( #ifndef RES_TRUSTAD - "P00 DETAIL: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via sshfp\n" + "P00 WARN: Host is untrusted, RES_TRUSTAD not set in response\n" + "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via sshfp\n" #endif // RES_TRUSTAD "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" From 301f518fcdc01336147d9802697389d58b5b2b15 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 13 Dec 2023 01:50:04 -0500 Subject: [PATCH 52/54] Fix test --- test/src/module/storage/sftpTest.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index b71648e24a..041195fa14 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1215,9 +1215,7 @@ testRun(void) "new storage (defaults)"); TEST_RESULT_LOG( "P00 WARN: res_nquery error [4] No address associated with name 'no-data'\n" -#ifdef RES_TRUSTAD "P00 WARN: Host cannot be verified via SSHFP, RES_TRUSTAD not set in response\n" -#endif // RES_TRUSTAD #ifndef RES_TRUSTAD "P00 WARN: RES_TRUSTAD not supported on this OS, host 'no-data' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD From fb39738f34b00e65c7cdb776105c7b05996b4408 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 20 Dec 2023 10:15:17 -0500 Subject: [PATCH 53/54] Refactor LOG_WARN_FMT to LOG_DETAIL_FMT in sshfp fingerprint loop --- src/storage/sftp/storage.c | 2 +- test/src/module/storage/sftpTest.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 6f11fab4ac..344c6b46c3 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1204,7 +1204,7 @@ storageSftpVerifyFingerprint(LIBSSH2_SESSION *const session, ns_msg handle) "sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } else - LOG_WARN_FMT( + LOG_DETAIL_FMT( "no sshfp fingerprint match found for sshfp digest_type [%d] hashType [%d] '%s'", digest_type, hashType, buffer); } diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 041195fa14..6198b1b646 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -8434,20 +8434,20 @@ testRun(void) "P00 WARN: Host cannot be verified, RES_TRUSTAD not set in response\n" "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via SSHFP\n" #endif // RES_TRUSTAD - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); harnessLogLevelReset(); @@ -8789,24 +8789,24 @@ testRun(void) "P00 WARN: Host is untrusted, RES_TRUSTAD not set in response\n" "P00 WARN: RES_TRUSTAD not supported on this OS, host 'www.postgresql.org' cannot be verified via sshfp\n" #endif // RES_TRUSTAD - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " 'bdc1f467ab69238fc4173c20658097835379dbe5'\n" #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'cf40a796b1e8775e60a77d410db745012e13410935489c411dbfcadf9d62de19'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [3]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c061e5ef152b63ebb1b024096'\n" #else - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'cf40a796b1e8775e60a77d410db745012e134109'\n" - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [2] hashType [2]" " 'ded38fadb5713bc6c772e788b5cc41223ca4072c'\n" #endif // LIBSSH2_HOSTKEY_HASH_SHA256 #ifdef RES_TRUSTAD - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #else - "P00 WARN: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" + "P00 DETAIL: no sshfp fingerprint match found for sshfp digest_type [1] hashType [2]" " '87ac6bede384d2dc6254f396b83ed34856512e64'"); #endif // RES_TRUSTAD From 7cf63c637d24d4ff12546d85303091419c918bcf Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 15 Jan 2024 16:01:36 -0500 Subject: [PATCH 54/54] Rebase to main --- src/storage/sftp/storage.c | 16 +++++++++------- test/src/module/storage/sftpTest.c | 9 ++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 344c6b46c3..1e4b2f070d 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1442,7 +1442,13 @@ storageSftpNew( LIBSSH2_KNOWNHOSTS *const knownHostsList = libssh2_knownhost_init(this->session); if (knownHostsList == NULL) - THROW_FMT(ServiceError, "failure during libssh2_knownhost_init"); + { + const int rc = libssh2_session_last_errno(this->session); + + THROW_FMT( + ServiceError, "failure during libssh2_knownhost_init: libssh2 errno [%d] %s", rc, + strZ(storageSftpLibSsh2SessionLastError(this->session))); + } // Get the list of known host files to search const StringList *const knownHostsPathList = storageSftpKnownHostsFilesList(param.knownHosts); @@ -1462,14 +1468,10 @@ storageSftpNew( LOG_DETAIL_FMT("libssh2 '%s' file is empty", currentKnownHostFile); else { - char *libSsh2ErrMsg; - int libSsh2ErrMsgLen; - - // Get the libssh2 error message - rc = libssh2_session_last_error(this->session, &libSsh2ErrMsg, &libSsh2ErrMsgLen, 0); + const String *const libssh2ErrMsg = storageSftpLibSsh2SessionLastError(this->session); LOG_DETAIL_FMT( - "libssh2 read '%s' failed: libssh2 errno [%d] %s", currentKnownHostFile, rc, libSsh2ErrMsg); + "libssh2 read '%s' failed: libssh2 errno [%d] %s", currentKnownHostFile, rc, strZ(libssh2ErrMsg)); } } else diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 6198b1b646..92a3bf69a4 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1123,6 +1123,7 @@ testRun(void) storageTest = NULL; + harnessLogLevelSet(logLevelDetail); TEST_ASSIGN( storageTest, storageSftpNewP( @@ -1138,10 +1139,17 @@ testRun(void) .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), "new storage (defaults)"); TEST_RESULT_LOG( + "P00 DETAIL: libssh2 '/home/" TEST_USER "/.ssh/known_hosts' file is empty\n" + "P00 DETAIL: libssh2 read '/home/" TEST_USER "/.ssh/known_hosts2' failed: libssh2 errno [-16] Failed to open file\n" + "P00 DETAIL: libssh2 read '/etc/ssh/ssh_known_hosts' failed: libssh2 errno [-16] Failed to open file\n" + "P00 DETAIL: libssh2 read '/etc/ssh/ssh_known_hosts2' failed: libssh2 errno [-16] libssh2 no session error message " + "provided [-16]\n" "P00 WARN: host 'localhost' not found in known hosts files, attempting to add host to " "'/home/" TEST_USER "/.ssh/known_hosts'\n" "P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'"); + harnessLogLevelReset(); + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); // ------------------------------------------------------------------------------------------------------------------------- @@ -1438,7 +1446,6 @@ testRun(void) // Uninstall shim for SFTP libresolv functions hrnSftpResolvShimUninstall(); ->>>>>>> 451c94824 (Start to shim libresolv functions in order to implement tests) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init success - hostKeyCheckType = accept-new - add host to user's known_hosts file DSS");