From a5702740e7ac1eaf4a3c811b2b210962fb6c752a Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 13 Sep 2023 00:16:38 -0400 Subject: [PATCH 01/20] Initial functional implementation of ssh-agent authorization --- src/build/config/config.yaml | 10 + src/build/help/help.xml | 8 + src/config/config.auto.h | 1 + src/config/parse.auto.c.inc | 88 ++++++- src/storage/sftp/helper.c | 3 +- src/storage/sftp/storage.c | 151 +++++++++--- src/storage/sftp/storage.h | 1 + test/src/common/harnessLibSsh2.c | 97 ++++++++ test/src/common/harnessLibSsh2.h | 8 + test/src/module/storage/sftpTest.c | 374 ++++++++++++++++------------- 10 files changed, 540 insertions(+), 201 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index a8ff09b30f..1ab7937afe 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2424,6 +2424,15 @@ option: command: repo-type depend: repo-sftp-host + repo-sftp-identity-agent: + section: global + group: repo + type: string + default: none + required: false + command: repo-type + depend: repo-sftp-host + repo-sftp-known-host: section: global group: repo @@ -2440,6 +2449,7 @@ option: section: global group: repo type: string + required: false command: repo-type depend: repo-sftp-host diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 8b9c94d7a5..944dba55b8 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1134,6 +1134,14 @@ /home/postgres/.ssh/known_hosts + + SFTP identity agent. + +

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to none disables the use of an authentication agent. Arguments to repo-sftp-identity-agent may use the tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

+
+ + none + /var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket
diff --git a/src/config/config.auto.h b/src/config/config.auto.h index cb9204c01f..b6bdfcfca3 100644 --- a/src/config/config.auto.h +++ b/src/config/config.auto.h @@ -524,6 +524,7 @@ typedef enum cfgOptRepoSftpHostKeyHashType, cfgOptRepoSftpHostPort, cfgOptRepoSftpHostUser, + cfgOptRepoSftpIdentityAgent, cfgOptRepoSftpKnownHost, cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 609baa1c24..faa6022abb 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8492,12 +8492,97 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-known-host ), // opt/repo-sftp-known-host // ----------------------------------------------------------------------------------------------------------------------------- + PARSE_RULE_OPTION // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_NAME("repo-sftp-identity-agent"), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_TYPE(cfgOptTypeString), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_REQUIRED(false), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-identity-agent + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_VAL_STR(parseRuleValStrQT_none_QT), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-sftp-private-key-file ( // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_NAME("repo-sftp-private-key-file"), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_TYPE(cfgOptTypeString), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-private-key-file - PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-private-key-file + PARSE_RULE_OPTION_REQUIRED(false), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-private-key-file @@ -10984,6 +11069,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpHostKeyHashType, // opt-resolve-order cfgOptRepoSftpHostPort, // opt-resolve-order cfgOptRepoSftpHostUser, // opt-resolve-order + cfgOptRepoSftpIdentityAgent, // opt-resolve-order cfgOptRepoSftpKnownHost, // opt-resolve-order cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order diff --git a/src/storage/sftp/helper.c b/src/storage/sftp/helper.c index 7a1321a226..02f8c7ad08 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), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index c592c208e3..d5497b9e68 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -36,6 +36,7 @@ struct StorageSftp LIBSSH2_SFTP *sftpSession; // LibSsh2 session sftp session LIBSSH2_SFTP_HANDLE *sftpHandle; // LibSsh2 session sftp handle TimeMSec timeout; // Session timeout + LIBSSH2_AGENT *agent; // LibSsh2 ssh agent handle }; /*********************************************************************************************************************************** @@ -308,6 +309,17 @@ storageSftpLibSsh2SessionFreeResource(THIS_VOID) } } + if (this->agent) + { + rc = libssh2_agent_disconnect(this->agent); + + if (rc != 0) + THROW_FMT(ServiceError, "failed to disconnect libssh2 ssh2 agent: libssh2 errno [%d]", rc); + + // Function returns void + libssh2_agent_free(this->agent); + } + if (this->session != NULL) { do @@ -1091,22 +1103,22 @@ storageSftpNew( FUNCTION_LOG_PARAM(TIME_MSEC, timeout); FUNCTION_LOG_PARAM(STRING, keyPriv); FUNCTION_LOG_PARAM(STRING_ID, hostKeyHashType); + FUNCTION_LOG_PARAM(STRING, param.hostFingerprint); + FUNCTION_LOG_PARAM(STRING_ID, param.hostKeyCheckType); + FUNCTION_LOG_PARAM(STRING, param.identityAgent); FUNCTION_LOG_PARAM(STRING, param.keyPub); FUNCTION_TEST_PARAM(STRING, param.keyPassphrase); - FUNCTION_LOG_PARAM(STRING_ID, param.hostKeyCheckType); - FUNCTION_LOG_PARAM(STRING, param.hostFingerprint); FUNCTION_LOG_PARAM(STRING_LIST, param.knownHosts); FUNCTION_LOG_PARAM(MODE, param.modeFile); FUNCTION_LOG_PARAM(MODE, param.modePath); - FUNCTION_LOG_PARAM(BOOL, param.write); FUNCTION_LOG_PARAM(FUNCTIONP, param.pathExpressionFunction); + FUNCTION_LOG_PARAM(BOOL, param.write); FUNCTION_LOG_END(); ASSERT(path != NULL); ASSERT(host != NULL); ASSERT(port != 0); ASSERT(user != NULL); - ASSERT(keyPriv != NULL); ASSERT(hostKeyHashType != 0); // Initialize user module userInit(); @@ -1315,35 +1327,118 @@ storageSftpNew( 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); - - do + // Authenticate via ssh agent if no private key is provided and ssh agent is not explicitely disabled + if (keyPriv == NULL && (param.identityAgent == NULL || !strEqZ(strLower(strTrim(strDup(param.identityAgent))), "none"))) { - rc = libssh2_userauth_publickey_fromfile( - this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase)); - } - while (storageSftpWaitFd(this, rc)); + // Init the libssh2 agent + this->agent = libssh2_agent_init(this->session); - strFree(privKeyPath); - strFree(pubKeyPath); + if (this->agent == NULL) + THROW_FMT(ServiceError, "failure initializing ssh-agent support"); - if (rc != 0) + // If a specific ssh agent path has been requested, set it for the agent + if (param.identityAgent != NULL) + { + // Does the version of libssh2 (>= 1.9.0) support the libssh2_agent_set_identity_path function +#if LIBSSH2_VERSION_NUM >= 0x010900 + libssh2_agent_set_identity_path( + this->agent, + regExpMatchOne(STRDEF("^ *~"), param.identityAgent) ? + strZ(storageSftpExpandTildePath(param.identityAgent)) : strZ(strTrim(strDup(param.identityAgent)))); +#else + THROW_FMT( + ServiceError, + "libssh2 version %s does not support ssh-agent identity path, requires version 1.9 or greater", + libssh2_version(0)); +#endif + } + + if ((rc = libssh2_agent_connect(this->agent)) != 0) + THROW_FMT(ServiceError, "failure connecting to ssh-agent [%d]", rc); + + if ((rc = libssh2_agent_list_identities(this->agent)) != 0) + THROW_FMT(ServiceError, "failure requesting identities to ssh-agent [%d]", rc); + + struct libssh2_agent_publickey *identity, *prev_identity = NULL; + + for (;;) + { + rc = libssh2_agent_get_identity(this->agent, &identity, prev_identity); + + // Break if we've reached the end of the public keys + if (rc == 1) + break; + + // Throw an error if libssh2_agent_get_identity errored + if (rc < 0) + THROW_FMT(ServiceError, "failure obtaining identity from ssh-agent [%d]", rc); + + // Attempt to authenticate with the current identity + do + { + rc = libssh2_agent_userauth(this->agent, strZ(user), identity); + } + while (storageSftpWaitFd(this, rc)); + + // Log the result of the authentication attempt + if (rc != 0) + LOG_DETAIL_FMT("ssh-agent authentication with username %s failed [%d]", strZ(user), rc); + else + { + LOG_DETAIL_FMT("ssh-agent authentication with username %s succeeded", strZ(user)); + break; + } + + prev_identity = identity; + } + + if (rc != 0) + THROW_FMT(ServiceError, "ssh-agent authentication failure [%d]", rc); + } + else { - if (rc == LIBSSH2_ERROR_EAGAIN) - THROW_FMT(ServiceError, "timeout during public key authentication"); + if (keyPriv != NULL) + { + // 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); - 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")); + 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); + + 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")); + } + } + else + { + THROW_FMT( + ConfigError, + "sftp auth --repo-sftp-identity-agent is configured as 'none' (disabled) and --repo-sftp-private-key-file is " + "empty. Ssh authorization cannot continue, reconfigure --repo-sftp-identity-agent or " + "--repo-sftp-private-key-file appropriately."); + } } // Init the sftp session diff --git a/src/storage/sftp/storage.h b/src/storage/sftp/storage.h index 5d9a558824..00785bcc39 100644 --- a/src/storage/sftp/storage.h +++ b/src/storage/sftp/storage.h @@ -35,6 +35,7 @@ typedef struct StorageSftpNewParam const String *keyPassphrase; StringId hostKeyCheckType; const String *hostFingerprint; + const String *identityAgent; const StringList *knownHosts; } StorageSftpNewParam; diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index 6436a0ecb1..1517994b09 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -154,6 +154,103 @@ hrnLibSsh2ScriptRun(const char *const function, const VariantList *const param, return result; } +/*********************************************************************************************************************************** +Shim for libssh2_agent_init +***********************************************************************************************************************************/ +LIBSSH2_AGENT * +libssh2_agent_init(LIBSSH2_SESSION *session) +{ + HrnLibSsh2 *hrnLibSsh2 = hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_INIT, NULL, (HrnLibSsh2 *)session); + + return hrnLibSsh2->resultNull ? NULL : (LIBSSH2_AGENT *)hrnLibSsh2; +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_connect +***********************************************************************************************************************************/ +int +libssh2_agent_connect(LIBSSH2_AGENT *agent) +{ + return hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_CONNECT, NULL, (HrnLibSsh2 *)agent)->resultInt; +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_disconnect +***********************************************************************************************************************************/ +int +libssh2_agent_disconnect(LIBSSH2_AGENT *agent) +{ + return hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_DISCONNECT, NULL, (HrnLibSsh2 *)agent)->resultInt; +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_free +***********************************************************************************************************************************/ +void +libssh2_agent_free(LIBSSH2_AGENT *agent) +{ + if (agent == NULL) + { + snprintf( + hrnLibSsh2ScriptError, sizeof(hrnLibSsh2ScriptError), + "libssh2 script function 'libssh2_agent_free', expects agent to be not NULL"); + THROW(AssertError, hrnLibSsh2ScriptError); + } + + hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_FREE, NULL, (HrnLibSsh2 *)agent); +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_get_identity +***********************************************************************************************************************************/ +int +libssh2_agent_get_identity(LIBSSH2_AGENT *agent, struct libssh2_agent_publickey **store, struct libssh2_agent_publickey *prev) +{ + // Avoid compiler complaining of unused params + (void)prev; + (void)store; + + HrnLibSsh2 *hrnLibSsh2 = hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_GET_IDENTITY, NULL, (HrnLibSsh2 *)agent); + + return hrnLibSsh2->resultInt; +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_list_identities +***********************************************************************************************************************************/ +int +libssh2_agent_list_identities(LIBSSH2_AGENT *agent) +{ + return hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_LIST_IDENTITIES, NULL, (HrnLibSsh2 *)agent)->resultInt; +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_set_identity_path +***********************************************************************************************************************************/ +void +libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, const char *path) +{ + // Avoid compiler complaining of unused param + (void)path; + + hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_SET_IDENTITY_PATH, NULL, (HrnLibSsh2 *)agent); +} + +/*********************************************************************************************************************************** +Shim for libssh2_agent_userauth +***********************************************************************************************************************************/ +int +libssh2_agent_userauth(LIBSSH2_AGENT *agent, const char *username, struct libssh2_agent_publickey *identity) +{ + // Avoid compiler complaining of unused params + (void)username; + (void)identity; + + HrnLibSsh2 *hrnLibSsh2 = hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_USERAUTH, NULL, (HrnLibSsh2 *)agent); + + return hrnLibSsh2->resultInt; +} + /*********************************************************************************************************************************** Shim for libssh2_init ***********************************************************************************************************************************/ diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index c17377eae8..802b9e0bc9 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -34,6 +34,14 @@ libssh2 authorization constants /*********************************************************************************************************************************** Function constants ***********************************************************************************************************************************/ +#define HRNLIBSSH2_AGENT_INIT "libssh2_agent_init" +#define HRNLIBSSH2_AGENT_CONNECT "libssh2_agent_connect" +#define HRNLIBSSH2_AGENT_DISCONNECT "libssh2_agent_disconnect" +#define HRNLIBSSH2_AGENT_FREE "libssh2_agent_free" +#define HRNLIBSSH2_AGENT_GET_IDENTITY "libssh2_agent_get_identity" +#define HRNLIBSSH2_AGENT_LIST_IDENTITIES "libssh2_agent_list_identities" +#define HRNLIBSSH2_AGENT_SET_IDENTITY_PATH "libssh2_agent_set_identity_path" +#define HRNLIBSSH2_AGENT_USERAUTH "libssh2_agent_userauth" #define HRNLIBSSH2_HOSTKEY_HASH "libssh2_hostkey_hash" #define HRNLIBSSH2_INIT "libssh2_init" #define HRNLIBSSH2_KNOWNHOST_ADDC "libssh2_knownhost_addc" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 4846e417b4..36a67863a9 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -285,271 +285,303 @@ testRun(void) " [9132333435363738393039383736353433323130] do not match"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("known host init failure"); + TEST_TITLE("libssh2_agent_init failure"); 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, .resultNull = true}, - {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .resultInt = LIBSSH2_ERROR_ALLOC, - .errMsg = (char *)"Unable to allocate memory for known-hosts collection"}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT, .resultNull = true}, {.function = NULL} }); - // Load configuration - 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); - 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "failure during libssh2_knownhost_init: libssh2 errno [-6] Unable to allocate memory for known-hosts collection"); + "failure initializing ssh-agent support"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("libssh2_session_hostkey fail - return NULL - hostKeyCheckType = yes"); + TEST_TITLE("libssh2_agent_connect failure"); 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 = 5}, - {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultNull = true}, - {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = -1}, {.function = NULL} }); - // Load configuration - 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); - 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "libssh2_session_hostkey failed to get hostkey: libssh2 error [-7]"); + "failure connecting to ssh-agent [-1]"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_MISMATCH"); + TEST_TITLE("libssh2_agent_list_identities failure"); 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 = 5}, - {.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_MISMATCH}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = -1}, {.function = NULL} }); 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "known hosts failure: 'localhost' mismatch in known hosts files: LIBSSH2_KNOWNHOST_CHECK_MISMATCH [1]: check type " - "[strict]"); + "failure requesting identities to ssh-agent [-1]"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_FAILURE"); + TEST_TITLE("libssh2_agent_get_identity failure"); 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 = 5}, - {.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_FAILURE}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = -1}, {.function = NULL} }); 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, "known hosts failure: 'localhost' LIBSSH2_KNOWNHOST_CHECK_FAILURE [3]: check type [strict]"); + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "failure obtaining identity from ssh-agent [-1]"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_NOTFOUND"); + TEST_TITLE("libssh2_agent_userauth failure"); 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 = 5}, - {.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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = -1}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = 1}, // 1 == reached the end of public keys list {.function = NULL} }); 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type" - " [strict]"); + "ssh-agent authentication failure [1]"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("read known_hosts file failure - empty files - log INFO on empty known_hosts files"); + TEST_TITLE("libssh2_agent_userauth success - libssh2_agent_disconnect failure in free resources"); 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 = 0}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 0}, - {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0}, - {.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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SFTP_INIT}, + {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, + {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = -1}, {.function = NULL} }); + Storage *storageTest = 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, "localhost"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); - HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + TEST_ASSIGN( + storageTest, + storageSftpNewP( + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1), + "new storage (defaults)"); + TEST_ERROR_FMT( + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), + ServiceError, + "failed to disconnect libssh2 ssh2 agent: libssh2 errno [-1]"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("libssh2_agent_userauth success"); + + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SFTP_INIT}, + {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, + {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_FREE}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, + {.function = NULL} + }); + + storageTest = NULL; + + TEST_ASSIGN( + storageTest, + storageSftpNewP( + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1), + "new storage (defaults)"); + + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("libssh2_agent_userauth success - identityAgent populated tilde path"); + +#if LIBSSH2_VERSION_NUM >= 0x010900 + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SFTP_INIT}, + {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, + {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_FREE}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, + {.function = NULL} + }); + + storageTest = NULL; + + TEST_ASSIGN( + storageTest, + storageSftpNewP( + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, + .identityAgent = STRDEF("~/.ssh/myagent")), + "new storage (defaults)"); + + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); +#else + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = NULL} + }); 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, + .identityAgent = STRDEF("~/.ssh/myagent")), ServiceError, - "known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type" - " [strict]"); - + "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); +#endif // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("knownhost_checkp unknown failure type"); + TEST_TITLE("libssh2_agent_userauth success - identityAgent populated full path"); +#if LIBSSH2_VERSION_NUM >= 0x010900 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 = 5}, - {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, - {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]", - .resultInt = 5}, + {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_EAGAIN}, + {.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_SFTP_INIT}, + {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, + {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_FREE}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, {.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, "localhost"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR); - hrnCfgArgRawZ(argList, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); - HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + storageTest = NULL; + + TEST_ASSIGN( + storageTest, + storageSftpNewP( + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, + .identityAgent = STRDEF("/var/lib/postgresql/.ssh/myagent")), + "new storage (defaults)"); + + memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); +#else + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = NULL} + }); 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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), - ServiceError, "known hosts failure: 'localhost' unknown failure [5]: check type [strict]"); + STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, + .identityAgent = STRDEF("/var/lib/postgresql/.ssh/myagent")), + ServiceError, + "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); +#endif + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("libssh2_agent_userauth failure - identityAgent disabled (none) and no private key configured"); + + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = NULL} + }); + + TEST_ERROR( + storageSftpNewP( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, .identityAgent = STRDEF("none")), + ConfigError, + "sftp auth --repo-sftp-identity-agent is configured as 'none' (disabled) and --repo-sftp-private-key-file is empty. Ssh" + " authorization cannot continue, reconfigure --repo-sftp-identity-agent or --repo-sftp-private-key-file " + "appropriately."); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("public key from file auth failure, no public key"); @@ -764,7 +796,7 @@ testRun(void) HRNLIBSSH2_MACRO_SHUTDOWN() }); - Storage *storageTest = NULL; + storageTest = NULL; TEST_ASSIGN( storageTest, From 3ff3ad81d12fd288f420c54066ea13b35814bc3a Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Thu, 14 Sep 2023 00:50:04 -0400 Subject: [PATCH 02/20] Add comment --- src/storage/sftp/storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index d5497b9e68..8e634d8a70 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1359,6 +1359,7 @@ storageSftpNew( if ((rc = libssh2_agent_list_identities(this->agent)) != 0) THROW_FMT(ServiceError, "failure requesting identities to ssh-agent [%d]", rc); + // Loop through the identities and attempt to authenticate with each struct libssh2_agent_publickey *identity, *prev_identity = NULL; for (;;) From 9a7a333eae62c916bdfe7d386dcaacee213cce25 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 10:32:40 -0400 Subject: [PATCH 03/20] Account for older libssh2 versions inability to set identity agent path More informative error messages Update harnessLibSsh2 and tests --- src/build/config/config.yaml | 1 - src/build/help/help.xml | 1 - src/config/parse.auto.c.inc | 5 ---- src/storage/sftp/storage.c | 23 ++++++++++++-- test/src/common/harnessLibSsh2.c | 11 +++++++ test/src/common/harnessLibSsh2.h | 2 ++ test/src/module/storage/sftpTest.c | 48 ++++++++++++++++++++++++++++-- 7 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index 1ab7937afe..3e2e525216 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2428,7 +2428,6 @@ option: section: global group: repo type: string - default: none required: false command: repo-type depend: repo-sftp-host diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 944dba55b8..be04c9a42f 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1140,7 +1140,6 @@

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to none disables the use of an authentication agent. Arguments to repo-sftp-identity-agent may use the tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

