aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Lin <jjlin@cs.stanford.edu>2014-09-15 21:16:46 -0700
committerDaniel Stenberg <daniel@haxx.se>2014-10-03 16:20:54 +0200
commitfa7d04fed4d4578fe29bdff0b5465f6e4a7da81a (patch)
treed06402280e95d3c9bb8a47a8a02ef1618e2fb340
parentb1c4c39c5830951b805d9cb136c2e3f0237776b9 (diff)
ssh: improve key file search
For private keys, use the first match from: user-specified key file (if provided), ~/.ssh/id_rsa, ~/.ssh/id_dsa, ./id_rsa, ./id_dsa Note that the previous code only looked for id_dsa files. id_rsa is now generally preferred, as it supports larger key sizes. For public keys, use the user-specified key file, if provided. Otherwise, try to extract the public key from the private key file. This means that passing --pubkey is typically no longer required, and makes the key-handling behavior more like OpenSSH.
-rw-r--r--docs/MANUAL26
-rw-r--r--docs/curl.18
-rw-r--r--lib/ssh.c75
3 files changed, 73 insertions, 36 deletions
diff --git a/docs/MANUAL b/docs/MANUAL
index 06b3abee5..18fecf6c5 100644
--- a/docs/MANUAL
+++ b/docs/MANUAL
@@ -41,12 +41,19 @@ SIMPLE USAGE
Get a file from an SSH server using SFTP:
- curl -u username sftp://shell.example.com/etc/issue
+ curl -u username sftp://example.com/etc/issue
- Get a file from an SSH server using SCP using a private key to authenticate:
+ Get a file from an SSH server using SCP using a private key
+ (not password-protected) to authenticate:
- curl -u username: --key ~/.ssh/id_dsa --pubkey ~/.ssh/id_dsa.pub \
- scp://shell.example.com/~/personal.txt
+ curl -u username: --key ~/.ssh/id_rsa \
+ scp://example.com/~/file.txt
+
+ Get a file from an SSH server using SCP using a private key
+ (password-protected) to authenticate:
+
+ curl -u username: --key ~/.ssh/id_rsa --pass private_key_password \
+ scp://example.com/~/file.txt
Get the main page from an IPv6 web server:
@@ -91,10 +98,13 @@ USING PASSWORDS
SFTP / SCP
- This is similar to FTP, but you can specify a private key to use instead of
- a password. Note that the private key may itself be protected by a password
- that is unrelated to the login password of the remote system. If you
- provide a private key file you must also provide a public key file.
+ This is similar to FTP, but you can use the --key option to specify a
+ private key to use instead of a password. Note that the private key may
+ itself be protected by a password that is unrelated to the login password
+ of the remote system; this password is specified using the --pass option.
+ Typically, curl will automatically extract the public key from the private
+ key file, but in cases where curl does not have the proper library support,
+ a matching public key file must be specified using the --pubkey option.
HTTP
diff --git a/docs/curl.1 b/docs/curl.1
index e52a7e4dd..4d97227af 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -825,7 +825,8 @@ If this option is used several times, the last one will be used. If
unspecified, the option defaults to 60 seconds.
.IP "--key <key>"
(SSL/SSH) Private key file name. Allows you to provide your private key in this
-separate file.
+separate file. For SSH, if not specified, curl tries the following candidates
+in order: '~/.ssh/id_rsa', '~/.ssh/id_dsa', './id_rsa', './id_dsa'.
If this option is used several times, the last one will be used.
.IP "--key-type <type>"
@@ -1283,6 +1284,11 @@ protocol instead of the default HTTP 1.1.
separate file.
If this option is used several times, the last one will be used.
+
+(As of 7.39.0, curl attempts to automatically extract the public key from the
+private key file, so passing this option is generally not required. Note that
+this public key extraction requires libcurl to be linked against a copy of
+libssh2 1.2.8 or higher that is itself linked against OpenSSL.)
.IP "-q"
If used as the first parameter on the command line, the \fIcurlrc\fP config
file will not be read and used. See the \fI-K, --config\fP for details on the
diff --git a/lib/ssh.c b/lib/ssh.c
index 887e10f21..76389a036 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -786,7 +786,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
(strstr(sshc->authlist, "publickey") != NULL)) {
char *home = NULL;
- bool rsa_pub_empty_but_ok = FALSE;
+ bool out_of_memory = FALSE;
sshc->rsa_pub = sshc->rsa = NULL;
@@ -794,34 +794,55 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
HOME environment variable etc? */
home = curl_getenv("HOME");
- if(data->set.str[STRING_SSH_PUBLIC_KEY] &&
- !*data->set.str[STRING_SSH_PUBLIC_KEY])
- rsa_pub_empty_but_ok = true;
- else if(data->set.str[STRING_SSH_PUBLIC_KEY])
- sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
- else if(home)
- sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
- else
- /* as a final resort, try current dir! */
- sshc->rsa_pub = strdup("id_dsa.pub");
-
- if(!rsa_pub_empty_but_ok && (sshc->rsa_pub == NULL)) {
- Curl_safefree(home);
- state(conn, SSH_SESSION_FREE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
+ if(data->set.str[STRING_SSH_PRIVATE_KEY])
+ sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
+ else {
+ /* If no private key file is specified, try some common paths. */
+ if(home) {
+ /* Try ~/.ssh first. */
+ sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
+ if(!sshc->rsa)
+ out_of_memory = TRUE;
+ else if(access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+ if(!sshc->rsa)
+ out_of_memory = TRUE;
+ else if(access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ }
+ }
+ }
+ if(!out_of_memory && !sshc->rsa) {
+ /* Nothing found; try the current dir. */
+ sshc->rsa = strdup("id_rsa");
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ sshc->rsa = strdup("id_dsa");
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ /* Out of guesses. Set to the empty string to avoid
+ * surprising info messages. */
+ sshc->rsa = strdup("");
+ }
+ }
+ }
}
- if(data->set.str[STRING_SSH_PRIVATE_KEY])
- sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
- else if(home)
- sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
- else
- /* as a final resort, try current dir! */
- sshc->rsa = strdup("id_dsa");
+ /*
+ * Unless the user explicitly specifies a public key file, let
+ * libssh2 extract the public key from the private key file.
+ * This is done by simply passing sshc->rsa_pub = NULL.
+ */
+ if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
+ sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
+ if(!sshc->rsa_pub)
+ out_of_memory = TRUE;
+ }
- if(sshc->rsa == NULL) {
+ if(out_of_memory || sshc->rsa == NULL) {
Curl_safefree(home);
+ Curl_safefree(sshc->rsa);
Curl_safefree(sshc->rsa_pub);
state(conn, SSH_SESSION_FREE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
@@ -834,8 +855,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(home);
- infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
- infof(data, "Using ssh private key file %s\n", sshc->rsa);
+ infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
+ infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
state(conn, SSH_AUTH_PKEY);
}