From 4ddb1b18805909bc7052a7a73578ac27b2065dd8 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 13 Sep 2023 00:16:38 -0400 Subject: [PATCH 1/9] Initial functional implementation of ssh-agent authorization --- test/src/module/storage/sftpTest.c | 299 +++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index a3e645b87f..95cf688473 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -295,6 +295,305 @@ testRun(void) // ------------------------------------------------------------------------------------------------------------------------- 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT, .resultNull = true}, + {.function = NULL} + }); + + TEST_ERROR( + storageSftpNewP( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "failure initializing ssh-agent support"); + + // ------------------------------------------------------------------------------------------------------------------------- + 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_HOSTKEY_HASH, .param = "[2]", .resultZ = "12345678909876543210"}, + {.function = HRNLIBSSH2_AGENT_INIT}, + {.function = HRNLIBSSH2_AGENT_CONNECT, .resultInt = -1}, + {.function = NULL} + }); + + TEST_ERROR( + storageSftpNewP( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "failure connecting to ssh-agent [-1]"); + + // ------------------------------------------------------------------------------------------------------------------------- + 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_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( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "failure requesting identities to ssh-agent [-1]"); + + // ------------------------------------------------------------------------------------------------------------------------- + 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_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( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "failure obtaining identity from ssh-agent [-1]"); + + // ------------------------------------------------------------------------------------------------------------------------- + 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_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( + TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, NULL, hashTypeSha1), + ServiceError, + "ssh-agent authentication failure [1]"); + + // ------------------------------------------------------------------------------------------------------------------------- + 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_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; + + 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( + 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"); +#endif + // ------------------------------------------------------------------------------------------------------------------------- + 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_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} + }); + + 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( + 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"); + hrnLibSsh2ScriptSet((HrnLibSsh2 []) { {.function = HRNLIBSSH2_INIT, .param = "[0]", .resultInt = LIBSSH2_ERROR_NONE}, From 94f458611aae9254fe0334e43215b7214aea1235 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 18 Sep 2023 10:32:40 -0400 Subject: [PATCH 2/9] Account for older libssh2 versions inability to set identity agent path More informative error messages Update harnessLibSsh2 and tests --- src/storage/sftp/storage.c | 1 - test/src/common/harnessLibSsh2.h | 3 ++ test/src/module/storage/sftpTest.c | 48 ++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index a57f7df7ea..aeda0ff286 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1424,7 +1424,6 @@ 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 16689c7bce..d541463a8b 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -134,8 +134,11 @@ typedef struct HrnLibSsh2 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 +<<<<<<< HEAD size_t len; // libssh2_session_hostkey len int type; // libssh2_session_hostkey type +======= +>>>>>>> 90d29d502 (Account for older libssh2 versions inability to set identity agent path) char *errMsg; // libssh2_session_last_error error msg } HrnLibSsh2; diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 95cf688473..972f684552 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -302,6 +302,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} }); @@ -309,7 +311,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"); @@ -321,7 +323,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} }); @@ -329,7 +336,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 9b8f665b8869a63005068d9ed525a0aa7925f4e3 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 00:24:13 -0400 Subject: [PATCH 3/9] 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/storage/sftp/storage.c | 34 +++++ test/src/common/harnessLibSsh2.h | 3 - test/src/module/storage/sftpTest.c | 209 +++++++++++++++++++++++------ 3 files changed, 203 insertions(+), 43 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index aeda0ff286..1523dda037 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -638,6 +638,40 @@ storageSftpIdentityFilesList(const StringList *const privKeys) FUNCTION_LOG_RETURN(STRING_LIST, 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 diff --git a/test/src/common/harnessLibSsh2.h b/test/src/common/harnessLibSsh2.h index d541463a8b..16689c7bce 100644 --- a/test/src/common/harnessLibSsh2.h +++ b/test/src/common/harnessLibSsh2.h @@ -134,11 +134,8 @@ typedef struct HrnLibSsh2 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 -<<<<<<< HEAD size_t len; // libssh2_session_hostkey len int type; // libssh2_session_hostkey type -======= ->>>>>>> 90d29d502 (Account for older libssh2 versions inability to set identity agent path) char *errMsg; // libssh2_session_last_error error msg } HrnLibSsh2; diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 972f684552..32d32f10d5 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -309,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"); @@ -326,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"); @@ -353,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 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); #endif - // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("libssh2_agent_list_identities failure"); @@ -388,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]"); @@ -412,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]"); @@ -429,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"); @@ -464,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))), @@ -499,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))); @@ -507,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 []) { @@ -534,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))); @@ -552,8 +688,17 @@ 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 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); #endif @@ -1202,7 +1347,6 @@ testRun(void) 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"); @@ -1493,6 +1637,7 @@ testRun(void) {.function = NULL} }); + // Load configuration argList = strLstNew(); hrnCfgArgRawZ(argList, cfgOptStanza, "test"); hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/pg"); @@ -1541,25 +1686,9 @@ testRun(void) // storageSftpWaitFd returns false {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, - {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_ERROR_NONE}, {.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 f4e637764e21080cf6137b04fe574c7e8625189c Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Mon, 25 Sep 2023 21:37:29 -0400 Subject: [PATCH 4/9] Refactor code Attempt to authenticate via default identity files if no private key file is provided Update tests --- src/storage/sftp/storage.c | 72 +++++++----------- test/src/common/harnessLibSsh2.h | 10 +++ test/src/module/storage/sftpTest.c | 117 +++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 45 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 1523dda037..1973ff894f 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -607,7 +607,8 @@ storageSftpKnownHostsFilesList(const StringList *const knownHosts) } /*********************************************************************************************************************************** -Build private key file list. privKeys requires full path and/or leading tilde path entries. +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 * storageSftpIdentityFilesList(const StringList *const privKeys) @@ -620,51 +621,32 @@ storageSftpIdentityFilesList(const StringList *const privKeys) MEM_CONTEXT_TEMP_BEGIN() { - // Process the privKey file list entries and add them to the result list - for (unsigned int listIdx = 0; listIdx < strLstSize(privKeys); listIdx++) + if (strLstEmpty(privKeys)) { - // 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); + // 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"); } - } - MEM_CONTEXT_TEMP_END(); - - FUNCTION_LOG_RETURN(STRING_LIST, 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++) + else { - // Get the trimmed file path and add it to the result list - const String *const filePath = strTrim(strLstGet(pathList, listIdx)); - - if (strBeginsWithZ(filePath, "~/")) + // 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(); @@ -1415,9 +1397,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)); @@ -1442,7 +1424,7 @@ storageSftpNew( } } - // Free private key list and public key path + // Free the private key list, and the public key path strLstFree(privateKeys); strFree(pubKeyPath); 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 32d32f10d5..4db6edbbc8 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}, @@ -1284,6 +1350,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}, @@ -1327,6 +1411,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} }); @@ -1689,6 +1791,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 a4263022ec5caf3f2b3cf1cb67de7b2d0a745297 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Tue, 26 Sep 2023 15:40:44 -0400 Subject: [PATCH 5/9] Remove spurious empty lines, add missing space before ',' Fix formatting --- src/storage/sftp/storage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 1973ff894f..b221caab87 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -1397,9 +1397,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 14ac55f94eb6ff57783b4752ff79944e96d4489d Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 27 Sep 2023 09:53:21 -0400 Subject: [PATCH 6/9] Attempt auth with default identity files when no private key is provided --- src/build/help/help.xml | 2 +- src/storage/sftp/storage.c | 97 ++++++++++++++++-------------- test/src/module/storage/sftpTest.c | 17 ++++-- 3 files changed, 64 insertions(+), 52 deletions(-) diff --git a/src/build/help/help.xml b/src/build/help/help.xml index 03db73cb0b..a22c90f007 100644 --- a/src/build/help/help.xml +++ b/src/build/help/help.xml @@ -1149,7 +1149,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.

diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index b221caab87..7480d3b6c5 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -623,31 +623,41 @@ 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")); + + 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); } - } + g } MEM_CONTEXT_TEMP_END(); @@ -1375,53 +1385,50 @@ storageSftpNew( libssh2_knownhost_free(knownHostsList); } - // Attempt to authenticate with any provided private keys - // 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); + // Build/normalize private keys list + StringList *const privateKeys = storageSftpIdentityFilesList(privKeys); + + // Attempt to authenticate with any provided private keys bool authSuccess = false; - if (!strLstEmpty(privateKeys)) + // Attempt to authenticate with each private key + for (unsigned int listIdx = 0; listIdx < strLstSize(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); + 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; + + 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 diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 4db6edbbc8..22d2910681 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1328,6 +1328,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"); @@ -1362,9 +1368,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}, @@ -1423,9 +1426,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}, @@ -1449,6 +1449,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 199eb12534082591c22d84effa1b88175ebd0cff Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 27 Sep 2023 10:34:27 -0400 Subject: [PATCH 7/9] Minor comment and formatting cleanup --- src/storage/sftp/storage.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 7480d3b6c5..73dc9cb7ce 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -624,8 +624,7 @@ storageSftpIdentityFilesList(const StringList *const privKeys) if (strLstEmpty(privKeys)) { // Create default file list, do not include non-existent files, reduces log noise - const Storage *const sshStorage = - storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh")); + const Storage *const sshStorage = storagePosixNewP(strNewFmt("%s%s", strZ(userHome()), "/.ssh")); StringList *const sshDefaultIdentityFiles = strLstNew(); strLstAddFmt(sshDefaultIdentityFiles, "%s%s", strZ(userHome()), "/.ssh/id_dsa"); @@ -1393,10 +1392,9 @@ storageSftpNew( // Build/normalize private keys list StringList *const privateKeys = storageSftpIdentityFilesList(privKeys); - // Attempt to authenticate with any provided private keys + // Attempt to authenticate with private keys bool authSuccess = false; - // Attempt to authenticate with each private key for (unsigned int listIdx = 0; listIdx < strLstSize(privateKeys); listIdx++) { const String *const privateKey = strLstGet(privateKeys, listIdx); @@ -1447,6 +1445,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); } From b4768cfddb7047591b6e6fa018184a3dc090a266 Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Wed, 27 Sep 2023 13:01:07 -0400 Subject: [PATCH 8/9] arm64 ci failed with no id_rsa* --- test/src/module/storage/sftpTest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 22d2910681..93da7542c1 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -1333,6 +1333,7 @@ testRun(void) 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); + HRN_STORAGE_PUT_EMPTY(storageSsh, KEYPRIV_CSTR); // Load configuration argList = strLstNew(); @@ -1453,6 +1454,7 @@ testRun(void) HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_CSTR); HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ECDSA_SK_CSTR); HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_ED25519_CSTR); + HRN_STORAGE_REMOVE(storageSsh, KEYPRIV_CSTR); // ------------------------------------------------------------------------------------------------------------------------- TEST_TITLE("known host init failure"); From 6c1ff1e6fbb0ed17d766ce7a2d7c271380393d9e Mon Sep 17 00:00:00 2001 From: Reid Thompson Date: Sat, 13 Jan 2024 09:34:57 -0500 Subject: [PATCH 9/9] Cleanup rebase --- src/storage/sftp/storage.c | 2 +- test/src/module/storage/sftpTest.c | 504 +---------------------------- 2 files changed, 2 insertions(+), 504 deletions(-) diff --git a/src/storage/sftp/storage.c b/src/storage/sftp/storage.c index 73dc9cb7ce..1c3028af71 100644 --- a/src/storage/sftp/storage.c +++ b/src/storage/sftp/storage.c @@ -656,7 +656,7 @@ storageSftpIdentityFilesList(const StringList *const privKeys) else strLstAdd(result, filePath); } - g + } } MEM_CONTEXT_TEMP_END(); diff --git a/test/src/module/storage/sftpTest.c b/test/src/module/storage/sftpTest.c index 93da7542c1..b93ed27833 100644 --- a/test/src/module/storage/sftpTest.c +++ b/test/src/module/storage/sftpTest.c @@ -341,509 +341,6 @@ testRun(void) ServiceError, "failure initializing ssh-agent support [-6]: Unable to allocate space for agent connection"); - // ------------------------------------------------------------------------------------------------------------------------- - 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_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", - .resultInt = LIBSSH2_ERROR_BAD_USE}, - {.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)), - .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), - ServiceError, - "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_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}, - {.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}, -#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, 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); -#if LIBSSH2_VERSION_NUM >= 0x010900 - 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), - .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( - 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 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); -#endif - // ------------------------------------------------------------------------------------------------------------------------- - 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_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}, - {.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"); - hrnCfgArgRawZ(argList, cfgOptRepoSftpUseSshAgent, "y"); - 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), - .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), - .knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), - .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), - ServiceError, - "failure requesting identities to ssh-agent [-1]"); - - // ------------------------------------------------------------------------------------------------------------------------- - 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_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}, - {.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), 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]"); - - // ------------------------------------------------------------------------------------------------------------------------- - 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_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}, - {.function = HRNLIBSSH2_AGENT_GET_IDENTITY, .resultInt = LIBSSH2_ERROR_NONE}, - {.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( - 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 authentication failed, reached end of public keys: libssh2 error [1]"); - - // ------------------------------------------------------------------------------------------------------------------------- - 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_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}, - {.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} - }); - - // 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( - storageTest, - 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)), - .identityAgent = cfgOptionIdxStrNull(cfgOptRepoSftpIdentityAgent, repoIdx), - .useSshAgent = cfgOptionIdxBool(cfgOptRepoSftpUseSshAgent, repoIdx)), - "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_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}, - {.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( - 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))); - - // ------------------------------------------------------------------------------------------------------------------------- - 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, 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); - -#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_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}, - {.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( - 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))); -#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), 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 1.8.0 does not support ssh-agent identity path, requires version 1.9 or greater"); -#endif - // ------------------------------------------------------------------------------------------------------------------------- - 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_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} - }); - - 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( - 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"); @@ -1795,6 +1292,7 @@ testRun(void) // storageSftpWaitFd returns false {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, {.function = HRNLIBSSH2_SESSION_LAST_ERRNO, .resultInt = LIBSSH2_ERROR_SOCKET_SEND}, + {.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_ERROR_NONE}, {.function = NULL} });