- none /var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket
diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index faa6022abb..9f5c2fba48 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8567,11 +8567,6 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ( // opt/repo-sftp-identity-agent PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-identity-agent PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_VAL_STR(parseRuleValStrQT_none_QT), // opt/repo-sftp-identity-agent ), // opt/repo-sftp-identity-agent ), // opt/repo-sftp-identity-agent ), // opt/repo-sftp-identity-agent diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 8e634d8a70..d44b89483c 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1333,8 +1333,14 @@ storageSftpNew( // Init the libssh2 agent this->agent = libssh2_agent_init(this->session); + char *ssh2ErrMsg; + int ssh2ErrMsgLen; + if (this->agent == NULL) - THROW_FMT(ServiceError, "failure initializing ssh-agent support"); + { + rc = libssh2_session_last_error(this->session, &ssh2ErrMsg, &ssh2ErrMsgLen, 0); + THROW_FMT(ServiceError, "failure initializing ssh-agent support [%d]: %s", rc, ssh2ErrMsg); + } // If a specific ssh agent path has been requested, set it for the agent if (param.identityAgent != NULL) @@ -1354,7 +1360,20 @@ storageSftpNew( } if ((rc = libssh2_agent_connect(this->agent)) != 0) - THROW_FMT(ServiceError, "failure connecting to ssh-agent [%d]", rc); + { + rc = libssh2_session_last_error(this->session, &ssh2ErrMsg, &ssh2ErrMsgLen, 0); + + // Does the version of libssh2 (>= 1.9.0) support the libssh2_agent_get_identity_path function +#if LIBSSH2_VERSION_NUM >= 0x010900 + const char *const identity_agent_path = libssh2_agent_get_identity_path(this->agent); +#else + const char *const identity_agent_path = NULL; +#endif + THROW_FMT( + ServiceError, + "failure connecting to ssh-agent %s[%d]%s", + identity_agent_path == NULL ? "" : zNewFmt("'%s' ", identity_agent_path) , rc, zNewFmt(": %s", ssh2ErrMsg)); + } if ((rc = libssh2_agent_list_identities(this->agent)) != 0) THROW_FMT(ServiceError, "failure requesting identities to ssh-agent [%d]", rc); diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index 1517994b09..f3c6d1b9a5 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -215,6 +215,17 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent, struct libssh2_agent_publickey return hrnLibSsh2->resultInt; } +/*********************************************************************************************************************************** +Shim for libssh2_agent_get_identity_path +***********************************************************************************************************************************/ +const char * +libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent) +{ + HrnLibSsh2 *hrnLibSsh2 = hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_GET_IDENTITY_PATH, NULL, (HrnLibSsh2 *)agent); + + return hrnLibSsh2->identity_agent; +} + /*********************************************************************************************************************************** Shim for libssh2_agent_list_identities ***********************************************************************************************************************************/ diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index 802b9e0bc9..16689c7bce 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -39,6 +39,7 @@ Function constants #define HRNLIBSSH2_AGENT_DISCONNECT "libssh2_agent_disconnect" #define HRNLIBSSH2_AGENT_FREE "libssh2_agent_free" #define HRNLIBSSH2_AGENT_GET_IDENTITY "libssh2_agent_get_identity" +#define HRNLIBSSH2_AGENT_GET_IDENTITY_PATH "libssh2_agent_get_identity_path" #define HRNLIBSSH2_AGENT_LIST_IDENTITIES "libssh2_agent_list_identities" #define HRNLIBSSH2_AGENT_SET_IDENTITY_PATH "libssh2_agent_set_identity_path" #define HRNLIBSSH2_AGENT_USERAUTH "libssh2_agent_userauth" @@ -131,6 +132,7 @@ typedef struct HrnLibSsh2 const String *symlinkExTarget; // libssh2_sftp_symlink_ex target const String *fileName; // libssh2_readdir* libssh2_stat* filename const String *readBuffer; // what to copy into read buffer + const char *identity_agent; // libssh2 identity agent path TimeMSec sleep; // Sleep specified milliseconds before returning from function size_t len; // libssh2_session_hostkey len int type; // libssh2_session_hostkey type diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 36a67863a9..5ccc308331 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -294,6 +294,8 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, {.function = HRNLIBSSH2_AGENT_INIT, .resultNull = true}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Unable to allocate space for agent connection", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = NULL} }); @@ -301,7 +303,7 @@ testRun(void) storageSftpNewP( TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "failure initializing ssh-agent support"); + "failure initializing ssh-agent support [-6]: Unable to allocate space for agent connection"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_connect failure"); @@ -313,7 +315,12 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, {.function = HRNLIBSSH2_AGENT_INIT}, - {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = -1}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_BAD_USE}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"no auth sock variable", + .resultInt = LIBSSH2_ERROR_BAD_USE}, +#if LIBSSH2_VERSION_NUM >= 0x010900 + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY_PATH}, +#endif {.function = NULL} }); @@ -321,7 +328,42 @@ testRun(void) storageSftpNewP( TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), ServiceError, - "failure connecting to ssh-agent [-1]"); + "failure connecting to ssh-agent [-39]: no auth sock variable"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("libssh2_agent_connect failure - non default agent"); + + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, +#if LIBSSH2_VERSION_NUM >= 0x010900 + {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_AGENT_PROTOCOL}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"failed connecting with agent", + .resultInt = LIBSSH2_ERROR_AGENT_PROTOCOL}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY_PATH, .identity_agent = (char *)"/tmp/pgbackrest-ssh-agent"}, +#endif + {.function = NULL} + }); +#if LIBSSH2_VERSION_NUM >= 0x010900 + TEST_ERROR( + storageSftpNewP( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, + .identityAgent = STRDEF("/tmp/pgbackrest-ssh-agent")), + ServiceError, + "failure connecting to ssh-agent '/tmp/pgbackrest-ssh-agent' [-42]: failed connecting with agent"); +#else + TEST_ERROR( + storageSftpNewP( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, + .identityAgent = STRDEF("/tmp/pgbackrest-ssh-agent")), + ServiceError, + "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); +#endif // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_list_identities failure"); From c54246f01346c3f73326d695cd72788ecb7b7099 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 11:24:41 -0400 Subject: [PATCH 04/20] Update helpTest for identity agent --- test/src/module/command/helpTest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index b37879752b..ef4c514a29 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -329,6 +329,7 @@ testRun(void) " --repo-sftp-host-port SFTP repository host port [default=22]\n" " --repo-sftp-host-user SFTP repository host user\n" " --repo-sftp-known-host SFTP known hosts file\n" + " --repo-sftp-identity-agent SFTP identity agent\n" " --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" From 554e3648371807f8eae70e6e1457a1ecdbf4a351 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 12:28:04 -0400 Subject: [PATCH 05/20] Remove extraneous space --- src/storage/sftp/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index d44b89483c..8a3f361cab 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1372,7 +1372,7 @@ storageSftpNew( THROW_FMT( ServiceError, "failure connecting to ssh-agent %s[%d]%s", - identity_agent_path == NULL ? "" : zNewFmt("'%s' ", identity_agent_path) , rc, zNewFmt(": %s", ssh2ErrMsg)); + identity_agent_path == NULL ? "" : zNewFmt("'%s' ", identity_agent_path), rc, zNewFmt(": %s", ssh2ErrMsg)); } if ((rc = libssh2_agent_list_identities(this->agent)) != 0) From 44d8527c0eb846472df31c3584cfc198ff947788 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 12:40:43 -0400 Subject: [PATCH 06/20] Replace hard coded libssh2 version with call to LIBSSH2_VERSION --- test/src/module/storage/sftpTest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 5ccc308331..05eb3adeaa 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -362,7 +362,7 @@ testRun(void) TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, .identityAgent = STRDEF("/tmp/pgbackrest-ssh-agent")), ServiceError, - "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); + "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif // ------------------------------------------------------------------------------------------------------------------------- @@ -547,7 +547,7 @@ testRun(void) STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, .identityAgent = STRDEF("~/.ssh/myagent")), ServiceError, - "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); + "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - identityAgent populated full path"); @@ -602,7 +602,7 @@ testRun(void) STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, .identityAgent = STRDEF("/var/lib/postgresql/.ssh/myagent")), ServiceError, - "libssh2 version 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); + "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif // ------------------------------------------------------------------------------------------------------------------------- From 73adc09c24ce3438c9df3c02f3057317796e2433 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 14:33:16 -0400 Subject: [PATCH 07/20] Remove space --- 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 be04c9a42f..a2817395f4 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1137,7 +1137,7 @@ SFTP identity agent. -

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to none disables the use of an authentication agent. Arguments to repo-sftp-identity-agent may use the tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

+

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to none disables the use of an authentication agent. Arguments to repo-sftp-identity-agent may use tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

/var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket From 9b890d94fb3a5850590e1562aa4d4d6d0b043bb9 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 15:08:37 -0400 Subject: [PATCH 08/20] Better error message --- src/storage/sftp/storage.c | 6 +++--- test/src/module/storage/sftpTest.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 8a3f361cab..4ca264abf1 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1455,9 +1455,9 @@ storageSftpNew( { THROW_FMT( ConfigError, - "sftp auth --repo-sftp-identity-agent is configured as 'none' (disabled) and --repo-sftp-private-key-file is " - "empty. Ssh authorization cannot continue, reconfigure --repo-sftp-identity-agent or " - "--repo-sftp-private-key-file appropriately."); + "ssh authorization cannot continue, --repo-sftp-identity-agent is configured as 'none' (disabled) and " + "--repo-sftp-private-key-file is not specified.\n HINT: configure --repo-sftp-identity-agent with an agent path" + " or --repo-sftp-private-key-file with a key file path."); } } diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 05eb3adeaa..58a89fc64f 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -621,9 +621,9 @@ testRun(void) storageSftpNewP( TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, .identityAgent = STRDEF("none")), ConfigError, - "sftp auth --repo-sftp-identity-agent is configured as 'none' (disabled) and --repo-sftp-private-key-file is empty. Ssh" - " authorization cannot continue, reconfigure --repo-sftp-identity-agent or --repo-sftp-private-key-file " - "appropriately."); + "ssh authorization cannot continue, --repo-sftp-identity-agent is configured as 'none' (disabled) and " + "--repo-sftp-private-key-file is not specified.\n HINT: configure --repo-sftp-identity-agent with an agent path or " + "--repo-sftp-private-key-file with a key file path."); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("public key from file auth failure, no public key"); From 4ccfa47962958860e73bfed2508b98ee8fb1dba8 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 00:24:13 -0400 Subject: [PATCH 09/20] Allow for multiple private key files Refactor ssh agent Add option to disable authorization via agent Attempt to authenticate via key file first If not authenticated via key file and agent not disabled, attempt to authenticate via agent --- src/build/config/config.yaml | 10 +- src/build/help/help.xml | 31 +- src/config/config.auto.h | 3 +- src/config/parse.auto.c.inc | 90 +++- src/storage/sftp/helper.c | 9 +- src/storage/sftp/storage.c | 156 +++--- src/storage/sftp/storage.h | 7 +- test/src/common/harnessLibSsh2.c | 2 +- test/src/module/command/helpTest.c | 1 + test/src/module/storage/sftpTest.c | 775 ++++++++++++++++++++++------- 10 files changed, 820 insertions(+), 264 deletions(-) diff --git a/src/build/config/config.yaml b/src/build/config/config.yaml index 3e2e525216..181eb8e637 100644 --- a/src/build/config/config.yaml +++ b/src/build/config/config.yaml @@ -2447,7 +2447,7 @@ option: repo-sftp-private-key-file: section: global group: repo - type: string + type: list required: false command: repo-type depend: repo-sftp-host @@ -2469,6 +2469,14 @@ option: command: repo-type depend: repo-sftp-host + repo-sftp-use-ssh-agent: + section: global + group: repo + type: boolean + default: true + command: repo-type + depend: repo-sftp-host + repo-storage-verify-tls: section: global group: repo diff --git a/src/build/help/help.xml b/src/build/help/help.xml index a2817395f4..3d3429e533 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1126,7 +1126,17 @@ pg-backup
- + + SFTP identity agent. + +

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Arguments to repo-sftp-identity-agent may use tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

