mirror of
https://github.com/curl/curl.git
synced 2026-07-10 04:37:15 +03:00
vssh: keyfile use cleanups
- make the libssh backend do the same fallback for private and public key filename as libssh2 already did and is documented behavior. This now uses a common function. - set the file names already in setup_connection if public key auth is requested, so that the connection reuse functions can use the information when checking for existing connections to reuse - rename the oddly named struct fields 'rsa' to 'priv_key' and 'rsa_pub' to 'pub_key' to better reflect their purposes Fixes #22243 Closes #22244
This commit is contained in:
parent
d3a7e57157
commit
c7f67be010
6 changed files with 112 additions and 107 deletions
|
|
@ -681,8 +681,8 @@ static bool ssh_config_matches(struct connectdata *one,
|
|||
|
||||
sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN);
|
||||
sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN);
|
||||
return sshc1 && sshc2 && Curl_safecmp(sshc1->rsa, sshc2->rsa) &&
|
||||
Curl_safecmp(sshc1->rsa_pub, sshc2->rsa_pub);
|
||||
return sshc1 && sshc2 && Curl_safecmp(sshc1->priv_key, sshc2->priv_key) &&
|
||||
Curl_safecmp(sshc1->pub_key, sshc2->pub_key);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -832,8 +832,7 @@ static int myssh_in_AUTHLIST(struct Curl_easy *data,
|
|||
/* For public key auth we need either the private key or
|
||||
CURLSSH_AUTH_AGENT. */
|
||||
if((sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) &&
|
||||
(data->set.str[STRING_SSH_PRIVATE_KEY] ||
|
||||
(data->set.ssh_auth_types & CURLSSH_AUTH_AGENT))) {
|
||||
(sshc->priv_key || (data->set.ssh_auth_types & CURLSSH_AUTH_AGENT))) {
|
||||
myssh_to(data, sshc, SSH_AUTH_PKEY_INIT);
|
||||
infof(data, "Authentication using SSH public key file");
|
||||
}
|
||||
|
|
@ -863,7 +862,7 @@ static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data,
|
|||
|
||||
/* Two choices, (1) private key was given on CMD,
|
||||
* (2) use the "default" keys. */
|
||||
if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
|
||||
if(sshc->priv_key) {
|
||||
if(sshc->pubkey && !data->set.ssl.primary.key_passwd) {
|
||||
rc = ssh_userauth_try_publickey(sshc->ssh_session, NULL, sshc->pubkey);
|
||||
if(rc == SSH_AUTH_AGAIN)
|
||||
|
|
@ -875,13 +874,11 @@ static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data,
|
|||
}
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_privkey_file(data->
|
||||
set.str[STRING_SSH_PRIVATE_KEY],
|
||||
rc = ssh_pki_import_privkey_file(sshc->priv_key,
|
||||
data->set.ssl.primary.key_passwd, NULL,
|
||||
NULL, &sshc->privkey);
|
||||
if(rc != SSH_OK) {
|
||||
failf(data, "Could not load private key file %s",
|
||||
data->set.str[STRING_SSH_PRIVATE_KEY]);
|
||||
failf(data, "Could not load private key file %s", sshc->priv_key);
|
||||
rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1916,8 +1913,8 @@ static void sshc_cleanup(struct ssh_conn *sshc)
|
|||
sshc->pubkey = NULL;
|
||||
}
|
||||
|
||||
curlx_safefree(sshc->rsa_pub);
|
||||
curlx_safefree(sshc->rsa);
|
||||
curlx_safefree(sshc->pub_key);
|
||||
curlx_safefree(sshc->priv_key);
|
||||
curlx_safefree(sshc->quote_path1);
|
||||
curlx_safefree(sshc->quote_path2);
|
||||
curlx_dyn_free(&sshc->readdir_buf);
|
||||
|
|
@ -2547,7 +2544,7 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data,
|
|||
Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
return Curl_ssh_setup_pkey(data, sshc);
|
||||
}
|
||||
|
||||
static Curl_recv scp_recv, sftp_recv;
|
||||
|
|
@ -2655,9 +2652,8 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
|
|||
sshc->privkey = NULL;
|
||||
sshc->pubkey = NULL;
|
||||
|
||||
if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
|
||||
rc = ssh_pki_import_pubkey_file(data->set.str[STRING_SSH_PUBLIC_KEY],
|
||||
&sshc->pubkey);
|
||||
if(sshc->pub_key) {
|
||||
rc = ssh_pki_import_pubkey_file(sshc->pub_key, &sshc->pubkey);
|
||||
if(rc != SSH_OK) {
|
||||
failf(data, "Could not load public key file");
|
||||
return CURLE_FAILED_INIT;
|
||||
|
|
|
|||
|
|
@ -1094,8 +1094,7 @@ static CURLcode sftp_upload_init(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode ssh_state_pkey_init(struct Curl_easy *data,
|
||||
struct ssh_conn *sshc)
|
||||
static void ssh_state_pkey_init(struct Curl_easy *data, struct ssh_conn *sshc)
|
||||
{
|
||||
/*
|
||||
* Check the supported auth types in the order I feel is most secure
|
||||
|
|
@ -1105,88 +1104,13 @@ static CURLcode ssh_state_pkey_init(struct Curl_easy *data,
|
|||
|
||||
if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
|
||||
strstr(sshc->authlist, "publickey")) {
|
||||
bool out_of_memory = FALSE;
|
||||
|
||||
sshc->rsa_pub = sshc->rsa = NULL;
|
||||
|
||||
if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
|
||||
sshc->rsa = curlx_strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
|
||||
if(!sshc->rsa)
|
||||
out_of_memory = TRUE;
|
||||
}
|
||||
else {
|
||||
/* To ponder about: should really the lib be messing about with the
|
||||
HOME environment variable etc? */
|
||||
char *home = curl_getenv("HOME");
|
||||
curlx_struct_stat sbuf;
|
||||
|
||||
/* If no private key file is specified, try some common paths. */
|
||||
if(home) {
|
||||
/* Try ~/.ssh first. */
|
||||
sshc->rsa = curl_maprintf("%s/.ssh/id_rsa", home);
|
||||
if(!sshc->rsa)
|
||||
out_of_memory = TRUE;
|
||||
else if(curlx_stat(sshc->rsa, &sbuf)) {
|
||||
curlx_free(sshc->rsa);
|
||||
sshc->rsa = curl_maprintf("%s/.ssh/id_dsa", home);
|
||||
if(!sshc->rsa)
|
||||
out_of_memory = TRUE;
|
||||
else if(curlx_stat(sshc->rsa, &sbuf)) {
|
||||
curlx_safefree(sshc->rsa);
|
||||
}
|
||||
}
|
||||
curlx_free(home);
|
||||
}
|
||||
if(!out_of_memory && !sshc->rsa) {
|
||||
/* Nothing found; try the current dir. */
|
||||
sshc->rsa = curlx_strdup("id_rsa");
|
||||
if(sshc->rsa && curlx_stat(sshc->rsa, &sbuf)) {
|
||||
curlx_free(sshc->rsa);
|
||||
sshc->rsa = curlx_strdup("id_dsa");
|
||||
if(sshc->rsa && curlx_stat(sshc->rsa, &sbuf)) {
|
||||
curlx_free(sshc->rsa);
|
||||
/* Out of guesses. Set to the empty string to avoid
|
||||
* surprising info messages. */
|
||||
sshc->rsa = curlx_strdup("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless the user explicitly specifies a public key file, let
|
||||
* libssh2 extract the public key from the private key file.
|
||||
* This is done by passing sshc->rsa_pub = NULL.
|
||||
*/
|
||||
if(!out_of_memory && data->set.str[STRING_SSH_PUBLIC_KEY] &&
|
||||
/* treat empty string the same way as NULL */
|
||||
data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
|
||||
sshc->rsa_pub = curlx_strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
|
||||
if(!sshc->rsa_pub)
|
||||
out_of_memory = TRUE;
|
||||
}
|
||||
|
||||
if(out_of_memory || !sshc->rsa) {
|
||||
curlx_safefree(sshc->rsa);
|
||||
curlx_safefree(sshc->rsa_pub);
|
||||
myssh_to(data, sshc, SSH_SESSION_FREE);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
sshc->passphrase = data->set.ssl.primary.key_passwd;
|
||||
if(!sshc->passphrase)
|
||||
sshc->passphrase = "";
|
||||
|
||||
if(sshc->rsa_pub)
|
||||
infof(data, "SSH: trying public key file '%s'", sshc->rsa_pub);
|
||||
infof(data, "SSH: trying private key file '%s'", sshc->rsa);
|
||||
|
||||
if(sshc->pub_key)
|
||||
infof(data, "SSH: trying public key file '%s'", sshc->pub_key);
|
||||
infof(data, "SSH: trying private key file '%s'", sshc->priv_key);
|
||||
myssh_to(data, sshc, SSH_AUTH_PKEY);
|
||||
}
|
||||
else {
|
||||
else
|
||||
myssh_to(data, sshc, SSH_AUTH_PASS_INIT);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode sftp_quote_stat(struct Curl_easy *data,
|
||||
|
|
@ -1559,14 +1483,11 @@ static CURLcode ssh_state_auth_pkey(struct Curl_easy *data,
|
|||
libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
|
||||
user,
|
||||
curlx_uztoui(strlen(user)),
|
||||
sshc->rsa_pub,
|
||||
sshc->rsa, sshc->passphrase);
|
||||
sshc->pub_key,
|
||||
sshc->priv_key, sshc->passphrase);
|
||||
if(rc == LIBSSH2_ERROR_EAGAIN)
|
||||
return CURLE_AGAIN;
|
||||
|
||||
curlx_safefree(sshc->rsa_pub);
|
||||
curlx_safefree(sshc->rsa);
|
||||
|
||||
if(rc == 0) {
|
||||
sshc->authed = TRUE;
|
||||
infof(data, "SSH: authenticated via publickey");
|
||||
|
|
@ -2626,8 +2547,8 @@ static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
|
|||
DEBUGASSERT(!sshc->kh);
|
||||
DEBUGASSERT(!sshc->ssh_agent);
|
||||
|
||||
curlx_safefree(sshc->rsa_pub);
|
||||
curlx_safefree(sshc->rsa);
|
||||
curlx_safefree(sshc->pub_key);
|
||||
curlx_safefree(sshc->priv_key);
|
||||
curlx_safefree(sshc->quote_path1);
|
||||
curlx_safefree(sshc->quote_path2);
|
||||
curlx_safefree(sshc->homedir);
|
||||
|
|
@ -2968,7 +2889,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data,
|
|||
break;
|
||||
|
||||
case SSH_AUTH_PKEY_INIT:
|
||||
result = ssh_state_pkey_init(data, sshc);
|
||||
ssh_state_pkey_init(data, sshc);
|
||||
break;
|
||||
|
||||
case SSH_AUTH_PKEY:
|
||||
|
|
@ -3343,7 +3264,7 @@ static CURLcode ssh_setup_connection(struct Curl_easy *data,
|
|||
if(Curl_meta_set(data, CURL_META_SSH_EASY, sshp, myssh_easy_dtor))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
return Curl_ssh_setup_pkey(data, sshc);
|
||||
}
|
||||
|
||||
static Curl_recv scp_recv, sftp_recv;
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ struct ssh_conn {
|
|||
|
||||
/* common */
|
||||
const char *passphrase; /* pass-phrase to use */
|
||||
char *rsa_pub; /* strdup'ed public key file */
|
||||
char *rsa; /* strdup'ed private key file */
|
||||
char *pub_key; /* strdup'ed public key file */
|
||||
char *priv_key; /* strdup'ed private key file */
|
||||
sshstate state; /* always use ssh.c:state() to change state! */
|
||||
sshstate nextstate; /* the state to goto after stopping */
|
||||
struct curl_slist *quote_item; /* for the quote option */
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "escape.h"
|
||||
#include "select.h" /* for Curl_pollset_change() */
|
||||
#include "url.h" /* for Curl_conn_meta_get() */
|
||||
#include "curlx/fopen.h"
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
const char *Curl_ssh_statename(sshstate state)
|
||||
|
|
@ -361,4 +362,87 @@ CURLcode Curl_ssh_pollset(struct Curl_easy *data, struct easy_pollset *ps)
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_ssh_setup_pkey(struct Curl_easy *data, struct ssh_conn *sshc)
|
||||
{
|
||||
char *home = NULL;
|
||||
if(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) {
|
||||
sshc->pub_key = sshc->priv_key = NULL;
|
||||
|
||||
if(data->set.str[STRING_SSH_PRIVATE_KEY]) {
|
||||
sshc->priv_key = curlx_strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
|
||||
if(!sshc->priv_key)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
/* To ponder about: should really the lib be messing about with the HOME
|
||||
environment variable etc? */
|
||||
curlx_struct_stat sbuf;
|
||||
home = curl_getenv("HOME");
|
||||
|
||||
/* If no private key file is specified, try some common paths. */
|
||||
if(home) {
|
||||
/* Try ~/.ssh first. */
|
||||
sshc->priv_key = curl_maprintf("%s/.ssh/id_rsa", home);
|
||||
if(!sshc->priv_key)
|
||||
goto fail;
|
||||
else if(curlx_stat(sshc->priv_key, &sbuf)) {
|
||||
curlx_free(sshc->priv_key);
|
||||
sshc->priv_key = curl_maprintf("%s/.ssh/id_dsa", home);
|
||||
if(!sshc->priv_key)
|
||||
goto fail;
|
||||
else if(curlx_stat(sshc->priv_key, &sbuf)) {
|
||||
curlx_safefree(sshc->priv_key);
|
||||
}
|
||||
}
|
||||
curlx_safefree(home);
|
||||
}
|
||||
if(!sshc->priv_key) {
|
||||
/* Nothing found; try the current dir. */
|
||||
sshc->priv_key = curlx_strdup("id_rsa");
|
||||
if(sshc->priv_key && curlx_stat(sshc->priv_key, &sbuf)) {
|
||||
curlx_free(sshc->priv_key);
|
||||
sshc->priv_key = curlx_strdup("id_dsa");
|
||||
if(sshc->priv_key && curlx_stat(sshc->priv_key, &sbuf)) {
|
||||
curlx_free(sshc->priv_key);
|
||||
/* Out of guesses. Set to the empty string to avoid
|
||||
* surprising info messages. */
|
||||
sshc->priv_key = curlx_strdup("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless the user explicitly specifies a public key file, let the SSH
|
||||
* library extract the public key from the private key file. This is done
|
||||
* by passing sshc->pub_key = NULL.
|
||||
*/
|
||||
if(data->set.str[STRING_SSH_PUBLIC_KEY] &&
|
||||
/* treat empty string the same way as NULL */
|
||||
data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
|
||||
sshc->pub_key = curlx_strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
|
||||
if(!sshc->pub_key)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sshc->passphrase = data->set.ssl.primary.key_passwd;
|
||||
if(!sshc->passphrase)
|
||||
sshc->passphrase = "";
|
||||
|
||||
if(sshc->pub_key)
|
||||
infof(data, "SSH: public key file '%s'", sshc->pub_key);
|
||||
if(sshc->priv_key)
|
||||
infof(data, "SSH: private key file '%s'", sshc->priv_key);
|
||||
else
|
||||
infof(data, "SSH: public key auth without private key set!");
|
||||
}
|
||||
return CURLE_OK;
|
||||
|
||||
fail:
|
||||
curlx_safefree(home);
|
||||
curlx_safefree(sshc->priv_key);
|
||||
curlx_safefree(sshc->pub_key);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#endif /* USE_SSH */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "urldata.h"
|
||||
|
||||
struct ssh_conn;
|
||||
|
||||
CURLcode Curl_getworkingpath(struct Curl_easy *data,
|
||||
const char *homedir,
|
||||
char **path);
|
||||
|
|
@ -40,5 +42,7 @@ CURLcode Curl_ssh_range(struct Curl_easy *data,
|
|||
curl_off_t *startp, curl_off_t *sizep);
|
||||
|
||||
CURLcode Curl_ssh_pollset(struct Curl_easy *data, struct easy_pollset *ps);
|
||||
CURLcode Curl_ssh_setup_pkey(struct Curl_easy *data, struct ssh_conn *sshc);
|
||||
|
||||
#endif /* USE_SSH */
|
||||
#endif /* HEADER_CURL_VSSH_VSSH_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue