mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-04-17 11:46:39 +02:00
Accept leading tilde in paths for SFTP public/private keys.
The documentation indicates that leading tilde file paths for public/private keys are valid but the functionality was omitted from the original implementation.
This commit is contained in:
parent
1141dc2070
commit
eb32d6de5e
@ -28,6 +28,17 @@
|
|||||||
<p>Multi-stanza check command.</p>
|
<p>Multi-stanza check command.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
|
||||||
|
<release-item>
|
||||||
|
<github-pull-request id="2136"/>
|
||||||
|
|
||||||
|
<release-item-contributor-list>
|
||||||
|
<release-item-contributor id="reid.thompson"/>
|
||||||
|
<release-item-reviewer id="david.steele"/>
|
||||||
|
</release-item-contributor-list>
|
||||||
|
|
||||||
|
<p>Accept leading tilde in paths for SFTP public/private keys.</p>
|
||||||
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<github-pull-request id="2072"/>
|
<github-pull-request id="2072"/>
|
||||||
|
|
||||||
|
@ -24,6 +24,9 @@ static struct
|
|||||||
|
|
||||||
gid_t groupId; // Real group id of the calling process from getgid()
|
gid_t groupId; // Real group id of the calling process from getgid()
|
||||||
const String *groupName; // Group name if it exists
|
const String *groupName; // Group name if it exists
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
const String *userHome; // User home directory
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
} userLocalData;
|
} userLocalData;
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
@ -40,6 +43,9 @@ userInitInternal(void)
|
|||||||
|
|
||||||
userLocalData.userId = getuid();
|
userLocalData.userId = getuid();
|
||||||
userLocalData.userName = userNameFromId(userLocalData.userId);
|
userLocalData.userName = userNameFromId(userLocalData.userId);
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
userLocalData.userHome = userHomeFromId(userLocalData.userId);
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
userLocalData.userRoot = userLocalData.userId == 0;
|
userLocalData.userRoot = userLocalData.userId == 0;
|
||||||
|
|
||||||
userLocalData.groupId = getgid();
|
userLocalData.groupId = getgid();
|
||||||
@ -114,6 +120,35 @@ groupNameFromId(gid_t groupId)
|
|||||||
FUNCTION_TEST_RETURN(STRING, NULL);
|
FUNCTION_TEST_RETURN(STRING, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************************************************************************************/
|
||||||
|
// Currently userHome() and userHomeFromId() are only used when building with libssh2
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
|
||||||
|
FN_EXTERN const String *
|
||||||
|
userHome(void)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_VOID();
|
||||||
|
FUNCTION_TEST_RETURN_CONST(STRING, userLocalData.userHome);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************************************************************************/
|
||||||
|
FN_EXTERN String *
|
||||||
|
userHomeFromId(uid_t userId)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM(UINT, userId);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
struct passwd *userData = getpwuid(userId);
|
||||||
|
|
||||||
|
if (userData != NULL)
|
||||||
|
FUNCTION_TEST_RETURN(STRING, strNewZ(userData->pw_dir));
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(STRING, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
FN_EXTERN uid_t
|
FN_EXTERN uid_t
|
||||||
userId(void)
|
userId(void)
|
||||||
|
@ -26,6 +26,16 @@ FN_EXTERN const String *groupName(void);
|
|||||||
// Get the group name from a group id. Returns NULL if the group id is invalid or there is no mapping.
|
// Get the group name from a group id. Returns NULL if the group id is invalid or there is no mapping.
|
||||||
FN_EXTERN String *groupNameFromId(gid_t groupId);
|
FN_EXTERN String *groupNameFromId(gid_t groupId);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
|
||||||
|
// Get the home directory of the current user. Returns NULL if there is no mapping.
|
||||||
|
FN_EXTERN const String *userHome(void);
|
||||||
|
|
||||||
|
// Get the user home directory from a user id. Returns NULL if the user id is invalid or there is no mapping.
|
||||||
|
FN_EXTERN String *userHomeFromId(uid_t userId);
|
||||||
|
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
// Get the id of the current user
|
// Get the id of the current user
|
||||||
FN_EXTERN uid_t userId(void);
|
FN_EXTERN uid_t userId(void);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ SFTP Storage
|
|||||||
#include "common/io/fd.h"
|
#include "common/io/fd.h"
|
||||||
#include "common/io/socket/client.h"
|
#include "common/io/socket/client.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
#include "common/regExp.h"
|
||||||
#include "common/user.h"
|
#include "common/user.h"
|
||||||
#include "storage/sftp/read.h"
|
#include "storage/sftp/read.h"
|
||||||
#include "storage/sftp/storage.intern.h"
|
#include "storage/sftp/storage.intern.h"
|
||||||
@ -306,6 +307,26 @@ storageSftpInfo(THIS_VOID, const String *const file, const StorageInfoLevel leve
|
|||||||
FUNCTION_LOG_RETURN(STORAGE_INFO, result);
|
FUNCTION_LOG_RETURN(STORAGE_INFO, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************************************************************************************/
|
||||||
|
static String *
|
||||||
|
storageSftpExpandTildePath(const String *const tildePath)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM(STRING, tildePath);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
String *const result = strNew();
|
||||||
|
|
||||||
|
// Append to user home directory path substring after the tilde
|
||||||
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
strCatFmt(result, "%s%s", strZ(userHome()), strZ(strSub(tildePath, (size_t)strChr(tildePath, '~') + 1)));
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(STRING, result);
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************/
|
/**********************************************************************************************************************************/
|
||||||
// Helper function to get info for a file if it exists. This logic can't live directly in storageSftpList() because there is a race
|
// 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
|
// condition where a file might exist while listing the directory but it is gone before stat() can be called. In order to get
|
||||||
@ -877,13 +898,22 @@ storageSftpNew(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform public key authorization, expand leading tilde key file paths if needed
|
||||||
|
String *const privKeyPath = regExpMatchOne(STRDEF("^ *~"), keyPriv) ? storageSftpExpandTildePath(keyPriv) : strDup(keyPriv);
|
||||||
|
String *const pubKeyPath =
|
||||||
|
param.keyPub != NULL && regExpMatchOne(STRDEF("^ *~"), param.keyPub) ?
|
||||||
|
storageSftpExpandTildePath(param.keyPub) : strDup(param.keyPub);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
rc = libssh2_userauth_publickey_fromfile(
|
rc = libssh2_userauth_publickey_fromfile(
|
||||||
this->session, strZ(user), strZNull(param.keyPub), strZ(keyPriv), strZNull(param.keyPassphrase));
|
this->session, strZ(user), strZNull(pubKeyPath), strZ(privKeyPath), strZNull(param.keyPassphrase));
|
||||||
}
|
}
|
||||||
while (storageSftpWaitFd(this, rc));
|
while (storageSftpWaitFd(this, rc));
|
||||||
|
|
||||||
|
strFree(privKeyPath);
|
||||||
|
strFree(pubKeyPath);
|
||||||
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
if (rc == LIBSSH2_ERROR_EAGAIN)
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
||||||
|
@ -30,6 +30,10 @@ testRun(void)
|
|||||||
TEST_RESULT_UINT(groupIdFromName(STRDEF("bogus")), (uid_t)-1, "get bogus group id");
|
TEST_RESULT_UINT(groupIdFromName(STRDEF("bogus")), (uid_t)-1, "get bogus group id");
|
||||||
TEST_RESULT_STR(groupName(), TEST_GROUP_STR, "check name name");
|
TEST_RESULT_STR(groupName(), TEST_GROUP_STR, "check name name");
|
||||||
TEST_RESULT_STR_Z(groupNameFromId(77777), NULL, "invalid group name by id");
|
TEST_RESULT_STR_Z(groupNameFromId(77777), NULL, "invalid group name by id");
|
||||||
|
|
||||||
|
TEST_RESULT_STR(userHome(), STRDEF("/home/" TEST_USER), "check user name");
|
||||||
|
TEST_RESULT_STR_Z(userHomeFromId(userId()), "/home/" TEST_USER, "user home by id");
|
||||||
|
TEST_RESULT_STR_Z(userHomeFromId(77777), NULL, "invalid user home by id");
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_HARNESS_RETURN_VOID();
|
FUNCTION_HARNESS_RETURN_VOID();
|
||||||
|
@ -192,7 +192,7 @@ testRun(void)
|
|||||||
ServiceError, "requested ssh2 hostkey hash type (aes-256-cbc) not available");
|
ServiceError, "requested ssh2 hostkey hash type (aes-256-cbc) not available");
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
TEST_TITLE("public key from file auth failure");
|
TEST_TITLE("public key from file auth failure leading - tilde key paths");
|
||||||
|
|
||||||
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
|
hrnLibSsh2ScriptSet((HrnLibSsh2 [])
|
||||||
{
|
{
|
||||||
@ -212,7 +212,8 @@ testRun(void)
|
|||||||
|
|
||||||
TEST_ERROR(
|
TEST_ERROR(
|
||||||
storageSftpNewP(
|
storageSftpNewP(
|
||||||
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, KEYPRIV, hashTypeSha1, .keyPub = KEYPUB,
|
TEST_PATH_STR, STRDEF("localhost"), 22, TEST_USER_STR, 1000, STRDEF("~/.ssh/id_rsa"), hashTypeSha1,
|
||||||
|
.keyPub = STRDEF("~/.ssh/id_rsa.pub"),
|
||||||
.hostFingerprint = STRDEF("3132333435363738393039383736353433323130")),
|
.hostFingerprint = STRDEF("3132333435363738393039383736353433323130")),
|
||||||
ServiceError,
|
ServiceError,
|
||||||
"public key authentication failed: libssh2 error [-16]\n"
|
"public key authentication failed: libssh2 error [-16]\n"
|
||||||
@ -4577,8 +4578,8 @@ testRun(void)
|
|||||||
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
|
hrnCfgArgRawZ(argList, cfgOptRepoType, "sftp");
|
||||||
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
|
hrnCfgArgRawZ(argList, cfgOptRepoSftpHost, "localhost");
|
||||||
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
|
hrnCfgArgRawZ(argList, cfgOptRepoSftpHostKeyHashType, "sha1");
|
||||||
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, KEYPRIV_CSTR);
|
hrnCfgArgRawZ(argList, cfgOptRepoSftpPrivateKeyFile, " ~/.ssh/id_rsa");
|
||||||
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, KEYPUB_CSTR);
|
hrnCfgArgRawZ(argList, cfgOptRepoSftpPublicKeyFile, " ~/.ssh/id_rsa.pub");
|
||||||
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
|
HRN_CFG_LOAD(cfgCmdArchiveGet, argList);
|
||||||
|
|
||||||
const Storage *storage = NULL;
|
const Storage *storage = NULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user