+
+ + /var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket + +
+ + SFTP known hosts file. @@ -1147,7 +1157,9 @@ SFTP private key file. -

SFTP private key file used for authentication.

+

SFTP private key file used for authentication. The {[dash]}-repo-sftp-private-key-file option can be passed multiple times to specify more than one private key file.

+

NOTE: If {[dash]}-repo-sftp-public-key-file is not specified, the public key path will be generated by appending .pub to the private key path and paired with it's private key for authentication. If it is specified, then it will be paired with each private key to attempt authentication.

+

NOTE: libssh2 versions before 1.9.0 expect a PEM format keypair, ssh-keygen -m PEM -t rsa -P will generate a PEM keypair without a passphrase.

~/.ssh/id_ed25519 @@ -1167,12 +1179,25 @@ SFTP public key file. -

SFTP public key file used for authentication. Optional if compiled against OpenSSL, required if compiled against a different library.

+

SFTP public key file used for authentication. Optional if compiled against OpenSSL, required if compiled against a different library. If a public key file is specified, it will be paired with each private key file during authorization.

+

NOTE: libssh2 versions before 1.9.0 expect a PEM format keypair, ssh-keygen -m PEM -t rsa -P will generate a PEM keypair without a passphrase.

~/.ssh/id_ed25519.pub
+ + SFTP use ssh agent. + + +

When enabled, if not already authenticated via a private key file, an attempt will be made to authenticate via ssh-agent.

+
+ + yes + no + +
+ Repository storage CA file. diff --git a/src/config/config.auto.h b/src/config/config.auto.h index b6bdfcfca3..661ce525f0 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 181 /*********************************************************************************************************************************** Option value constants @@ -529,6 +529,7 @@ typedef enum cfgOptRepoSftpPrivateKeyFile, cfgOptRepoSftpPrivateKeyPassphrase, cfgOptRepoSftpPublicKeyFile, + cfgOptRepoSftpUseSshAgent, cfgOptRepoStorageCaFile, cfgOptRepoStorageCaPath, cfgOptRepoStorageHost, diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 9f5c2fba48..41ff2f3445 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8575,10 +8575,11 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = PARSE_RULE_OPTION // opt/repo-sftp-private-key-file ( // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_NAME("repo-sftp-private-key-file"), // opt/repo-sftp-private-key-file - PARSE_RULE_OPTION_TYPE(cfgOptTypeString), // opt/repo-sftp-private-key-file + PARSE_RULE_OPTION_TYPE(cfgOptTypeList), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_REQUIRED(false), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-private-key-file + PARSE_RULE_OPTION_MULTI(true), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-private-key-file // opt/repo-sftp-private-key-file @@ -8813,6 +8814,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-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_NAME("repo-sftp-use-ssh-agent"), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_TYPE(cfgOptTypeBoolean), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_NEGATE(true), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_REQUIRED(true), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTIONAL // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-use-ssh-agent + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // opt/repo-sftp-use-ssh-agent + PARSE_RULE_OPTIONAL_DEFAULT // opt/repo-sftp-use-ssh-agent + ( // opt/repo-sftp-use-ssh-agent + PARSE_RULE_VAL_BOOL_TRUE, // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + ), // opt/repo-sftp-use-ssh-agent + // ----------------------------------------------------------------------------------------------------------------------------- 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 @@ -11069,6 +11156,7 @@ static const uint8_t optionResolveOrder[] = cfgOptRepoSftpPrivateKeyFile, // opt-resolve-order cfgOptRepoSftpPrivateKeyPassphrase, // opt-resolve-order cfgOptRepoSftpPublicKeyFile, // opt-resolve-order + cfgOptRepoSftpUseSshAgent, // 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 02f8c7ad08..33c62ad05b 100644 --- a/src/storage/sftp/helper.c +++ b/src/storage/sftp/helper.c @@ -27,20 +27,21 @@ storageSftpHelper(const unsigned int repoIdx, const bool write, StoragePathExpre MEM_CONTEXT_TEMP_BEGIN() { const StringList *const knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)); + const StringList *const privKeys = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)); MEM_CONTEXT_PRIOR_BEGIN() { result = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), - cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .write = write, - .pathExpressionFunction = pathExpressionCallback, .modeFile = STORAGE_MODE_FILE_DEFAULT, + cfgOptionUInt64(cfgOptIoTimeout), privKeys, cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), + .write = write, .pathExpressionFunction = pathExpressionCallback, .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .hostFingerprint = cfgOptionIdxStrNull(cfgOptRepoSftpHostFingerprint, repoIdx), - .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), .knownHosts = knownHosts); + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx), .knownHosts = knownHosts); } MEM_CONTEXT_PRIOR_END(); } diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 4ca264abf1..fa1d657c17 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -607,6 +607,40 @@ storageSftpExpandTildePath(const String *const tildePath) FUNCTION_TEST_RETURN(STRING, result); } +/*********************************************************************************************************************************** +Expand any leading tilde filepaths in a path list. If a path is not a leading tilde path it is returned as is. +***********************************************************************************************************************************/ +static StringList * +storageSftpExpandFilePaths(const StringList *const pathList) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(STRING_LIST, pathList); + FUNCTION_LOG_END(); + + StringList *const result = strLstNew(); + + MEM_CONTEXT_TEMP_BEGIN() + { + // Process the list entries and add them to the result list + for (unsigned int listIdx = 0; listIdx < strLstSize(pathList); listIdx++) + { + // Get the trimmed file path and add it to the result list + const String *const filePath = strTrim(strLstGet(pathList, listIdx)); + + if (strBeginsWithZ(filePath, "~/")) + { + // Expand leading tilde and add to the result list + strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); + } + else + strLstAdd(result, filePath); + } + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_LOG_RETURN(STRING_LIST, result); +} + /**********************************************************************************************************************************/ // Helper function to get info for a file if it exists. This logic can't live directly in storageSftpList() because there is a race // condition where a file might exist while listing the directory but it is gone before stat() can be called. In order to get @@ -1093,7 +1127,7 @@ static const StorageInterface storageInterfaceSftp = FN_EXTERN Storage * storageSftpNew( const String *const path, const String *const host, const unsigned int port, const String *const user, - const TimeMSec timeout, const String *const keyPriv, const StringId hostKeyHashType, const StorageSftpNewParam param) + const TimeMSec timeout, const StringList *const privKeys, const StringId hostKeyHashType, const StorageSftpNewParam param) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(STRING, path); @@ -1101,7 +1135,7 @@ storageSftpNew( FUNCTION_LOG_PARAM(UINT, port); FUNCTION_LOG_PARAM(STRING, user); FUNCTION_LOG_PARAM(TIME_MSEC, timeout); - FUNCTION_LOG_PARAM(STRING, keyPriv); + FUNCTION_LOG_PARAM(STRING_LIST, privKeys); FUNCTION_LOG_PARAM(STRING_ID, hostKeyHashType); FUNCTION_LOG_PARAM(STRING, param.hostFingerprint); FUNCTION_LOG_PARAM(STRING_ID, param.hostKeyCheckType); @@ -1112,6 +1146,7 @@ storageSftpNew( FUNCTION_LOG_PARAM(MODE, param.modeFile); FUNCTION_LOG_PARAM(MODE, param.modePath); FUNCTION_LOG_PARAM(FUNCTIONP, param.pathExpressionFunction); + FUNCTION_LOG_PARAM(BOOL, param.useSshAgent); FUNCTION_LOG_PARAM(BOOL, param.write); FUNCTION_LOG_END(); @@ -1327,8 +1362,57 @@ storageSftpNew( libssh2_knownhost_free(knownHostsList); } - // Authenticate via ssh agent if no private key is provided and ssh agent is not explicitely disabled - if (keyPriv == NULL && (param.identityAgent == NULL || !strEqZ(strLower(strTrim(strDup(param.identityAgent))), "none"))) + // Attempt to authenticate with any provided private keys + bool authSuccess = false; + + if (!strLstEmpty(privKeys)) + { + // Normalize private keys to absolute paths + StringList *const privateKeys = storageSftpExpandFilePaths(privKeys); + + // If provided a public key normalize it if necessary + String *const pubKeyPath = + param.keyPub != NULL && + regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); + + // Attempt to authenticate with each private key + for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) + { + const String *const privateKey = strLstGet(privateKeys, listIdx); + + // If a public key has been provided use only that public key, otherwise use the private key with a .pub extension + do + { + rc = libssh2_userauth_publickey_fromfile( + this->session, strZ(user), + pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), + strZ(privateKey), strZNull(param.keyPassphrase)); + } + while (storageSftpWaitFd(this, rc)); + + // Log the result of the authentication attempt + if (rc != 0) + if (rc == LIBSSH2_ERROR_EAGAIN) + LOG_DETAIL_FMT("timeout during public key authentication"); + else + LOG_DETAIL_FMT( + "public key authentication with username %s and key %s failed [%d]", strZ(user), strZ(privateKey), rc); + else + { + authSuccess = true; + + LOG_DETAIL_FMT("public key authentication with username %s and key %s succeeded", strZ(user), strZ(privateKey)); + break; + } + } + + // Free the private key list, and the public key path + strLstFree(privateKeys); + strFree(pubKeyPath); + } + + // Attempt to authenticate with agent if not authenticated and agent enabled + if (authSuccess == false && param.useSshAgent == true) { // Init the libssh2 agent this->agent = libssh2_agent_init(this->session); @@ -1359,20 +1443,16 @@ storageSftpNew( #endif } + // Attempt to connect to the agent if ((rc = libssh2_agent_connect(this->agent)) != 0) { rc = libssh2_session_last_error(this->session, &ssh2ErrMsg, &ssh2ErrMsgLen, 0); - // Does the version of libssh2 (>= 1.9.0) support the libssh2_agent_get_identity_path function -#if LIBSSH2_VERSION_NUM >= 0x010900 - const char *const identity_agent_path = libssh2_agent_get_identity_path(this->agent); -#else - const char *const identity_agent_path = NULL; -#endif THROW_FMT( ServiceError, "failure connecting to ssh-agent %s[%d]%s", - identity_agent_path == NULL ? "" : zNewFmt("'%s' ", identity_agent_path), rc, zNewFmt(": %s", ssh2ErrMsg)); + param.identityAgent == NULL ? "" : zNewFmt("'%s' ", strZ(param.identityAgent)), rc, + zNewFmt(": %s", ssh2ErrMsg)); } if ((rc = libssh2_agent_list_identities(this->agent)) != 0) @@ -1405,60 +1485,22 @@ storageSftpNew( LOG_DETAIL_FMT("ssh-agent authentication with username %s failed [%d]", strZ(user), rc); else { + authSuccess = true; + LOG_DETAIL_FMT("ssh-agent authentication with username %s succeeded", strZ(user)); break; } prev_identity = identity; } - - if (rc != 0) - THROW_FMT(ServiceError, "ssh-agent authentication failure [%d]", rc); } - else - { - if (keyPriv != NULL) - { - // 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)); - - strFree(privKeyPath); - strFree(pubKeyPath); - - 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")); - } - } - else - { - THROW_FMT( - ConfigError, - "ssh authorization cannot continue, --repo-sftp-identity-agent is configured as 'none' (disabled) and " - "--repo-sftp-private-key-file is not specified.\n HINT: configure --repo-sftp-identity-agent with an agent path" - " or --repo-sftp-private-key-file with a key file path."); - } + if (authSuccess == false) + { + storageSftpEvalLibSsh2Error( + rc, libssh2_sftp_last_error(this->sftpSession), &ServiceError, + rc != 1 ? STRDEF("ssh authentication failed") : STRDEF("ssh authentication failed, reached end of public keys"), + NULL); } // Init the sftp session diff --git a/src/storage/sftp/storage.h b/src/storage/sftp/storage.h index 00785bcc39..06902fd1f2 100644 --- a/src/storage/sftp/storage.h +++ b/src/storage/sftp/storage.h @@ -37,13 +37,14 @@ typedef struct StorageSftpNewParam const String *hostFingerprint; const String *identityAgent; const StringList *knownHosts; + const bool useSshAgent; } StorageSftpNewParam; -#define storageSftpNewP(path, host, port, user, timeout, keyPriv, hostKeyHashType, ...) \ - storageSftpNew(path, host, port, user, timeout, keyPriv, hostKeyHashType, (StorageSftpNewParam){VAR_PARAM_INIT, __VA_ARGS__}) +#define storageSftpNewP(path, host, port, user, timeout, privKeys, hostKeyHashType, ...) \ + storageSftpNew(path, host, port, user, timeout, privKeys, hostKeyHashType, (StorageSftpNewParam){VAR_PARAM_INIT, __VA_ARGS__}) FN_EXTERN Storage *storageSftpNew( - const String *path, const String *host, unsigned int port, const String *user, TimeMSec timeout, const String *keyPriv, + const String *path, const String *host, unsigned int port, const String *user, TimeMSec timeout, const StringList *privKeys, StringId hostKeyHashType, const StorageSftpNewParam param); #endif // HAVE_LIBSSH2 diff --git a/test/src/common/harnessLibSsh2.c b/test/src/common/harnessLibSsh2.c index f3c6d1b9a5..80b331c10b 100644 --- a/test/src/common/harnessLibSsh2.c +++ b/test/src/common/harnessLibSsh2.c @@ -223,7 +223,7 @@ libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent) { HrnLibSsh2 *hrnLibSsh2 = hrnLibSsh2ScriptRun(HRNLIBSSH2_AGENT_GET_IDENTITY_PATH, NULL, (HrnLibSsh2 *)agent); - return hrnLibSsh2->identity_agent; + return hrnLibSsh2->identity_agent == NULL ? NULL : hrnLibSsh2->identity_agent; } /*********************************************************************************************************************************** diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index ef4c514a29..e55308bb58 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -333,6 +333,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-use-ssh-agent SFTP use ssh agent [default=y]\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 58a89fc64f..299c9ad48a 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -66,6 +66,10 @@ testRun(void) // Install shim to manage true/false return for fdReady hrnFdReadyShimInstall(); + // Build default test private key list + StringList *privKeyList = strLstNew(); + strLstAdd(privKeyList, KEYPRIV); + // Directory and file that cannot be accessed to test permissions errors const String *fileNoPerm = STRDEF(TEST_PATH "/noperm/noperm"); String *pathNoPerm = strPath(fileNoPerm); @@ -91,7 +95,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, privKeyList, hashTypeSha1, .keyPub = KEYPUB, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT), ServiceError, "unable to init libssh2"); @@ -107,7 +111,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 5, privKeyList, hashTypeSha1, .keyPub = KEYPUB, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT), ServiceError, "unable to init libssh2 session"); @@ -128,7 +132,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, privKeyList, hashTypeSha1, .keyPub = KEYPUB, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT), ServiceError, "libssh2 handshake failed [-45]: Bad socket provided"); @@ -148,7 +152,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 100, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 100, privKeyList, hashTypeSha1, .keyPub = KEYPUB, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT), ServiceError, "timeout during libssh2 handshake [-37]"); @@ -167,7 +171,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, privKeyList, hashTypeSha1, .keyPub = KEYPUB, .hostFingerprint = STRDEF("3132333435363738393039383736353433323130"), .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_FINGERPRINT), ServiceError, "libssh2 hostkey hash failed: libssh2 errno [-7]"); @@ -185,7 +189,7 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 20, KEYPRIV, cipherTypeAes256Cbc, .keyPub = KEYPUB, + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 20, privKeyList, cipherTypeAes256Cbc, .keyPub = KEYPUB, .write = true, .hostKeyCheckType = SFTP_STRICT_HOSTKEY_CHECKING_STRICT), ServiceError, "requested ssh2 hostkey hash type (aes-256-cbc) not available"); @@ -204,6 +208,12 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING}, {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = -16}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = -1}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = 1}, // 1 == reached the end of public keys list {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK}, {.function = NULL} }); @@ -228,19 +238,16 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, - "public key authentication failed: libssh2 error [-16]\n" - "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"); + "ssh authentication failed, reached end of public keys: libssh2 error [1]"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("fingerprint mismatch"); @@ -273,13 +280,14 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "host [3132333435363738393039383736353433323130] and configured fingerprint (repo-sftp-host-fingerprint)" " [9132333435363738393039383736353433323130] do not match"); @@ -301,7 +309,16 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "failure initializing ssh-agent support [-6]: Unable to allocate space for agent connection"); @@ -318,15 +335,21 @@ testRun(void) {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_BAD_USE}, {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"no auth sock variable", .resultInt = LIBSSH2_ERROR_BAD_USE}, -#if LIBSSH2_VERSION_NUM >= 0x010900 - {.function = HRNLIBSSH2_AGENT_GET_IDENTITY_PATH}, -#endif {.function = NULL} }); TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "failure connecting to ssh-agent [-39]: no auth sock variable"); @@ -345,26 +368,57 @@ testRun(void) {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_AGENT_PROTOCOL}, {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"failed connecting with agent", .resultInt = LIBSSH2_ERROR_AGENT_PROTOCOL}, - {.function = HRNLIBSSH2_AGENT_GET_IDENTITY_PATH, .identity_agent = (char *)"/tmp/pgbackrest-ssh-agent"}, #endif {.function = NULL} }); + + // Load configuration + 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, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpIdentityAgent, "/tmp/pgbackrest-ssh-agent"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); #if LIBSSH2_VERSION_NUM >= 0x010900 TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, - .identityAgent = STRDEF("/tmp/pgbackrest-ssh-agent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "failure connecting to ssh-agent '/tmp/pgbackrest-ssh-agent' [-42]: failed connecting with agent"); #else TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, - .identityAgent = STRDEF("/tmp/pgbackrest-ssh-agent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif - // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_list_identities failure"); @@ -380,9 +434,34 @@ testRun(void) {.function = NULL} }); + // Load configuration + 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, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpUseSshAgent, "y"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "failure requesting identities to ssh-agent [-1]"); @@ -404,7 +483,17 @@ testRun(void) TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "failure obtaining identity from ssh-agent [-1]"); @@ -421,16 +510,27 @@ testRun(void) {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, - {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = -1}, - {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = 1}, // 1 == reached the end of public keys list + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED}, + {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = 1}, + {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK}, {.function = NULL} }); TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, - "ssh-agent authentication failure [1]"); + "ssh authentication failed, reached end of public keys: libssh2 error [1]"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - libssh2_agent_disconnect failure in free resources"); @@ -456,7 +556,17 @@ testRun(void) TEST_ASSIGN( storageTest, storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), "new storage (defaults)"); TEST_ERROR_FMT( memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), @@ -491,7 +601,17 @@ testRun(void) TEST_ASSIGN( storageTest, storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), "new storage (defaults)"); memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); @@ -499,6 +619,21 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - identityAgent populated tilde path"); + // Load configuration + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, "/tmp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpIdentityAgent, "~/.ssh/myagent"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + #if LIBSSH2_VERSION_NUM >= 0x010900 hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -526,8 +661,17 @@ testRun(void) TEST_ASSIGN( storageTest, storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, - .identityAgent = STRDEF("~/.ssh/myagent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), "new storage (defaults)"); memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); @@ -544,14 +688,38 @@ testRun(void) TEST_ERROR( storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, - .identityAgent = STRDEF("~/.ssh/myagent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - identityAgent populated full path"); + // Load configuration + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, "/tmp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpIdentityAgent, "/var/lib/postgresql/.ssh/myagent"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + #if LIBSSH2_VERSION_NUM >= 0x010900 hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -581,8 +749,17 @@ testRun(void) TEST_ASSIGN( storageTest, storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, - .identityAgent = STRDEF("/var/lib/postgresql/.ssh/myagent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), "new storage (defaults)"); memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))); @@ -599,34 +776,107 @@ testRun(void) TEST_ERROR( storageSftpNewP( - STRDEF("/tmp"), STRDEF("localhost"), 22, TEST_USER_STR, 5, NULL, hashTypeSha1, - .identityAgent = STRDEF("/var/lib/postgresql/.ssh/myagent")), + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), + .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), + .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), ServiceError, "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("known host init failure"); + + 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, .resultNull = true}, + {.function = NULL} + }); + + // Load configuration + 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "failure during libssh2_knownhost_init"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("libssh2_agent_userauth failure - identityAgent disabled (none) and no private key configured"); + TEST_TITLE("libssh2_session_hostkey fail - return NULL - hostKeyCheckType = yes"); 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_KNOWNHOST_INIT}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultNull = true}, + {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, {.function = NULL} }); + // Load configuration + 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + TEST_ERROR( storageSftpNewP( - TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1, .identityAgent = STRDEF("none")), - ConfigError, - "ssh authorization cannot continue, --repo-sftp-identity-agent is configured as 'none' (disabled) and " - "--repo-sftp-private-key-file is not specified.\n HINT: configure --repo-sftp-identity-agent with an agent path or " - "--repo-sftp-private-key-file with a key file path."); + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "libssh2_session_hostkey failed to get hostkey: libssh2 error [-7]"); // ------------------------------------------------------------------------------------------------------------------------- - TEST_TITLE("public key from file auth failure, no public key"); + TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_MISMATCH"); hrnLibSsh2ScriptSet((HrnLibSsh2 []) { @@ -637,10 +887,7 @@ testRun(void) {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 5}, {.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_MATCH}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",null,\"" KEYPRIV_CSTR "\",null]", .resultInt = -16}, - {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK}, + .resultInt = LIBSSH2_KNOWNHOST_CHECK_MISMATCH}, {.function = NULL} }); @@ -648,7 +895,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -656,13 +903,158 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, - "public key authentication failed: libssh2 error [-16]\n" - "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"); - TEST_RESULT_BOOL( - unsetenv("PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"), 0, "unset PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"); + "known hosts failure: 'localhost' mismatch in known hosts files: LIBSSH2_KNOWNHOST_CHECK_MISMATCH [1]: check type " + "[strict]"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_FAILURE"); + + 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 = 5}, + {.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_FAILURE}, + {.function = NULL} + }); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, "known hosts failure: 'localhost' LIBSSH2_KNOWNHOST_CHECK_FAILURE [3]: check type [strict]"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("knownhost_checkp failure LIBSSH2_KNOWNHOST_CHECK_NOTFOUND"); + + 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 = 5}, + {.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 = NULL} + }); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type" + " [strict]"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("read known_hosts file failure - empty files - log INFO on empty known_hosts files"); + + 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 = 0}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS_FILE_CSTR "\",1]", .resultInt = 0}, + {.function = HRNLIBSSH2_KNOWNHOST_READFILE, .param = "[\"" ETC_KNOWNHOSTS2_FILE_CSTR "\",1]", .resultInt = 0}, + {.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 = NULL} + }); + + // Load configuration + 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); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, + "known hosts failure: 'localhost' not found in known hosts files: LIBSSH2_KNOWNHOST_CHECK_NOTFOUND [2]: check type" + " [strict]"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("knownhost_checkp unknown failure type"); + + 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 = 5}, + {.function = HRNLIBSSH2_SESSION_HOSTKEY, .len = 20, .type = LIBSSH2_HOSTKEY_TYPE_RSA, .resultZ = HOSTKEY}, + {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]", + .resultInt = 5}, + {.function = NULL} + }); + + // Load configuration + 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + + TEST_ERROR( + storageSftpNewP( + cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), + cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(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), + .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), + ServiceError, "known hosts failure: 'localhost' unknown failure [5]: check type [strict]"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("public key from file LIBSSH2_ERROR_EAGAIN, failure"); @@ -681,6 +1073,7 @@ testRun(void) .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = LIBSSH2_ERROR_EAGAIN}, {.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING_WRITING}, + {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK}, {.function = NULL} }); @@ -702,7 +1095,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -710,7 +1103,7 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, - "timeout during public key authentication"); + "ssh authentication failed: libssh2 error [-37]"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("sftp session init failure ssh2 error"); @@ -740,7 +1133,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -778,7 +1171,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -819,7 +1212,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -845,7 +1238,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -894,7 +1287,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -953,7 +1346,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1019,7 +1412,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1073,7 +1466,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1126,7 +1519,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1202,7 +1595,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1265,7 +1658,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1322,7 +1715,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1380,7 +1773,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1438,7 +1831,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1496,7 +1889,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1553,7 +1946,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1605,7 +1998,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1659,7 +2052,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1708,7 +2101,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1737,7 +2130,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1762,7 +2155,7 @@ testRun(void) {.function = HRNLIBSSH2_KNOWNHOST_CHECKP, .param = "[\"localhost\",22,\"" HOSTKEY "\",20,65537]", .resultInt = LIBSSH2_KNOWNHOST_CHECK_MATCH}, {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",null,\"" KEYPRIV_CSTR "\",null]", .resultInt = 0}, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = 0}, {.function = HRNLIBSSH2_SFTP_INIT}, HRNLIBSSH2_MACRO_SHUTDOWN() }); @@ -1772,7 +2165,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1838,7 +2231,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1886,7 +2279,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1937,7 +2330,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -1990,7 +2383,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2038,7 +2431,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = 0600, .modePath = 0700, .write = true, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2098,7 +2491,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2106,11 +2499,7 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, - "public key authentication failed: libssh2 error [-16]\n" - "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"); + "ssh authentication failed: libssh2 error [-16]"); TEST_RESULT_BOOL( unsetenv("PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"), 0, "unset PGBACKREST_REPO1_SFTP_PRIVATE_KEY_PASSPHRASE"); @@ -2204,7 +2593,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2291,7 +2680,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2318,7 +2707,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2360,7 +2749,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2384,7 +2773,7 @@ testRun(void) Storage *storageRootNoPath = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2506,7 +2895,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2826,7 +3215,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -2968,7 +3357,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3084,7 +3473,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3244,7 +3633,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3404,7 +3793,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3574,7 +3963,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3715,7 +4104,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3786,7 +4175,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3919,7 +4308,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -3993,7 +4382,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4039,7 +4428,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4182,7 +4571,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4255,7 +4644,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4447,7 +4836,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4570,7 +4959,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4603,7 +4992,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4636,7 +5025,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4695,7 +5084,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4752,7 +5141,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4786,7 +5175,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4814,7 +5203,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4847,7 +5236,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4881,7 +5270,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4914,7 +5303,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4946,7 +5335,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -4978,7 +5367,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5029,7 +5418,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5065,7 +5454,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5100,7 +5489,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5140,7 +5529,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5176,7 +5565,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5214,7 +5603,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5257,7 +5646,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5299,7 +5688,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5340,7 +5729,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5382,7 +5771,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5423,7 +5812,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5459,7 +5848,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5494,7 +5883,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5535,7 +5924,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5574,7 +5963,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5612,7 +6001,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5655,7 +6044,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5690,7 +6079,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5727,7 +6116,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5771,7 +6160,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5815,7 +6204,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5852,7 +6241,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5887,7 +6276,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5918,7 +6307,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5963,7 +6352,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -5991,7 +6380,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6020,7 +6409,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6054,7 +6443,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6086,7 +6475,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6118,7 +6507,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6154,7 +6543,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6184,7 +6573,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6213,7 +6602,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6245,7 +6634,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6279,7 +6668,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6310,7 +6699,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6362,7 +6751,7 @@ testRun(void) Storage *storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6390,7 +6779,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6420,7 +6809,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6449,7 +6838,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6478,7 +6867,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6509,7 +6898,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6551,7 +6940,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6587,7 +6976,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6620,7 +7009,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6675,7 +7064,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6752,7 +7141,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6855,7 +7244,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -6930,7 +7319,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7004,7 +7393,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7091,7 +7480,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7190,7 +7579,7 @@ testRun(void) storageTest = storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7512,7 +7901,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7543,7 +7932,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7575,7 +7964,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7611,7 +8000,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7647,7 +8036,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7681,7 +8070,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7710,7 +8099,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7739,7 +8128,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7769,7 +8158,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7800,7 +8189,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7831,7 +8220,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), @@ -7863,7 +8252,7 @@ testRun(void) storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), cfgOptionIdxUInt(cfgOptRepoSftpHostPort, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHostUser, repoIdx), - cfgOptionUInt64(cfgOptIoTimeout), cfgOptionIdxStr(cfgOptRepoSftpPrivateKeyFile, repoIdx), + cfgOptionUInt64(cfgOptIoTimeout), strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpPrivateKeyFile, repoIdx)), cfgOptionIdxStrId(cfgOptRepoSftpHostKeyHashType, repoIdx), .modeFile = STORAGE_MODE_FILE_DEFAULT, .modePath = STORAGE_MODE_PATH_DEFAULT, .keyPub = cfgOptionIdxStrNull(cfgOptRepoSftpPublicKeyFile, repoIdx), .keyPassphrase = cfgOptionIdxStrNull(cfgOptRepoSftpPrivateKeyPassphrase, repoIdx), From 6f85b9f259d114a1d66d3f07e439f85071e9669a Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 00:34:23 -0400 Subject: [PATCH 10/20] Change repo-sftp-use-ssh-agent from 'no' to 'n' --- 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 3d3429e533..aca0c275b3 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1194,7 +1194,7 @@ yes - no + n From a0e793d44d94c49304560ba57893c97cd43a1a4f Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 00:37:02 -0400 Subject: [PATCH 11/20] Change repo-sftp-use-ssh-agent default from 'yes' to 'y' --- 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 aca0c275b3..188a43af64 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1193,7 +1193,7 @@

When enabled, if not already authenticated via a private key file, an attempt will be made to authenticate via ssh-agent.

- yes + y n
From fb27618ed217a65e0c7b811a9eb9d91ce238f137 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 21:37:29 -0400 Subject: [PATCH 12/20] Refactor code Attempt to authenticate via default identity files if no private key file is provided Update tests --- src/storage/sftp/storage.c | 156 ++++++++++++++++------------- test/src/common/harnessLibSsh2.h | 10 ++ test/src/module/storage/sftpTest.c | 120 ++++++++++++++++++++++ 3 files changed, 215 insertions(+), 71 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index fa1d657c17..01bd88a4cb 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -540,6 +540,26 @@ storageSftpInfo(THIS_VOID, const String *const file, const StorageInfoLevel leve FUNCTION_LOG_RETURN(STORAGE_INFO, result); } +/**********************************************************************************************************************************/ +static String * +storageSftpExpandTildePath(const String *const tildePath) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRING, tildePath); + FUNCTION_TEST_END(); + + String *const result = strNew(); + + // Append to user home directory path substring after the tilde + MEM_CONTEXT_TEMP_BEGIN() + { + strCatFmt(result, "%s%s", strZ(userHome()), strZ(strSub(tildePath, (size_t)strChr(tildePath, '~') + 1))); + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_TEST_RETURN(STRING, result); +} + /*********************************************************************************************************************************** Build known hosts file list. If knownHosts is empty build the default file list, otherwise build the list provided. knownHosts requires full path and/or leading tilde path entries. @@ -573,9 +593,8 @@ storageSftpKnownHostsFilesList(const StringList *const knownHosts) if (strBeginsWithZ(filePath, "~/")) { - // Replace leading tilde with space, trim space, prepend user home path and add to the result list - strLstAddFmt( - result, "%s%s", strZ(userHome()), strZ(strTrim(strSub(filePath, (size_t)strChr(filePath, '~') + 1)))); + // Expand leading tilde and add to the result list + strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); } else strLstAdd(result, filePath); @@ -587,53 +606,47 @@ storageSftpKnownHostsFilesList(const StringList *const knownHosts) FUNCTION_LOG_RETURN(STRING_LIST, result); } -/**********************************************************************************************************************************/ -static String * -storageSftpExpandTildePath(const String *const tildePath) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(STRING, tildePath); - FUNCTION_TEST_END(); - - String *const result = strNew(); - - // Append to user home directory path substring after the tilde - MEM_CONTEXT_TEMP_BEGIN() - { - strCatFmt(result, "%s%s", strZ(userHome()), strZ(strSub(tildePath, (size_t)strChr(tildePath, '~') + 1))); - } - MEM_CONTEXT_TEMP_END(); - - FUNCTION_TEST_RETURN(STRING, result); -} - /*********************************************************************************************************************************** -Expand any leading tilde filepaths in a path list. If a path is not a leading tilde path it is returned as is. +Build identity file list. If privKeys is empty build the default file list, otherwise build the list provided. privKeys +requires full path and/or leading tilde path entries. ***********************************************************************************************************************************/ static StringList * -storageSftpExpandFilePaths(const StringList *const pathList) +storageSftpIdentityFilesList(const StringList *const privKeys) { FUNCTION_LOG_BEGIN(logLevelDebug); - FUNCTION_LOG_PARAM(STRING_LIST, pathList); + FUNCTION_LOG_PARAM(STRING_LIST, privKeys); FUNCTION_LOG_END(); StringList *const result = strLstNew(); MEM_CONTEXT_TEMP_BEGIN() { - // Process the list entries and add them to the result list - for (unsigned int listIdx = 0; listIdx < strLstSize(pathList); listIdx++) + if (strLstEmpty(privKeys)) { - // Get the trimmed file path and add it to the result list - const String *const filePath = strTrim(strLstGet(pathList, listIdx)); - - if (strBeginsWithZ(filePath, "~/")) + // Create default file list + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_dsa"); + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa"); + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa_sk"); + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ed25519"); + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ed25519_sk"); + strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_rsa"); + } + else + { + // Process the known host list entries and add them to the result list + for (unsigned int listIdx = 0; listIdx < strLstSize(privKeys); listIdx++) { - // Expand leading tilde and add to the result list - strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); + // Get the trimmed file path and add it to the result list + const String *const filePath = strTrim(strLstGet(privKeys, listIdx)); + + if (strBeginsWithZ(filePath, "~/")) + { + // Expand leading tilde and add to the result list + strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); + } + else + strLstAdd(result, filePath); } - else - strLstAdd(result, filePath); } } MEM_CONTEXT_TEMP_END(); @@ -1365,52 +1378,53 @@ storageSftpNew( // Attempt to authenticate with any provided private keys bool authSuccess = false; - if (!strLstEmpty(privKeys)) - { - // Normalize private keys to absolute paths - StringList *const privateKeys = storageSftpExpandFilePaths(privKeys); + // Build/normalize private keys list + StringList *const privateKeys = storageSftpIdentityFilesList(privKeys); - // If provided a public key normalize it if necessary - String *const pubKeyPath = - param.keyPub != NULL && - regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); + // If provided a public key normalize it if necessary + String *const pubKeyPath = + param.keyPub != NULL && + regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); - // Attempt to authenticate with each private key - for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) - { - const String *const privateKey = strLstGet(privateKeys, listIdx); + // Attempt to authenticate with each private key + for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) + { + const String *const privateKey = strLstGet(privateKeys, listIdx); - // If a public key has been provided use only that public key, otherwise use the private key with a .pub extension - do - { - rc = libssh2_userauth_publickey_fromfile( - this->session, strZ(user), - pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), - strZ(privateKey), strZNull(param.keyPassphrase)); - } - while (storageSftpWaitFd(this, rc)); + // If a public key has been provided use only that public key, otherwise use the private key with a .pub extension + do + { + rc = libssh2_userauth_publickey_fromfile( + this->session, strZ(user), + pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), + strZ(privateKey), strZNull(param.keyPassphrase)); + } + while (storageSftpWaitFd(this, rc)); - // Log the result of the authentication attempt - if (rc != 0) - if (rc == LIBSSH2_ERROR_EAGAIN) - LOG_DETAIL_FMT("timeout during public key authentication"); - else - LOG_DETAIL_FMT( - "public key authentication with username %s and key %s failed [%d]", strZ(user), strZ(privateKey), rc); + // Log the result of the authentication attempt + if (rc != 0) + { + if (rc == LIBSSH2_ERROR_EAGAIN) + LOG_DETAIL_FMT("timeout during public key authentication"); else { - authSuccess = true; - - LOG_DETAIL_FMT("public key authentication with username %s and key %s succeeded", strZ(user), strZ(privateKey)); - break; + LOG_DETAIL_FMT( + "public key authentication with username %s and key %s failed [%d]", strZ(user), strZ(privateKey), rc); } } + else + { + authSuccess = true; - // Free the private key list, and the public key path - strLstFree(privateKeys); - strFree(pubKeyPath); + LOG_DETAIL_FMT("public key authentication with username %s and key %s succeeded", strZ(user), strZ(privateKey)); + break; + } } + // Free the private key list, and the public key path + strLstFree(privateKeys); + strFree(pubKeyPath); + // Attempt to authenticate with agent if not authenticated and agent enabled if (authSuccess == false && param.useSshAgent == true) { diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index 16689c7bce..9546f5c511 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -25,6 +25,16 @@ libssh2 authorization constants #define KEYPUB STRDEF("/home/" TEST_USER "/.ssh/id_rsa.pub") #define KEYPRIV_CSTR "/home/" TEST_USER "/.ssh/id_rsa" #define KEYPUB_CSTR "/home/" TEST_USER "/.ssh/id_rsa.pub" +#define KEYPRIV_DSA_CSTR "/home/" TEST_USER "/.ssh/id_dsa" +#define KEYPUB_DSA_CSTR "/home/" TEST_USER "/.ssh/id_dsa.pub" +#define KEYPRIV_ECDSA_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa" +#define KEYPUB_ECDSA_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa.pub" +#define KEYPRIV_ECDSA_SK_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa_sk" +#define KEYPUB_ECDSA_SK_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa_sk.pub" +#define KEYPRIV_ED25519_CSTR "/home/" TEST_USER "/.ssh/id_ed25519" +#define KEYPUB_ED25519_CSTR "/home/" TEST_USER "/.ssh/id_ed25519.pub" +#define KEYPRIV_ED25519_SK_CSTR "/home/" TEST_USER "/.ssh/id_ed25519_sk" +#define KEYPUB_ED25519_SK_CSTR "/home/" TEST_USER "/.ssh/id_ed25519_sk.pub" #define KNOWNHOSTS_FILE_CSTR "/home/" TEST_USER "/.ssh/known_hosts" #define KNOWNHOSTS2_FILE_CSTR "/home/" TEST_USER "/.ssh/known_hosts2" #define ETC_KNOWNHOSTS_FILE_CSTR "/etc/ssh/ssh_known_hosts" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 299c9ad48a..dc907d5888 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -301,12 +301,31 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT, .resultNull = true}, {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"Unable to allocate space for agent connection", .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = NULL} }); + // Load configuration + 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, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + TEST_ERROR( storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), @@ -331,6 +350,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_BAD_USE}, {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .errMsg = (char *)"no auth sock variable", @@ -362,6 +384,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, #if LIBSSH2_VERSION_NUM >= 0x010900 {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, @@ -383,6 +408,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); hrnCfgArgRawZ(argList, cfgOptRepoSftpIdentityAgent, "/tmp/pgbackrest-ssh-agent"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); @@ -428,6 +455,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = -1}, @@ -445,6 +475,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); hrnCfgArgRawZ(argList, cfgOptRepoSftpUseSshAgent, "y"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); @@ -474,6 +506,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, @@ -506,6 +541,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, @@ -541,6 +579,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, @@ -551,6 +592,23 @@ testRun(void) {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = -1}, {.function = NULL} }); + + // Load configuration + argList = strLstNew(); + hrnCfgArgRawZ(argList, cfgOptStanza, "test"); + hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); + hrnCfgArgRawZ(argList, cfgOptRepo, "1"); + hrnCfgArgRawZ(argList, cfgOptRepoPath, "/tmp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostUser, TEST_USER); + hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + Storage *storageTest = NULL; TEST_ASSIGN( @@ -582,6 +640,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, @@ -630,6 +691,8 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyCheckType, "fingerprint"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, "~/.ssh/id_rsa"); + hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, "~/.ssh/id_rsa.pub"); hrnCfgArgRawZ(argList, cfgOptRepoSftpHostFingerprint, "3132333435363738393039383736353433323130"); hrnCfgArgRawZ(argList, cfgOptRepoSftpIdentityAgent, "~/.ssh/myagent"); HRN_CFG_LOAD(cfgCmdArchiveGet, argList); @@ -641,6 +704,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, @@ -682,6 +748,9 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = NULL} }); @@ -727,6 +796,24 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_DSA_CSTR "\",\"" KEYPRIV_DSA_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_CSTR "\",\"" KEYPRIV_ECDSA_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_SK_CSTR "\",\"" KEYPRIV_ECDSA_SK_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_SK_CSTR "\",\"" KEYPRIV_ED25519_SK_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, @@ -770,6 +857,24 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_DSA_CSTR "\",\"" KEYPRIV_DSA_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_CSTR "\",\"" KEYPRIV_ECDSA_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_SK_CSTR "\",\"" KEYPRIV_ECDSA_SK_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_SK_CSTR "\",\"" KEYPRIV_ED25519_SK_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, + .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", + .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = NULL} }); @@ -1129,6 +1234,21 @@ testRun(void) {.function = NULL} }); + // Load configuration + 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, cfgOptRepoSftpKnownHost, KNOWNHOSTS_FILE_CSTR); + HRN_CFG_LOAD(cfgCmdArchiveGet, argList); + TEST_ERROR( storageSftpNewP( cfgOptionIdxStr(cfgOptRepoPath, repoIdx), cfgOptionIdxStr(cfgOptRepoSftpHost, repoIdx), From e8cc4b3c0b9e3728039a21f75327d910191d4bb5 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 26 Sep 2023 00:38:25 -0400 Subject: [PATCH 13/20] Do not attempt to read non-existent default identity files, reduces noise in logs from read failures Update tests --- src/storage/sftp/storage.c | 32 ++++++++++++++++++++---------- test/src/module/storage/sftpTest.c | 17 ++++++++++------ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 01bd88a4cb..92b669daf0 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -623,27 +623,37 @@ storageSftpIdentityFilesList(const StringList *const privKeys) { if (strLstEmpty(privKeys)) { - // Create default file list - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_dsa"); - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa"); - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa_sk"); - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ed25519"); - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_ed25519_sk"); - strLstAddFmt(result, "%s%s", strZ(userHome()), "/.ssh/id_rsa"); + // Create default file list, do not include non-existent files, reduces log noise + const Storage *const sshStorage = + storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh"), .modeFile = 0600, .modePath = 0700); + + StringList *const sshDefaultIdentityFiles = strLstNew(); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_dsa"); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa"); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa_sk"); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ed25519"); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ed25519_sk"); + strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_rsa"); + + for (unsigned int listIdx = 0; listIdx < strLstSize(sshDefaultIdentityFiles); listIdx++) + { + const String *const filePath = strLstGet(sshDefaultIdentityFiles, listIdx); + + if (storageExistsP(sshStorage, filePath)) + strLstAdd(result, filePath); + } } else { - // Process the known host list entries and add them to the result list + // Process the privKey file list entries and add them to the result list for (unsigned int listIdx = 0; listIdx < strLstSize(privKeys); listIdx++) { // Get the trimmed file path and add it to the result list const String *const filePath = strTrim(strLstGet(privKeys, listIdx)); + // Expand leading tilde and add to the result list if (strBeginsWithZ(filePath, "~/")) - { - // Expand leading tilde and add to the result list strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); - } else strLstAdd(result, filePath); } diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index dc907d5888..107a0c5e68 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -774,6 +774,12 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - identityAgent populated full path"); + Storage *storageSsh = storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh"), .write = true); + HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_DSA_CSTR); + HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ECDSA_CSTR); + HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ECDSA_SK_CSTR); + HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ED25519_CSTR); + // Load configuration argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptStanza, "test"); @@ -808,9 +814,6 @@ testRun(void) {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_SK_CSTR "\",\"" KEYPRIV_ED25519_SK_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = LIBSSH2_ERROR_ALLOC}, @@ -869,9 +872,6 @@ testRun(void) {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_SK_CSTR "\",\"" KEYPRIV_ED25519_SK_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", .resultInt = LIBSSH2_ERROR_ALLOC}, @@ -895,6 +895,11 @@ testRun(void) ServiceError, "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif + HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_DSA_CSTR); + HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_CSTR); + HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_SK_CSTR); + HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ED25519_CSTR); + // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("known host init failure"); From ed906bf41bab21f30be474a0e9612d5f8ce2a2b6 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 26 Sep 2023 08:53:34 -0400 Subject: [PATCH 14/20] Add more detail re sftp private key --- src/build/help/help.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 188a43af64..8a68674937 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1126,7 +1126,7 @@ pg-backup - + SFTP identity agent.

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Arguments to repo-sftp-identity-agent may use tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

@@ -1136,7 +1136,7 @@
- + SFTP known hosts file. @@ -1157,7 +1157,7 @@ SFTP private key file. -

SFTP private key file used for authentication. The {[dash]}-repo-sftp-private-key-file option can be passed multiple times to specify more than one private key file.

+

SFTP private key file used for authentication. The {[dash]}-repo-sftp-private-key-file option can be passed multiple times to specify more than one private key file. If unspecified, will attempt authentication via any default private key files (~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519, ~/.ssh/id_ed25519_sk, ~/.ssh/id_rsa) that are present.

NOTE: If {[dash]}-repo-sftp-public-key-file is not specified, the public key path will be generated by appending .pub to the private key path and paired with it's private key for authentication. If it is specified, then it will be paired with each private key to attempt authentication.

NOTE: libssh2 versions before 1.9.0 expect a PEM format keypair, ssh-keygen -m PEM -t rsa -P will generate a PEM keypair without a passphrase.

@@ -1169,7 +1169,7 @@ SFTP private key passphrase. -

Passphrase used to access the private key. This is an optional feature when creating an SSH public/private key pair.

+

Passphrase used to access the private key. This is an optional feature when creating an SSH public/private key pair. If specified, it will be used with each key.

BeSureToGenerateAndUseASecurePassphrase @@ -1179,14 +1179,14 @@ SFTP public key file. -

SFTP public key file used for authentication. Optional if compiled against OpenSSL, required if compiled against a different library. If a public key file is specified, it will be paired with each private key file during authorization.

+

SFTP public key file used for authentication. Optional if compiled against OpenSSL, required if compiled against a different library. If a public key file is specified, it will be paired with each private key file during authentication.

NOTE: libssh2 versions before 1.9.0 expect a PEM format keypair, ssh-keygen -m PEM -t rsa -P will generate a PEM keypair without a passphrase.

~/.ssh/id_ed25519.pub
- + SFTP use ssh agent. From 63ae124ae3d0d9118b061cdecfe7e572cbdcb829 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 26 Sep 2023 15:15:34 -0400 Subject: [PATCH 15/20] Working ssh-agent implementation Will add code to attempt authentication via default private key files as a separate commit --- src/build/help/help.xml | 6 +- src/storage/sftp/storage.c | 108 ++++++++++++----------------- test/src/common/harnessLibSsh2.h | 10 --- test/src/module/storage/sftpTest.c | 40 ----------- 4 files changed, 46 insertions(+), 118 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 8a68674937..b04e65ad30 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1132,7 +1132,7 @@

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Arguments to repo-sftp-identity-agent may use tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

- /var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket + /var/lib/postgresql/.ssh/pgbackrest_ssh_identity_agent_socket
@@ -1157,7 +1157,7 @@ SFTP private key file. -

SFTP private key file used for authentication. The {[dash]}-repo-sftp-private-key-file option can be passed multiple times to specify more than one private key file. If unspecified, will attempt authentication via any default private key files (~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519, ~/.ssh/id_ed25519_sk, ~/.ssh/id_rsa) that are present.

+

SFTP private key file used for authentication. The {[dash]}-repo-sftp-private-key-file option can be passed multiple times to specify more than one private key file.

NOTE: If {[dash]}-repo-sftp-public-key-file is not specified, the public key path will be generated by appending .pub to the private key path and paired with it's private key for authentication. If it is specified, then it will be paired with each private key to attempt authentication.

NOTE: libssh2 versions before 1.9.0 expect a PEM format keypair, ssh-keygen -m PEM -t rsa -P will generate a PEM keypair without a passphrase.

@@ -1190,7 +1190,7 @@ SFTP use ssh agent. -

When enabled, if not already authenticated via a private key file, an attempt will be made to authenticate via ssh-agent.

+

When enabled, if not already authenticated via a private key file, an attempt will be made to authenticate via ssh-agent. The default agent is read from the SSH_AUTH_SOCK environment variable. The default agent may be overridden by using the repo-sftp-identity-agent setting if compiled against libssh2 version 1.9 or greater.

y diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 92b669daf0..b5eeae161c 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -607,8 +607,7 @@ storageSftpKnownHostsFilesList(const StringList *const knownHosts) } /*********************************************************************************************************************************** -Build identity file list. If privKeys is empty build the default file list, otherwise build the list provided. privKeys -requires full path and/or leading tilde path entries. +Build private key file list. privKeys requires full path and/or leading tilde path entries. ***********************************************************************************************************************************/ static StringList * storageSftpIdentityFilesList(const StringList *const privKeys) @@ -621,42 +620,17 @@ storageSftpIdentityFilesList(const StringList *const privKeys) MEM_CONTEXT_TEMP_BEGIN() { - if (strLstEmpty(privKeys)) + // Process the privKey file list entries and add them to the result list + for (unsigned int listIdx = 0; listIdx < strLstSize(privKeys); listIdx++) { - // Create default file list, do not include non-existent files, reduces log noise - const Storage *const sshStorage = - storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh"), .modeFile = 0600, .modePath = 0700); - - StringList *const sshDefaultIdentityFiles = strLstNew(); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_dsa"); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa"); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ecdsa_sk"); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ed25519"); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_ed25519_sk"); - strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_rsa"); - - for (unsigned int listIdx = 0; listIdx < strLstSize(sshDefaultIdentityFiles); listIdx++) - { - const String *const filePath = strLstGet(sshDefaultIdentityFiles, listIdx); + // Get the trimmed file path and add it to the result list + const String *const filePath = strTrim(strLstGet(privKeys, listIdx)); - if (storageExistsP(sshStorage, filePath)) - strLstAdd(result, filePath); - } - } - else - { - // Process the privKey file list entries and add them to the result list - for (unsigned int listIdx = 0; listIdx < strLstSize(privKeys); listIdx++) - { - // Get the trimmed file path and add it to the result list - const String *const filePath = strTrim(strLstGet(privKeys, listIdx)); - - // Expand leading tilde and add to the result list - if (strBeginsWithZ(filePath, "~/")) - strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); - else - strLstAdd(result, filePath); - } + // Expand leading tilde and add to the result list + if (strBeginsWithZ(filePath, "~/")) + strLstAddFmt(result, "%s", strZ(storageSftpExpandTildePath(filePath))); + else + strLstAdd(result, filePath); } } MEM_CONTEXT_TEMP_END(); @@ -1386,8 +1360,6 @@ storageSftpNew( } // Attempt to authenticate with any provided private keys - bool authSuccess = false; - // Build/normalize private keys list StringList *const privateKeys = storageSftpIdentityFilesList(privKeys); @@ -1396,42 +1368,47 @@ storageSftpNew( param.keyPub != NULL && regExpMatchOne(STRDEF("^ *~"), param.keyPub) ? storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub); - // Attempt to authenticate with each private key - for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) - { - const String *const privateKey = strLstGet(privateKeys, listIdx); + bool authSuccess = false; - // If a public key has been provided use only that public key, otherwise use the private key with a .pub extension - do + if (!strLstEmpty(privateKeys)) + { + // Attempt to authenticate with each private key + for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) { - rc = libssh2_userauth_publickey_fromfile( - this->session, strZ(user), - pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), - strZ(privateKey), strZNull(param.keyPassphrase)); - } - while (storageSftpWaitFd(this, rc)); + const String *const privateKey = strLstGet(privateKeys, listIdx); - // Log the result of the authentication attempt - if (rc != 0) - { - if (rc == LIBSSH2_ERROR_EAGAIN) - LOG_DETAIL_FMT("timeout during public key authentication"); - else + // If a public key has been provided use only that public key, otherwise use the private key with a .pub extension + do { - LOG_DETAIL_FMT( - "public key authentication with username %s and key %s failed [%d]", strZ(user), strZ(privateKey), rc); + rc = libssh2_userauth_publickey_fromfile( + this->session, strZ(user), + pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), + strZ(privateKey), strZNull(param.keyPassphrase)); } - } - else - { - authSuccess = true; + while (storageSftpWaitFd(this, rc)); - LOG_DETAIL_FMT("public key authentication with username %s and key %s succeeded", strZ(user), strZ(privateKey)); - break; + // Log the result of the authentication attempt + if (rc != 0) + { + if (rc == LIBSSH2_ERROR_EAGAIN) + LOG_DETAIL_FMT("timeout during public key authentication"); + else + { + LOG_DETAIL_FMT( + "public key authentication with username %s and key %s failed [%d]", strZ(user), strZ(privateKey), rc); + } + } + else + { + authSuccess = true; + + LOG_DETAIL_FMT("public key authentication with username %s and key %s succeeded", strZ(user), strZ(privateKey)); + break; + } } } - // Free the private key list, and the public key path + // Free private key list and public key path strLstFree(privateKeys); strFree(pubKeyPath); @@ -1447,6 +1424,7 @@ storageSftpNew( if (this->agent == NULL) { rc = libssh2_session_last_error(this->session, &ssh2ErrMsg, &ssh2ErrMsgLen, 0); + THROW_FMT(ServiceError, "failure initializing ssh-agent support [%d]: %s", rc, ssh2ErrMsg); } diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index 9546f5c511..16689c7bce 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -25,16 +25,6 @@ libssh2 authorization constants #define KEYPUB STRDEF("/home/" TEST_USER "/.ssh/id_rsa.pub") #define KEYPRIV_CSTR "/home/" TEST_USER "/.ssh/id_rsa" #define KEYPUB_CSTR "/home/" TEST_USER "/.ssh/id_rsa.pub" -#define KEYPRIV_DSA_CSTR "/home/" TEST_USER "/.ssh/id_dsa" -#define KEYPUB_DSA_CSTR "/home/" TEST_USER "/.ssh/id_dsa.pub" -#define KEYPRIV_ECDSA_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa" -#define KEYPUB_ECDSA_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa.pub" -#define KEYPRIV_ECDSA_SK_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa_sk" -#define KEYPUB_ECDSA_SK_CSTR "/home/" TEST_USER "/.ssh/id_ecdsa_sk.pub" -#define KEYPRIV_ED25519_CSTR "/home/" TEST_USER "/.ssh/id_ed25519" -#define KEYPUB_ED25519_CSTR "/home/" TEST_USER "/.ssh/id_ed25519.pub" -#define KEYPRIV_ED25519_SK_CSTR "/home/" TEST_USER "/.ssh/id_ed25519_sk" -#define KEYPUB_ED25519_SK_CSTR "/home/" TEST_USER "/.ssh/id_ed25519_sk.pub" #define KNOWNHOSTS_FILE_CSTR "/home/" TEST_USER "/.ssh/known_hosts" #define KNOWNHOSTS2_FILE_CSTR "/home/" TEST_USER "/.ssh/known_hosts2" #define ETC_KNOWNHOSTS_FILE_CSTR "/etc/ssh/ssh_known_hosts" diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 107a0c5e68..045fa7d17c 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -774,12 +774,6 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_userauth success - identityAgent populated full path"); - Storage *storageSsh = storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh"), .write = true); - HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_DSA_CSTR); - HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ECDSA_CSTR); - HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ECDSA_SK_CSTR); - HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_ED25519_CSTR); - // Load configuration argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptStanza, "test"); @@ -802,21 +796,6 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_DSA_CSTR "\",\"" KEYPRIV_DSA_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_CSTR "\",\"" KEYPRIV_ECDSA_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_SK_CSTR "\",\"" KEYPRIV_ECDSA_SK_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = HRNLIBSSH2_AGENT_SET_IDENTITY_PATH}, {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, @@ -860,21 +839,6 @@ testRun(void) {.function = HRNLIBSSH2_SESSION_INIT_EX, .param = "[null,null,null,null]"}, {.function = HRNLIBSSH2_SESSION_HANDSHAKE, .param = HANDSHAKE_PARAM, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_DSA_CSTR "\",\"" KEYPRIV_DSA_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_CSTR "\",\"" KEYPRIV_ECDSA_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ECDSA_SK_CSTR "\",\"" KEYPRIV_ECDSA_SK_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_ED25519_CSTR "\",\"" KEYPRIV_ED25519_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, - {.function = HRNLIBSSH2_USERAUTH_PUBLICKEY_FROMFILE_EX, - .param = "[\"" TEST_USER "\"," TEST_USER_LEN ",\"" KEYPUB_CSTR "\",\"" KEYPRIV_CSTR "\",null]", - .resultInt = LIBSSH2_ERROR_ALLOC}, {.function = HRNLIBSSH2_AGENT_INIT}, {.function = NULL} }); @@ -895,10 +859,6 @@ testRun(void) ServiceError, "libssh2 version " LIBSSH2_VERSION " does not support ssh-agent identity path, requires version 1.9 or greater"); #endif - HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_DSA_CSTR); - HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_CSTR); - HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_SK_CSTR); - HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ED25519_CSTR); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("known host init failure"); From 764bae38655955c4172f16c96ca1d12b89ec36cb Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 26 Sep 2023 15:40:44 -0400 Subject: [PATCH 16/20] Remove spurious empty lines, add missing space before ',' Fix formatting --- src/build/help/help.xml | 9 --------- src/storage/sftp/storage.c | 6 +++--- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index b04e65ad30..03db73cb0b 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1133,7 +1133,6 @@ /var/lib/postgresql/.ssh/pgbackrest_ssh_identity_agent_socket -
@@ -1144,13 +1143,6 @@ /home/postgres/.ssh/known_hosts - - SFTP identity agent. - -

Specifies the UNIX-domain socket used to communicate with the authentication agent. This option overrides the SSH_AUTH_SOCK environment variable and can be used to select a specific agent. Setting the socket name to none disables the use of an authentication agent. Arguments to repo-sftp-identity-agent may use tilde syntax to refer to a user's home directory. This option is not valid for versions of libssh2 prior to 1.9

-
- - /var/lib/postgresql/.ssh/.pgbackrest_ssh_identity_agent_socket
@@ -1195,7 +1187,6 @@ y n - diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index b5eeae161c..52ec1846a5 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1381,9 +1381,9 @@ storageSftpNew( do { rc = libssh2_userauth_publickey_fromfile( - this->session, strZ(user), - pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(),"%s.pub", strZ(privateKey))), - strZ(privateKey), strZNull(param.keyPassphrase)); + this->session, strZ(user), + pubKeyPath != NULL ? strZ(pubKeyPath) : strZ(strCatFmt(strNew(), "%s.pub", strZ(privateKey))), + strZ(privateKey), strZNull(param.keyPassphrase)); } while (storageSftpWaitFd(this, rc)); From bb3b6ec9000117369d10dfbdcdf2b5ede57dba27 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 12 Jan 2024 11:38:12 -0500 Subject: [PATCH 17/20] Finish rebase with main --- src/config/parse.auto.c.inc | 160 ++++++++++++++--------------- src/storage/sftp/storage.c | 8 +- test/src/module/storage/sftpTest.c | 16 ++- 3 files changed, 97 insertions(+), 87 deletions(-) diff --git a/src/config/parse.auto.c.inc b/src/config/parse.auto.c.inc index 41ff2f3445..35836901d9 100644 --- a/src/config/parse.auto.c.inc +++ b/src/config/parse.auto.c.inc @@ -8410,6 +8410,86 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-host-user ), // opt/repo-sftp-host-user // ----------------------------------------------------------------------------------------------------------------------------- + PARSE_RULE_OPTION // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_NAME("repo-sftp-identity-agent"), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_TYPE(cfgOptTypeString), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_REQUIRED(false), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent + PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-identity-agent + ( // opt/repo-sftp-identity-agent + PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-identity-agent + PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + ), // opt/repo-sftp-identity-agent + // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-sftp-known-host ( // opt/repo-sftp-known-host PARSE_RULE_OPTION_NAME("repo-sftp-known-host"), // opt/repo-sftp-known-host @@ -8492,86 +8572,6 @@ static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] = ), // opt/repo-sftp-known-host ), // opt/repo-sftp-known-host // ----------------------------------------------------------------------------------------------------------------------------- - PARSE_RULE_OPTION // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_NAME("repo-sftp-identity-agent"), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_TYPE(cfgOptTypeString), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_RESET(true), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_REQUIRED(false), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_SECTION(cfgSectionGlobal), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_GROUP_MEMBER(true), // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_GROUP_ID(cfgOptGrpRepo), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdExpire) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND_ROLE_ASYNC_VALID_LIST // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND_ROLE_LOCAL_VALID_LIST // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdBackup) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND_ROLE_REMOTE_VALID_LIST // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdAnnotate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdArchivePush) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdCheck) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdInfo) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdManifest) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoCreate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoGet) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoLs) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoPut) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRepoRm) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdRestore) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaCreate) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaDelete) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdStanzaUpgrade) // opt/repo-sftp-identity-agent - PARSE_RULE_OPTION_COMMAND(cfgCmdVerify) // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // opt/repo-sftp-identity-agent - PARSE_RULE_OPTIONAL // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTIONAL_GROUP // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_OPTIONAL_DEPEND // opt/repo-sftp-identity-agent - ( // opt/repo-sftp-identity-agent - PARSE_RULE_VAL_OPT(cfgOptRepoType), // opt/repo-sftp-identity-agent - PARSE_RULE_VAL_STRID(parseRuleValStrIdSftp), // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - ), // opt/repo-sftp-identity-agent - // ----------------------------------------------------------------------------------------------------------------------------- PARSE_RULE_OPTION // opt/repo-sftp-private-key-file ( // opt/repo-sftp-private-key-file PARSE_RULE_OPTION_NAME("repo-sftp-private-key-file"), // opt/repo-sftp-private-key-file diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 52ec1846a5..a57f7df7ea 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1453,8 +1453,12 @@ storageSftpNew( THROW_FMT( ServiceError, "failure connecting to ssh-agent %s[%d]%s", - param.identityAgent == NULL ? "" : zNewFmt("'%s' ", strZ(param.identityAgent)), rc, - zNewFmt(": %s", ssh2ErrMsg)); +#if LIBSSH2_VERSION_NUM >= 0x010900 + param.identityAgent == NULL ? "" : zNewFmt("'%s' ", strZ(param.identityAgent)), +#else + "", +#endif + rc, zNewFmt(": %s", ssh2ErrMsg)); } if ((rc = libssh2_agent_list_identities(this->agent)) != 0) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 045fa7d17c..d4f20990c3 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -647,12 +647,14 @@ testRun(void) {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_LIST_IDENTITIES, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, + {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_EAGAIN}, + {.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_BLOCK_READING}, {.function = HRNLIBSSH2_AGENT_USERAUTH, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_SFTP_INIT}, {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_FREE}, - {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]", .resultInt = 0}, {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, {.function = NULL} }); @@ -717,7 +719,7 @@ testRun(void) {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_FREE}, - {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]", .resultInt = 0}, {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, {.function = NULL} }); @@ -808,7 +810,7 @@ testRun(void) {.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = 0}, {.function = HRNLIBSSH2_AGENT_DISCONNECT, .resultInt = LIBSSH2_ERROR_NONE}, {.function = HRNLIBSSH2_AGENT_FREE}, - {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgbackrest instance shutdown\",\"\"]", .resultInt = 0}, + {.function = HRNLIBSSH2_SESSION_DISCONNECT_EX, .param = "[11,\"pgBackRest instance shutdown\",\"\"]", .resultInt = 0}, {.function = HRNLIBSSH2_SESSION_FREE, .resultInt = 0}, {.function = NULL} }); @@ -869,6 +871,9 @@ testRun(void) {.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, .resultNull = true}, + {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_ALLOC}, + {.function = HRNLIBSSH2_SESSION_LAST_ERROR, .resultInt = LIBSSH2_ERROR_ALLOC, + .errMsg = (char *)"Unable to allocate memory for known-hosts collection"}, {.function = NULL} }); @@ -899,7 +904,7 @@ testRun(void) .hostKeyCheckType = cfgOptionIdxStrId(cfgOptRepoSftpHostKeyCheckType, repoIdx), .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx))), ServiceError, - "failure during libssh2_knownhost_init"); + "failure during libssh2_knownhost_init: libssh2 errno [-6] Unable to allocate memory for known-hosts collection"); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_session_hostkey fail - return NULL - hostKeyCheckType = yes"); @@ -1696,7 +1701,8 @@ testRun(void) "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'"); + "P00 WARN: pgBackRest added new host 'localhost' to '/home/" TEST_USER "/.ssh/known_hosts'\n" + "P00 DETAIL: public key authentication with username vagrant and key /home/vagrant/.ssh/id_rsa succeeded"); harnessLogLevelReset(); From bc5a24c037dfac3bcee452fc6d8dd712ef16c3f5 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 12 Jan 2024 11:45:37 -0500 Subject: [PATCH 18/20] Fix option order --- test/src/module/command/helpTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/module/command/helpTest.c b/test/src/module/command/helpTest.c index e55308bb58..8fff72a88a 100644 --- a/test/src/module/command/helpTest.c +++ b/test/src/module/command/helpTest.c @@ -328,8 +328,8 @@ testRun(void) " --repo-sftp-host-key-hash-type SFTP repository host key hash type\n" " --repo-sftp-host-port SFTP repository host port [default=22]\n" " --repo-sftp-host-user SFTP repository host user\n" - " --repo-sftp-known-host SFTP known hosts file\n" " --repo-sftp-identity-agent SFTP identity agent\n" + " --repo-sftp-known-host SFTP known hosts file\n" " --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" From a70cdb1619072338b0eba81de4e030861b9f74f1 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 12 Jan 2024 12:00:41 -0500 Subject: [PATCH 19/20] Replace vagrant with TEST_USER --- test/src/module/storage/sftpTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index d4f20990c3..b452e7277d 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1702,7 +1702,7 @@ testRun(void) "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'\n" - "P00 DETAIL: public key authentication with username vagrant and key /home/vagrant/.ssh/id_rsa succeeded"); + "P00 DETAIL: public key authentication with username vagrant and key /home/" TEST_USER "/.ssh/id_rsa succeeded"); harnessLogLevelReset(); From 50ec47d20d337eb6493684922889d61120af1742 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Fri, 12 Jan 2024 12:09:04 -0500 Subject: [PATCH 20/20] Replace vagrant with TEST_USER in other location --- test/src/module/storage/sftpTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index b452e7277d..a3e645b87f 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1702,7 +1702,7 @@ testRun(void) "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'\n" - "P00 DETAIL: public key authentication with username vagrant and key /home/" TEST_USER "/.ssh/id_rsa succeeded"); + "P00 DETAIL: public key authentication with username " TEST_USER " and key /home/" TEST_USER "/.ssh/id_rsa succeeded"); harnessLogLevelReset();